使用 by = 数据表的每一行

问题描述 投票:0回答:3

我有一个数据表,我正在尝试创建一个新变量,该变量是所有其他列的函数。一个简化的示例是,如果我只想对所有行求和或取平均值。例如:

dt <- data.table(a = 1:9, b = seq(10,90,10), c = seq(11:19), d = seq(100, 900, 100))

我想创建一个向量/列,它只是所有列的平均值。我想到的语法看起来像这样:

dt[, average := mean(.SD)]

然而,这就是整个事情的总结。我知道我也可以:

dt[, average := lapply(.SD, mean)] 

但这给出了单行结果。我本质上是在寻找相当于:

dt[, average := lapply(.SD, mean), by = all]

这样它就可以简单地计算所有行的值,而无需创建“id”列并通过该列进行所有计算。这可能吗?

r data.table
3个回答
21
投票

以下 data.table 代码对我有用。

 dt[, average := rowMeans(.SD)]

正如 @jangorecki 所指出的,只要您记住每一行都是一个列表对象,就可以构造自己的函数来按行运行:

# my function, must unlist the argument
myMean <- function(i, ...) mean(unlist(i), ...)

使用

by=seq_len

dt[, averageNew := myMean(.SD), by = seq_len(nrow(dt))]

使用

row.names

dt[, averageOther := myMean(.SD), by = row.names(dt)]

7
投票

我认为更好的解决方案就是使用

apply
来实现此目的,它是为行式矩阵类操作而设计的,而
data.table
则不是。

> dt$average = apply(dt, 1, mean)
> dt

   a  b c   d average
1: 1 10 1 100      28
2: 2 20 2 200      56
3: 3 30 3 300      84
4: 4 40 4 400     112
5: 5 50 5 500     140
6: 6 60 6 600     168
7: 7 70 7 700     196
8: 8 80 8 800     224
9: 9 90 9 900     252

0
投票

使用 data.table by 子句的优点是可以直观地将每一列视为函数中的原子值。您还可以将该函数应用于过滤行,只需使用 by=1:length(column) 即可。使用 data.table 应该比 apply 函数快得多。

dt <- data.table(a = 1:9, b = seq(10,90,10), c = seq(11:19), d = seq(100, 900, 100))
dt[a>2,avg:=mean(c(a,b,c,d)), by=1:length(a)]
dt

   a  b c   d avg
1: 1 10 1 100  NA
2: 2 20 2 200  NA
3: 3 30 3 300  84
4: 4 40 4 400 112
5: 5 50 5 500 140
6: 6 60 6 600 168
7: 7 70 7 700 196
8: 8 80 8 800 224
9: 9 90 9 900 252
© www.soinside.com 2019 - 2024. All rights reserved.