【问题标题】:R assign ID to records NOT using loopsR将ID分配给不使用循环的记录
【发布时间】:2019-11-25 19:46:27
【问题描述】:

我需要遍历数据表“A”并根据条件为该记录或记录组分配一个增量 ID,例如:

library(data.table)
A <- data.table(x = c(1,2,3,4,5,6,7,8,9,10,11,12,13,14), 
  y = c(2,2,2,2,2,2,2,2,3,3,3,3,3,3), z = 0)

for(i in 1:nrow(A))
 {
   if((A[i]$x %% A[i]$y) == 0) {A[i]$z <- i}
   print(i)
 }

z 列成为一种滚动 ID。 我需要在不使用循环的情况下执行相同的操作。

【问题讨论】:

    标签: r loops data.table vectorization


    【解决方案1】:

    或者你可以试试这个(sinde x 已经包含索引值)

    在满足x %% y == 0 条件的行上使用 x 值更新(通过引用)z 值。在所有其他行上,z 保持其原始值(即 0)。

    A[ x %% y == 0, z:=x]
    
    #     x y  z
    # 1:  1 2  0
    # 2:  2 2  2
    # 3:  3 2  0
    # 4:  4 2  4
    # 5:  5 2  0
    # 6:  6 2  6
    # 7:  7 2  0
    # 8:  8 2  8
    # 9:  9 3  9
    # 10:10 3  0
    # 11:11 3  0
    # 12:12 3 12
    # 13:13 3  0
    # 14:14 3  0
    

    当然你也可以使用.I来获取一行的索引

    A[ x %% y == 0, z := .I]
    

    也可以使用...根据您的列类,您必须将一些整数列设置为双精度类,以避免出现警告消息。

    基准

    最多 50000 行,Ronaks 的答案更快,在此之上,.I 解决方案是“获胜”。

    用于基准测试的代码

    vec <- c( seq( 1,10000, by = 1000), seq( 1,100000, by = 10000), 
              seq( 1,1000000, by = 100000), seq( 1,10000000, by = 1000000) )
    
    l <- lapply( vec, function(x){
      A <- data.table(x = as.double( 1:x ), 
                      y = as.double( sample(2:3, x, replace = TRUE) ), 
                      z = as.double(0) )
      m <- microbenchmark::microbenchmark(
        Ronak = { 
          DT <- copy(A)
          inds <- DT$x %% DT$y == 0
          DT$z[inds] <- which(inds)
        },
        Wimpel = {
          DT <- copy(A)
          DT[ x %% y == 0, z:=as.double(.I)]
        },
        times = 10 )
      setDT(m)[, .(n = x, median = median(time)), by = .(expr)][]
    })
    
    library(scales)
    library(ggplot2)
    ggplot( data = rbindlist(l), aes( x = n, y = median/1000000, group = expr, colour = expr )) + 
      geom_smooth( se = FALSE ) +
      labs( x = "rows",
            y = "median [ms]" ) 
    

    【讨论】:

    • 对于较大的行,这里的速度稍快一些,与较小的行数非常相似。 A[['z']] &lt;- A[['x']]; A[['z']][A[['x']] %% A[['y']] != 0 ] &lt;- 0。它不是最好看的,但它确实适用于 base 和 data.table。
    【解决方案2】:

    你可以得到%%运算符返回0的索引,并在该位置分配索引值。

    inds <- A$x %% A$y == 0
    A$z[inds] <- which(inds)
    
    A
    #     x y  z
    # 1:  1 2  0
    # 2:  2 2  2
    # 3:  3 2  0
    # 4:  4 2  4
    # 5:  5 2  0
    # 6:  6 2  6
    # 7:  7 2  0
    # 8:  8 2  8
    # 9:  9 3  9
    #10: 10 3  0
    #11: 11 3  0
    #12: 12 3 12
    #13: 13 3  0
    #14: 14 3  0
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-09-20
      • 1970-01-01
      • 1970-01-01
      • 2017-02-09
      • 2019-02-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多