【问题标题】:Is there a way to speed up a for loop?有没有办法加快 for 循环?
【发布时间】:2020-01-29 03:54:56
【问题描述】:

我正在使用 for 循环。 for 循环的目标是简单地测试一个条件并对数据进行适当的编码。该循环必须迭代超过 503,288 个唯一值并包括三个 if 语句。有没有办法加快 for 循环?

代码如下:

count<- 0
for(i in unique(Data$ID)){ #503288

  #Subset Relevant Data
  Loop_Before<- subset(Primary_Before, ID == i); Loop_After <- subset(Primary_After, ID == i)

  if(nrow(Loop_Before) >= 1 & nrow(Loop_After) >= 1){
    Data$Status[Data$ID == i] <- "Both Elections"

  }

  if(nrow(Loop_Before) >= 1 & nrow(Loop_After) == 0){
    Data$Status[Data$ID == i] <- "Only Primary Election"

  }

  if(nrow(Loop_Before) >= 0 & nrow(Loop_After) == 1){
    Data$Status[Data$ID == i] <- "Only General Election"

  }

  message(count<- count +1)

}



table(Data$Status)

感谢您的帮助!

【问题讨论】:

  • 不知道Primary_BeforePrimary_After 是如何形成的,或者它们与Data 的关系如何。几乎肯定有一种方法可以做到这一点,它不涉及循环的每个步骤的多个过滤器和全帧复制。完整的副本。每一步。如果您想要一个有意义的答案,我建议您通过提供Data(以及其他,视情况而定)的代表性样本来使这个问题可重现,最好使用data.frame(...)dput(head(Data,10)) 之类的东西(具有不同的数据)。

标签: r performance for-loop parallel-processing


【解决方案1】:

完全避免for-循环。我不知道你的数据集,但以下应该快 10 甚至 100 倍:

library(tidyverse) # load some packages that will help

# let's create some sample data
Data <- data.frame(ID = c(1,1,1,1,2,2,2,3,3))
Primary_before <- data.frame(ID = c(0,1,2,2,3,3,3))
Primary_after <- data.frame(ID = c(1,3))

# now for every ID we count the nr of rows in both dataframes
summarised_before <- Primary_before %>%
    group_by(ID) %>%
    summarise(nrRows = n())

     ID nrRows
  <dbl>  <int>
1     0      1
2     1      1
3     2      2
4     3      3

summarised_after <- Primary_after %>%
    group_by(ID) %>%
    summarise(nrRows = n())

     ID nrRows
  <dbl>  <int>
1     1      1
2     3      1

# now we join them together
summarised_both <- summarised_after %>%
    full_join(summarised_before, by = "ID", suffix = c("_after", "_before"))

# and now we do the final calculation
summarised_both %>%
    mutate(nrRows_after = replace_na(nrRows_after, 0)) %>%
    mutate(Status = case_when(nrRows_before >= 1 & nrRows_after >= 1    ~ "Both elections"
                              , nrRows_before >= 1 & nrRows_after == 0  ~ "Only primary election"
                              , nrRows_before >= 0 & nrRows_after == 1  ~ "Only general election")) %>%
    filter(ID %in% Data$ID)

我保存了中间结果,但你也可以一次性完成,像这样:

Primary_before %>%
    group_by(ID) %>%
    summarise(nrRows = n()) %>%
    full_join(Primary_after %>%
                  group_by(ID) %>%
                  summarise(nrRows = n())
              , by = "ID"
              , suffix = c("_after", "_before")) %>%
    mutate(nrRows_after = replace_na(nrRows_after, 0)) %>%
    mutate(Status = case_when(nrRows_before >= 1 & nrRows_after >= 1    ~ "Both elections"
                              , nrRows_before >= 1 & nrRows_after == 0  ~ "Only primary election"
                              , nrRows_before >= 0 & nrRows_after == 1  ~ "Only general election")) %>%
    filter(ID %in% Data$ID)

【讨论】:

  • 啊,我理解直觉。这更有意义,并且肯定是一种更有效的方法!非常感谢您的有用帖子。
  • 乐于助人。 :)
猜你喜欢
  • 2020-09-14
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多