【问题标题】:Generating multiple new columns in data.table using multiple functions applied to multiple columns使用应用于多个列的多个函数在 data.table 中生成多个新列
【发布时间】:2019-07-29 16:48:48
【问题描述】:

我想将多个函数应用于 data.table 的多个列,并根据输出生成新列。我在这里找到了类似的问题,但提供的答案似乎没有解决我的确切问题,例如:

Apply multiple functions to multiple columns in data.table

ddply to multiple columns equivalent in data.table

R data.table - Apply function A to some columns and function B to some others

生成一些数据:

set.seed(1)
p <- rep(seq(1:10),4)
p

time1 <- sample(1:40, 40, replace=TRUE)
time2 <- sample(1:40, 40, replace=TRUE)
contact1 <- sample(rep(c("personal", "nonpersonal"),20), 40)
contact2 <- sample(rep(c("personal", "nonpersonal"),20), 40)
closeness1 <- sample(1:10, 40, replace=TRUE)
closeness2 <- sample(1:10, 40, replace=TRUE)

dt <- data.table::data.table(p, time1, time2, contact1, contact2, closeness1, closeness2)

这可行,但似乎效率低下,因为我分别为每一列运行它:

# s1
dt[, c("scliq.s", "symgr.s") :=list(length(which(.SD<=7)), length(which(.SD>7 & .SD<=31))), .SDcols="time1", by = p]

# d1
dt[, c("scliq.d", "symgr.d") :=list(length(which(.SD<=7)), length(which(.SD>7 & .SD<=31))), .SDcols="time2", by = p]

# s2
dt[, c("pers.s", "npers.s") :=list(length(which(.SD=="personal"))/length(which(.SD=="personal" | .SD=="nonpersonal")), length(which(.SD=="nonpersonal"))/length(which(.SD=="personal" | .SD=="nonpersonal"))), .SDcols="contact1", by = p]

# d2
dt[, c("pers.d", "npers.d") :=list(length(which(.SD=="personal"))/length(which(.SD=="personal" | .SD=="nonpersonal")), length(which(.SD=="nonpersonal"))/length(which(.SD=="personal" | .SD=="nonpersonal"))), .SDcols="contact2", by = p]

我曾尝试修改其他帖子中的类似解决方案。为了简单起见,我只为# s1# d1 尝试了这个,但最终想一次性完成# s1# d1# s2# d2。我没有卡在length(which) 上,只需要计算每种情况下的实例数(table() 也可以,但我无法让data.table 保存来自table() 的正确输出):

# option 1
my.summary = function(x) list(count1 = length(which(x<=7)), count2 = length(which(x>7 & x<=31)))

dt[, c("scliq.s", "symgr.s", "scliq.d", "symgr.d") :=unlist(lapply(.SD, my.summary)), .SDcols = c("time1", "time2"), by = p]

# option 2, note: I wasn't sure how to adapt sum/mean to a nested function call (i.e., length(which))
dt$dday <- 1 # add a constant column
dt <- dcast(dt, dday~dday, fun=list(sum, mean), value.var = c("time1", "time2"))

我成功生成了所需数量的列。但是,所有四列在每一行中都包含相同的值,即使它可能不相同,如以下代码 sn-p 的输出所示:

dt[, unlist(lapply(.SD, my.summary)), .SDcols = c("time1", "time2"), by = p]

我想做的第二点是根据上述 time1 和 time2 列的标准计算 closeness1 和 2 的平均值(再次分别针对 p 的每个值,即by = p)并保存使用格式“scliq”/“symgr”在新列中输出,如上所述。例如,我想计算 time1 中所有分数等于或低于 7 以及 time1 中所有分数在 8 到 31 之间的 closeness1 平均值(同样适用于 closeness2 和 time2)。

我还应该注意,我知道如何使用 tidyverse 包解决这个问题,但为了简洁和高效,我很想在data.table 中学习如何做到这一点。任何提示或实际上的解决方案将不胜感激。

【问题讨论】:

  • 一些建议:(1)如果你只使用.SD中的一列,你也可以直接使用它(虽然没有引号); (2)在条件上不要使用lenghtwhich,最好使用sum。例如:sum(time1 &lt;= 7).

标签: r data.table


【解决方案1】:

my.summary 的解决方案不起作用的原因是 unlist 默认情况下是递归的, 所以它最终将所有嵌套列表中的所有值打包在一个向量中, 而data.table 最终会默默地回收值。 考虑到 Jaap 的评论, 你可以写:

my.summary = function(x) list(sum(x<=7), sum(x>7 & x<=31))

dt[, c("scliq.s", "symgr.s", "scliq.d", "symgr.d") := unlist(lapply(.SD, my.summary), recursive = FALSE),
   .SDcols = c("time1", "time2"), by = p]

对于手段,我可​​以想到 2 个选项, 第一个使用.SDby, 有时可能很慢:

dt[, c("mean1", "mean2") := .(.SD[time1 <= 7, mean(closeness1)], 
                              .SD[time2 > 7 & time2 <= 31, mean(closeness2)]),
   by = p,
   .SDcols = time1:closeness2]

另一种选择是计算子表中的均值,然后返回:

dt[dt[time1 <= 7, .(ans = mean(closeness1)), by = p], mean1 := ans, on = "p"]
dt[dt[time2 > 7 & time2 <= 31, .(ans = mean(closeness2)), by = p], mean2 := ans, on = "p"]

根据您的实际数据, 一个可能比另一个快, 所以你应该给他们计时。

【讨论】:

  • 非常感谢。这很好用。你知道我会如何处理第二个问题,即根据 x 列中的标准(例如分数低于 7 的任何人)在 y 列上运行一个函数(例如平均值)吗?
  • @Tiberius 我有几个想法。我已经更新了答案。
  • 很棒,就像一个魅力。我最终做了这样的事情:dt[, c("mean1", "mean2", "mean3", "mean4") := .( .SD[time1 &lt;= 7, mean(closeness1)], .SD[time1 &gt; 7 &amp; time1 &lt;= 31, mean(closeness1)], .SD[time2 &lt;= 7, mean(closeness2)], .SD[time2 &gt; 7 &amp; time2 &lt;= 31, mean(closeness2)]), by = p, .SDcols = c("time1", "time2", "closeness1","closeness2")]
猜你喜欢
  • 2015-06-19
  • 1970-01-01
  • 2018-04-23
  • 2013-01-09
  • 2021-08-09
相关资源
最近更新 更多