我试图做一件简单的事情,按照他们的意思划分40列data.table。我无法提供实际数据(并非所有列都是数字,而且我有> 8M行),但这里有一个例子:
library(data.table)
dt <- data.table(matrix(sample(1:100,4000,T),ncol=40))
colmeans <- colMeans(dt)
接下来我以为我会这样做:
for (col in names(colmeans)) dt[,col:=dt[,col]/colmeans[col]]
但是这会返回一个错误,因为dt[,col]
要求不引用列名。使用as.name(col)
并不会将其删除。
现在,
res <- t(t(dt[,1:40,with=F]/colmeans))
包含展开的结果,但我无法将其插回到data.table中,如
dt[,1:40] <- res
不起作用,dt[,1:40:=res, with=F]
也不起作用。
以下作品,但我觉得它很难看:
for (i in seq_along(colmeans)) dt[,i:=dt[,i,with=F]/colmeans[i],with=F]
当然,我也可以通过调用data.table()
上的res
和我的data.table所具有的其他非数字列重新创建一个新的data.table,但他们的效率并不高?
答案 0 :(得分:25)
怎么样
dt[, (names(dt)) := lapply(.SD, function(x) x/mean(x))]
如果您需要指定某些列,可以使用
dt[, 1:40 := lapply(.SD, function(x) x/mean(x)), .SDcols = 1:40]
或
cols <- names(dt)[c(1,5,10)]
dt[, (cols) := lapply(.SD, function(x) x/mean(x)), .SDcols = cols]
答案 1 :(得分:3)
我们也可以使用set
。在这种情况下,使用[.data.table
和:=
应该没有明显区别,但在必须多次调用[.data.table
的情况下,使用set()
有助于避免这种情况开销和可能显着加快。
for(j in names(dt)) {
set(dt, i=NULL, j = j, value = dt[[j]]/mean(dt[[j]]))
}
也可以在选定的列上完成,即
nm1 <- names(dt)[1:5]
for(j in nm1){
set(dt, i = NULL, j = j, value = dt[[j]]/mean(dt[[j]]))
}
set.seed(24)
dt <- as.data.frame(matrix(sample(1:100,4000,TRUE),ncol=40))
setDT(dt)
答案 2 :(得分:3)
dplyr 0.4.3
要按平均值划分所有列,您可以执行以下操作:
dplyr::mutate_each(dt, funs(. / mean(.)))
或者指定列位置:
dplyr::mutate_each(dt, funs(. / mean(.)), 5:10)
或列名:
dplyr::mutate_each_(dt, funs(. / mean(.)), colnames(dt)[5:10])
dplyr 0.4.3.9000
如果您只想划分数字列,则dplyr
的devel版本具有mutate_if
,该版本对谓词返回TRUE
dplyr::mutate_if(dt, is.numeric, funs(. / mean(.)))
答案 3 :(得分:1)
一点melt
和dcast
魔法怎么样?这会将数据转换为“长”格式,然后再转换回原始的“宽”格式。
首先,melt
ID上的变量:
# make an ID variable
dt[, idvar := 1:nrow(dt)]
# melt the data on the ID variable
dt2 <- melt(dt, "idvar")
然后通过平均操作对每个组进行划分:
# use data.table by = to do a fast division by group mean
dt2[, divByMean := value / mean(value), by = variable]
dt2
## idvar variable value divByMean
## 1: 1 V1 15 0.2859867
## 2: 2 V1 92 1.7540515
## 3: 3 V1 27 0.5147760
## 4: 4 V1 7 0.1334604
## 5: 5 V1 18 0.3431840
## ---
## 3996: 96 V40 54 1.1111111
## 3997: 97 V40 51 1.0493827
## 3998: 98 V40 23 0.4732510
## 3999: 99 V40 8 0.1646091
## 4000: 100 V40 11 0.2263374
然后回到原来的宽幅格式:
# now dcast back to "wide"
dt3 <- dcast(dt2, idvar ~ variable, mean, value.var = "divByMean")
dt3[1:5, 1:5]
## idvar V1 V2 V3 V4
## 1 1 0.2859867 0.6913303 0.2110919 1.6156624
## 2 2 1.7540515 0.7847534 0.5948954 1.8817715
## 3 3 0.5147760 0.2615845 0.8827480 0.4181715
## 5 5 0.3431840 0.3550075 0.3646133 0.3231325
## 4 4 0.1334604 1.7937220 1.3241220 1.3685611