我有一个包含name
和class
的data.table。每个name
属于一个class
。这是一个示例数据集。
library(data.table)
DT <- data.table(name = c("John","Smith","Jane","Ruby","Emerald","Jasmine","Tulip"),
class = c(1,2,3))
我想创建一个列,其中包含一个人所属的班级中的所有学生。这就是我正在做的事情并且它有效。
DT[, class.students := paste(.SD), .SDcols = "name", by = "class"]
我试图理解为什么以下内容不起作用,即它不会评估组中所有name
列表中的函数(它只返回name
创建列中行的值)
DT[, class.students := paste(name), by = "class"]
特别是下面的max
代码按预期工作时,即它会对组中的所有元素进行求值,并为每个组返回相同的值。
DT[, class.students := max(name), by = "class"]
我在这里缺少什么?
编辑:max
是一个糟糕的例子,因为它不能以第一种方式使用.SDcols
,但我希望我想传达的内容很明确。
答案 0 :(得分:3)
.SD
是list
,因此它会返回一个可能不合适的输出(如果我们检查str
)。作为一个小例子
paste(list(letters[1:3])) #not the desirable output
#[1] "c(\"a\", \"b\", \"c\")"
paste(letters[1:3]) #did not change anything
#[1] "a" "b" "c"
但是,paste
也有sep
和collapse
作为参数
paste(letters[1:3], collapse=", ")
#[1] "a, b, c"
使用OP的例子,
DT[, class.students := paste(name, collapse=", "), by = class]
我们建议直接将函数应用于.SD
,但如果只有一列,我们可以list
将vector
转换为[[
或转换为unlist
与DT[, class.students := paste(unlist(.SD), collapse=", "), by = class]
等。
DT[, class.students := paste(.SD[[1]], collapse=", "), by = class]
或者
str(DT)
如果我们检查上述所有内容中的.SD
,那就是相同的
关于在list
上应用函数的最佳方式 - 正如我们已经提到的那样,它是.SD
。当列数更多时,data.frame
非常有用。与lapply
中一样,当有多个列时,我们使用DT[, class.students := lapply(.SD, paste, collapse=", "), by = class]
遍历列并继续
.SDcols
如果只使用了一列列,我们也可以指定.SDcols
。这里,在示例中,只有两列,因此不需要str(DT)
#Classes ‘data.table’ and 'data.frame': 7 obs. of 3 variables:
# $ name : chr "John" "Smith" "Jane" "Ruby" ...
# $ class : num 1 2 3 1 2 3 1
# $ class.students: chr "John, Ruby, Tulip" "Smith, Emerald" "Jane, Jasmine" "John, Ruby, Tulip" ...
# - attr(*, ".internal.selfref")=<externalptr>
。
time