首页 > 解决方案 > 根据其他列中的最小值查找列值和名称

问题描述

我有一个看起来像这样的 data.table

library( data.table )

dt <- data.table( p1 = c("a", "b", "c", "d", "e", "f", "g"), 
                  p2 = c("b", "c", "d", "a", "f", "g", "h"), 
                  p3 = c("z", "x", NA, NA, "y", NA, "s"), 
                  t1 = c(1, 2, 3, NA, 5, 6, 7), 
                  t2 = c(7, 6, 5, NA, 3, 2, NA), 
                  t3 = c(8, 3, NA, NA, 2, NA, 1) )

#    p1 p2   p3 t1 t2 t3
# 1:  a  b    z  1  7  8
# 2:  b  c    x  2  6  3
# 3:  c  d <NA>  3  5 NA
# 4:  d  a <NA> NA NA NA
# 5:  e  f    y  5  3  2
# 6:  f  g <NA>  6  2 NA
# 7:  g  h    s  7 NA  1

它具有代表名称的 p 列和代表值的 t 列。t1 是对应于 p1 的值,t2 对应于 p2 等。
在每一行上,p 列的值是唯一的(或NA)。t 列中的值也是如此。

我想要做的是创建三个新列:

我更喜欢 a data.table,因为我的实际数据包含更多的行和列。我知道熔化是一种选择,但我想用这些数据来保存我的内存,所以使用的内存越少越好(生产数据包含几百万行和 >200 列)。

到目前为止,我已经找到了一种t_min使用以下方法创建 -column 的方法:

t_cols = dt[ , .SD, .SDcols = grep( "t[1-3]", names( dt ), value = TRUE ) ]
dt[ !all( is.na( t_cols ) ), 
    t_min := do.call( pmin, c( .SD, list( na.rm = TRUE ) ) ), 
    .SDcols = names( t_cols ) ]

但我无法全神贯注地创建p_minp_col_min列。我想which.min()在某个地方发挥作用,但我无法弄清楚。可能我忽略了一些简单的事情(它似乎总是.. ;-))。

期望的输出

dt.desired <- data.table( p1 = c("a", "b", "c", "d", "e", "f", "g"), 
                          p2 = c("b", "c", "d", "a", "f", "g", "h"), 
                          p3 = c("z", "x", NA, NA, "y", NA, "s"), 
                          t1 = c(1, 2, 3, NA, 5, 6, 7), 
                          t2 = c(7, 6, 5, NA, 3, 2, NA), 
                          t3 = c(8, 3, NA, NA, 2, NA, 1),
                          t_min = c(1,2,3,NA,2,2,1),
                          p_min = c("a","b","c",NA,"y","g","s"),
                          p_col_min = c("p1","p1","p1",NA,"p3","p2","p3") )

#    p1 p2   p3 t1 t2 t3 t_min p_min p_col_min
# 1:  a  b    z  1  7  8     1     a        p1
# 2:  b  c    x  2  6  3     2     b        p1
# 3:  c  d <NA>  3  5 NA     3     c        p1
# 4:  d  a <NA> NA NA NA    NA  <NA>      <NA>
# 5:  e  f    y  5  3  2     2     y        p3
# 6:  f  g <NA>  6  2 NA     2     g        p2
# 7:  g  h    s  7 NA  1     1     s        p3

标签: rdata.table

解决方案


这是另一条路线:

dt[, t_min := do.call(pmin, c(.SD, na.rm = TRUE)), .SDcols = patterns('t[[:digit:]]')]

dt[!is.na(t_min),
   c('p_min', 'p_min_col') := {

     arr_ind = .SD[, which(t_min == .SD, arr.ind = TRUE), .SDcols = patterns('t[[:digit:]]')]
     arr_ind = arr_ind[order(arr_ind[, 1]), ]

     p_m = .SD[, as.matrix(.SD)[arr_ind], .SDcols = patterns('p')]
     p_m_c = grep('^p', names(.SD), value = TRUE)[arr_ind[, 2]]

     list(p_m, p_m_c)
     } 
   ]

推荐阅读