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

7vux5j2d  于 12个月前  发布在  其他
关注(0)|答案(4)|浏览(96)

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

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==“A1”且A > 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
        }

此代码给出错误(仅检查第一行)
于是,我尝试着去改变。它工作

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,在调用这个函数之前,我必须检查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)
} 
}

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

wlwcrazw

wlwcrazw1#

你应该使用data.table框架来使它更快:

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

uyhoqukh2#

提出的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,而不需要加载外部包。

ogq8wdun

ogq8wdun3#

您的dplyr解决方案本身是正确的

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

你不需要一个跟踪函数来检查条件,这是在ifelse中完成的。
如果你真的想把结果传递给另一个函数,你需要删除abc作为第一个函数参数,因为这是在%>%之后隐式的。

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

... %>% test(arg2, arg3, ...)
46scxncf

46scxncf4#

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

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)        

    }

相关问题