【问题标题】:R - data.table assign the name of a column that is the minium of a row as value to new columnR - data.table 将作为行的最小值的列的名称作为值分配给新列
【发布时间】:2021-05-30 13:00:23
【问题描述】:

感谢你们提出优雅的解决方案!两种解决方案都适用于我,但只有 melt() 和反向连接解决方​​案适用于带有日期而不是数值的 data.table。

编辑

我通过融合并结合 Wimpel 获得的结果实现了提议的 data.table 解决方案,因为他/她的解决方案也适用于存储在日期列中的日期,而不是最初的玩具数据都是整数值。

我更喜欢 Peace Wang 解决方案的可读性,尽管使用 data.table assignments 和 IMO,它的语法比 melt() 解决方案更清晰,但是(至少对我而言),它不起作用带有日期类型的列。

对数值/整数数据的两种解决方案进行基准测试,发现melt() 解决方案显然是赢家。


编辑 2 如果我实施 Peace Wang 提出的解决方案,要通过转换来复制 NA 值,请参阅下面的输入 data.table 的更正版本。

我有这样的东西: 将在不同日期进行的测量的患者记录列表成像。日期列的名称可能是“2020-12-15”/“2021-01-15”等。

 ID   Date_1       Date_2      Date_3   
  1   1990-01-01   1990-02-01  1990-03-01      
  2   1990-01-01   1990-02-01  1990-03-01       
  3   1990-01-01   1982-02-01  1990-03-01 

我已经确定了 data.table dt 中每一行的最小值,如下所示:

dt <- dt[, Min := do.call(pmin, c(.SD, list(na.rm = TRUE))), .SDcols = -(1)]

到目前为止一切顺利。现在我想添加一个新的 col Min_Date 说明每行找到的最小值的相应 col 名称(在我的示例中为日期),以最终得到这样的结果:

  ID   Date_1       Date_2      Date_3        Min        Min_Date
  1    1990-01-01   1990-02-01  1990-03-01   1990-01-01  Date_1
  2    1990-01-01   1990-02-01  1990-03-01   1990-01-01  Date_1
  3    1990-01-01   1982-02-01  1990-03-01   1982-02-01  Date_2

我尝试了以下变化:

dt <- dt[, Min_Date := do.call(which.pmin, c(.SD, list(na.rm = TRUE))),
                           .SDcols = (2:4)]

然后尝试用 col 索引做某事。还不知道我在.I 周围的方式,但是当我在这些方面使用时我无法让它工作:

exclusions.dt[exclusions.dt[, .I[which.min(.SD)], ISSUE_ID, .SDcols = (2:6)]$V1]

不胜感激!

【问题讨论】:

  • dt[,(date_min = colnames(.SD)[apply(.SD,1,which.min)]),.SDcols=!1]
  • 感谢您的建议。刚刚关闭了我的电脑。明天早上我会先试一试,然后再报告。
  • 了解提议的内部作用,我想知道为什么它给我关于NAs created through conversion 的重复警告...
  • dt[,.(date_min = colnames(.SD)[apply(.SD,1,which.min)]),.SDcols=!1] 这样会更好,.( )`` means list()```。

标签: r data.table


【解决方案1】:

这是另一个data.table 方法

#sample data
library( data.table )
DT <- fread("ID   Date_1   Date_2   Date_3   
  1    100      200      300      
  2    100      500      300      
  3    200      150      400    ")

#melt to long format and get rows with minimum value by ID
DT.min <- melt( DT, id.vars = "ID" )[ , .SD[ which.min(value) ], by = ID]
#    ID variable value
# 1:  1   Date_1   100
# 2:  2   Date_1   100
# 3:  3   Date_2   150

#join back to DT
DT[ DT.min, `:=`( Min = i.value, Min_Date = i.variable ), on = .(ID)][]
#    ID Date_1 Date_2 Date_3 Min Min_Date
# 1:  1    100    200    300 100   Date_1
# 2:  2    100    500    300 100   Date_1
# 3:  3    200    150    400 150   Date_2

【讨论】:

  • 感谢您的建议。我会试一试。只是为了澄清一下,DT.lookup 来自哪里?
  • 啊,在我的函数中完全理解和实现这种转换需要一段时间,但基本上DT.lookup 是我们想要作为lookup 的上一步中计算出的DT.min随后的连接,因为它包含所有想要的数据。 - 我做对了吗?有用!非常感谢!
  • 一个后续问题。如果在给定行中有超过 n>1 个日期等于给定行的最小值,该解决方案将如何表现?然后它会选择第一个匹配的(从 LHS 到 RHS)值的列名称为Min_Date
  • 是的。对不起命名混淆:)
【解决方案2】:

下面的代码可以工作。

dt <- fread("
             ID   Date_1   Date_2   Date_3
  1    100      200      300
  2    100      500      300
  3    200      150      400
")
dt[, `:=`(Min = do.call(pmin, c(.SD, list(na.rm = TRUE))),
          date_min = colnames(.SD)[apply(.SD, 1, which.min)]
         ), 
   .SDcols = -1]

如果您收到NAs 警告,也许您可​​以尝试先刷新dt

【讨论】:

  • 再次感谢王和平提出的解决方案。但是,我仍然得到NAs generated through conversion warnings。由于我的 data.table 很长,并且不断打印到控制台的警告大大减慢了速度,我将解决方案代码包装到 suppressWarnings({ your code }) 并检查了输出。第一部分按预期工作,计算Min 并将其存储在Min 列中。但是,date_min 列仅填充有 NAs
  • 复制并运行我的整个代码后是否收到警告?我建议你用rm(list = ls()) 清理你的变量环境(特别是dt)。
  • 呵呵,真没意思。根据玩具数据,一切都按预期顺利运行....我清理环境后再试
  • 这是有道理的。我猜你的NAs generated through conversion warnings 警告是由于你在dtexclusions.dt 上的多个:=。清除环境后,第一个 := 操作应该会按预期运行所有内容。
  • 我编辑了主要问题,以便数据现在包括真实日期而不是玩具整数值。使用这些值,您还应该在最后的date_min 列中看到NAs
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-26
  • 1970-01-01
相关资源
最近更新 更多