R 使用应用于多列的多个函数在data.table中生成多个新列

R 使用应用于多列的多个函数在data.table中生成多个新列,r,data.table,R,Data.table,我想对data.table的几列应用几个函数,并根据输出生成新的列。我在这里发现了类似的问题,但提供的答案似乎没有解决我的确切问题,例如: 生成一些数据: 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", "no

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

生成一些数据:

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)
我成功地生成了所需数量的列。但是,所有四列在每一行中都包含相同的值,即使它可能不相同,如以下代码段的输出所示:

dt[, unlist(lapply(.SD, my.summary)), .SDcols = c("time1", "time2"), by = p]
我想做的第二点是,根据以上列time1和time2的标准计算接近度1和2的平均值(同样是分别计算p的每个值,即,
by=p
),并使用上述格式“scliq”/“symgr”将输出保存在新列中。例如,我想计算time1中7或7以下的所有分数以及time1中8到31之间的所有分数的接近度1的平均值(对于接近度2和time2也是如此)


我还应该注意到,我知道如何使用tidyverse软件包解决这个问题,但为了简洁和高效,我非常希望在
data.table
中学习如何解决这个问题。任何提示或解决方案都将不胜感激。

您使用
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]
另一个选项是计算子表中的平均值,然后返回:

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"]

dt[dt[time1 7&time2一些建议:(1)如果你在
.SD
中只使用一列,你也可以直接使用它(尽管没有引号);(2)与其在条件上使用
lenght
which
,不如使用
sum
。例如:
sum(time1非常感谢。这很有效。你知道我可以如何进行第二部分,即根据第x列中的标准(例如,任何分数低于7分的人)在第y列上运行函数(例如,平均值)?@Tiberius我有一些想法。我更新了答案。太棒了,非常有魅力。我最后做了这样的事情:
dt[,c(“平均值1”、“平均值2”、“平均值3”、“平均值4”):=。(.SD[time1 7和time1
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]
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"]