【问题标题】:Update some columns conditionally with max value for all values in chosen columns (data.table, r)使用所选列中所有值的最大值有条件地更新某些列(data.table,r)
【发布时间】:2016-04-19 20:52:20
【问题描述】:

我有一个 900,000 x 500 类型的数据集,但下面显示了一个适合该问题的玩具数据集。

library(data.table)
df1 <- data.table(x = c(1,2,4,0), y = c(0,0,10,15), z = c(1,1,1,0))

我想做以下事情:

  1. 对于列 y 和 z
  2. 选择值 = 0 的行
  3. 将这些替换为 max+1,其中 max 是在整个列上计算的

我对 data.table 很陌生。在stackoverflow上查看问题示例,我找不到类似的问题,除了这个: How to replace NA values in a table *for selected columns*? data.frame, data.table

我自己的尝试如下,但这不起作用:

for (col in c("x", "y")) df1[(get(col)) == 0, (col) := max(col) + 1)

显然,我还没有习惯data.table,所以我现在正在用头撞墙......

如果除了data.table 之外还有人可以提供dplyr 解决方案,我将不胜感激。

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    我们可以使用set 并将值为0 的行分配给该列的max +1。

     for(j in c("y", "z")){
        set(df1, i= which(!df1[[j]]), j=j, value= max(df1[[j]])+1)
     }
    
    df1
    #   x  y z
    #1: 1 16 1
    #2: 2 16 1
    #3: 4 10 1
    #4: 0 15 2
    

    注意:set 方法将非常有效,因为避免了 [.data.table 的开销


    或者一种效率较低的方法是在 .SDcols 中指定感兴趣的列,遍历列 (lapply(..),replace 基于逻辑索引的值,然后分配 (:=)输出回列。

    df1[, c('y', 'z') := lapply(.SD, function(x) 
             replace(x, !x, max(x)+1)), .SDcols= y:z]
    

    【讨论】:

    • 再次感谢您的帮助!我也尝试使用set,但无法帮助自己使用它。我会接受这个答案。
    【解决方案2】:

    dplyr 版本非常简单(我认为)

    > library(dplyr)
    # indented for clarity
    > mutate(df1, 
        y= ifelse(y>0, y, max(y)+1), 
        z= ifelse(z>0, z, max(z)+1))
    
      x  y z
    1 1 16 1
    2 2 16 1
    3 4 10 1
    4 0 15 2
    

    编辑 正如 cmets 中的 David Arenburg 所指出的,这对玩具示例很有帮助,但对 500 列的数据没有帮助。他提出了类似的建议:

    df1 %>% mutate_each(funs(ifelse(. > 0, ., max(.) + 1)), -1)
    

    -1 指定除第一列之外的所有列

    【讨论】:

    • 其实没有。OP有500列。 “dplyr 方式”类似于dt %&gt;% mutate_each(funs(ifelse(. &gt; 0, ., max(.) + 1)), y:z) 或类似的东西。
    • 好的,也可以。我会添加它来回答你。
    【解决方案3】:

    作为替代,ifelse(test, yes, no) 可能有用

    顺其自然

    library(data.table)
    dt <- data.table(x = c(1,2,4,0), y = c(0,0,10,15), z = c(1,1,1,0))
    
    print(dt)
    
    dt[, y := ifelse(!y, max(y) + 1, y)]
    
    print(dt)
    

    【讨论】:

    • 谢谢。但是,由于我有将近 500 列,因此很难对每列使用 ifelse。 lapply 可以在这里使用更简单的ifelse 吗?
    • @info_seekeR 是的,lapply 可以在这里使用,就像在 akrun 的帖子中一样。因为你说你有大数据,你可能想考虑这篇文章说ifelse 可能很慢(我不确定它是否适用于你的情况):stackoverflow.com/a/16275201/1191259
    • @info_seekeR 如何循环列与如何处理每列的问题正交,因此正如@Frank 所说,lapply 的使用方式与@arkun 的答案相同。 Wrt 是否缓慢,你没有衡量标准。如果速度是一个问题,首先要做的是,恕我直言,在replaceifelse 之外单独计算max(c)+1
    • 如果你已经陷入这种困境,你可以只做 dt[y == 0L, y := max(dt$y) + 1L] 以避免一起使用 ifelse (这对 replace IMO 没有任何新内容)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-21
    • 2022-07-05
    • 1970-01-01
    • 1970-01-01
    • 2022-01-14
    • 2013-04-13
    • 1970-01-01
    相关资源
    最近更新 更多