R替代循环超过1000万个数据

时间:2017-09-07 08:08:16

标签: r

需要一些优化代码的解决方案来运行循环而不使用索引

  abc <- data.frame(A = c(1,2,3,4,5) , 
                    B = c("A","B","C","D","E") , 
                    C = c("A1" ,"B1" , "A1" , "C1" , "A1") )

让我们说,我想添加一个新的列说D.当且仅当C ==&#34; A1&#34;和A&gt; 2然后D将是1。         所以我的输出需要是:

  A B C  D  
1 1 A A1 NA
2 2 B B1 NA
3 3 C A1 1
4 4 D C1 NA 
5 5 E A1 1

可以这样做:

     for (i in 1:nrow(abc){
         if(abc$C[i] == "A1" & abc$A[i] > 2 )
          {
              abc$D[i] == 1
           }
          } 

但我希望代码不使用索引来加快处理速度

当我尝试的时候:

     if(abc$C == "A1" & abc$A > 2 )
        {
            abc$D == 1
        } 

此代码给出错误(仅检查第一行)

然后我尝试了deplyr(mutate)。它工作

     abc <- abc %>% mutate( D = ifelse(C == "A1" & A > 2 , 1,NA))

但问题是当我使用函数执行此操作时。假设我有一个功能

     test <- function(abc ,abc$A , abc$C){

            abc <- abc %>% mutate( D = 1)

                return(abc)
        }

现在我想在调用它之前使用此函数创建D 在这里输入代码#function我必须检查C和A的条件

所以我尝试了解决方案: 这不起作用。

abc <- abc %>% mutate( if(C == "A1" & A > 2) ) %>% test(abc ,abc$A , abc$C)

我需要解决方案来解决这种类型的场景不像这样

for (i in 1:nrow(abc){
if(abc$C[i] == "A1" & abc$A[i] > 2 )
{
  abc <- test(abc ,abc$A , abc$C)
} 
}

需要更好的建议。请执行代码并告诉我更好的方法。 我有2000万数据。所以索引会 花很多时间(我想)

4 个答案:

答案 0 :(得分:4)

您应该使用data.table框架来加快速度:

require(data.table)
setDT(abc)
abc[C == "A1" & A > 2, D := 1]

答案 1 :(得分:2)

提出的3个解决方案中最快的是data.table和索引向量(docendo discimus)然后是dplyr

f <- function(DF){
    DF %>% mutate(D = ifelse(C == "A1" & A > 2 , 1,NA))
}

g <- function(DF){
    setDT(DF)
    DF[C == "A1" & A > 2, D := 1]
}

h <- function(DF){
    idx <- DF[["C"]] == "A1" & DF[["A"]] > 2
    DF[["D"]][idx] <- 1
    DF
}

set.seed(3472)
n <- 20e6
abcd <- data.frame(
    A = sample(5, n, TRUE),
    B = sample(c("A","B","C","D","E"), n, TRUE),
    C = sample(c("A1", "B1", "A1", "C1", "A1"), n, TRUE)
)

microbenchmark::microbenchmark(
    dplyr = {f(abcd)},
    data.table = {g(abcd)},
    index = {h(abcd)},
    times = 10)
Unit: seconds
       expr      min       lq     mean   median       uq      max neval
      dplyr 5.193977 5.230753 5.299558 5.293965 5.356213 5.419657    10
 data.table 1.880420 1.929242 1.976511 1.980238 2.021672 2.089020    10
      index 1.866140 1.918988 1.979210 1.956200 2.053038 2.153510    10

请注意,在基于data.table的解决方案中,重复调用函数setDT(),在实际情况下使用时,它只会被调用一次。
支持索引向量解决方案,它仅使用基本R而无需加载外部包。

答案 2 :(得分:0)

您的int fd = open("/tmp/testfile", O_CREAT | O_EXCL); 解决方案本身是正确的

dplyr

您不需要跟进功能来检查条件,这是在abc <- abc %>% mutate( D = ifelse(C == "A1" & A > 2 , 1,NA))

内完成的

如果你真的想把结果传递给另一个函数,你需要删除ifelse作为第一个函数参数,因为它隐含在abc之后。

%>%

应该是

... %>% test(abc, arg2, arg3, ...)

答案 3 :(得分:0)

我们可以在函数中传递列名:

abc <- function_name(rlang::sym('column_name1'),rlang::sym('column_name2'))

function_name<- function( var1 , var2)
   {
      abc <- abc %>% 
      mutate( C = !!var1,
              A = !!var2)

#now everytime we call the function with specific column names the function 
#will refer to those column and iterate the values of the column to check 
#for any given conditions

abc <- abc %>% 
         mutate( new_col_D = ifelse(C == "A1" & A > 2 , 1,NA)))  

       abc <- abc %>% select(-A,-C)

       return(abc)        

    }