根据R中的data.table列计算中值
我试图计算一个跨多个列的中值,但是我的数据有点古怪。它看起来像下面的示例根据R中的data.table列计算中值,r,data.table,lapply,rep,R,Data.table,Lapply,Rep,我试图计算一个跨多个列的中值,但是我的数据有点古怪。它看起来像下面的示例 library(data.table) dt <- data.table("ID" = c(1,2,3,4),"none" = c(0,5,5,3), "ten" = c(3,2,5,4),"twenty" = c(0,2,3,1)) ID none ten twenty 1: 1 0 3 0 2: 2 5 2 2 3: 3
library(data.table)
dt <- data.table("ID" = c(1,2,3,4),"none" = c(0,5,5,3),
"ten" = c(3,2,5,4),"twenty" = c(0,2,3,1))
ID none ten twenty
1: 1 0 3 0
2: 2 5 2 2
3: 3 5 5 3
4: 4 3 4 1
是我想要创建的计算
对于ID=2
median(c(0, 0, 0, 0, 0, 10, 10, 20, 20))
我曾经尝试过使用
rep()
和lappy()
,但收效甚微,我正在寻找一些关于如何实现这一目标的明确指导。我知道对于rep()
这样的人,我必须硬编码我的值以重复(例如rep(0,2)
或rep(10,2)
),这就是我所期望的。我正在努力创建一个列表或向量,每个列都有重复。您需要一个字典来将列名翻译成相应的数字,然后它就相当简单了:
dict = data.table(name = c('none', 'ten', 'twenty'), number = c(0, 10, 20))
melt(dt, id.var = 'ID')[
dict, on = c(variable = 'name')][, median(rep(number, value)), by = ID]
# ID V1
#1: 1 10
#2: 2 0
#3: 3 10
#4: 4 10
以下是一种按行
dplyr
方式:
dt %>% rowwise %>%
do(med = median(c(rep(0, .$none), rep(10, .$ten), rep(20, .$twenty)))) %>%
as.data.frame
med
1 10
2 0
3 10
4 10
受@Arun答案的启发,这也起到了作用:
dt %>% group_by(ID) %>%
summarise(med = median(rep(c(0, 10, 20), c(none, ten, twenty))))
Source: local data table [4 x 2]
ID med
(dbl) (dbl)
1 1 10
2 2 0
3 3 10
4 4 10
下面是另一个
数据。表
方式(假设唯一的ID
):
这只是一种尝试,目的是在不改变形状的情况下获得@eddi的答案(我倾向于将其作为最后手段)。以下是一种避免行操作和改变形状的方法:
dt[, m := {
cSD = Reduce(`+`, .SD, accumulate=TRUE)
k = floor(cSD[[length(.SD)]]/2)
m = integer(.N)
for(i in seq_along(cSD)) {
left = m == 0L
if(!any(left)) break
m[left] = i * (cSD[[i]][left] >= k[left])
}
names(.SD)[m]
}, .SDcols=none:twenty]
给
ID none ten twenty m
1: 1 0 3 0 ten
2: 2 5 2 2 none
3: 3 5 5 3 ten
4: 4 3 4 1 ten
对于循环,我借用了@alexis_laz的风格,例如
我跳过了列名的翻译,但这很简单。您可以在结尾使用
c(0,10,20)
而不是名称(.SD)
示例中创建dt
的代码与问题描述不匹配。这只是一个输入错误,但一开始让我感到困惑,因为所有的答案都与您预期的结果不同。对于ID=2,“无”
和“二十”
的数字互换。根据你的代码,你将得到ID=2的中位数(0,0,0,0,0,10,10,20,20)@Uwe好的,抓到了。我试图修复它,以便显示的内容与示例输入匹配。如果有问题,我怀疑OP会介意编辑;如果我们错了,他们总是可以把它们回滚。这个.SDcols=none:twenty
很漂亮。我不知道你能做到。还有,什么是.N
?@Bazz是的,.SDcols的快捷方式是最近才添加的.N
指的是表中的行数,或者,如果有一个by=
子句(就像在Arun的回答中),它指的是by-group.Nice-clean单行代码中的行数,这正是我试图实现的。我必须对我的价值观进行硬编码,这样才能最好地回答这个问题,尽管我也可以看到,如果我的价值观也在一个专栏中,它将如何适用。
dt[, m := {
cSD = Reduce(`+`, .SD, accumulate=TRUE)
k = floor(cSD[[length(.SD)]]/2)
m = integer(.N)
for(i in seq_along(cSD)) {
left = m == 0L
if(!any(left)) break
m[left] = i * (cSD[[i]][left] >= k[left])
}
names(.SD)[m]
}, .SDcols=none:twenty]
ID none ten twenty m
1: 1 0 3 0 ten
2: 2 5 2 2 none
3: 3 5 5 3 ten
4: 4 3 4 1 ten