从R中的data.table列计算中位数

时间:2016-06-01 21:48:36

标签: 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    5   5      3
4:  4    3   4      1

表格中的列表示该值的出现次数。我想计算中位数。

例如ID = 1

median(c(10, 10, 10))

是我想要创建的计算。

表示ID = 2

median(c(0, 0, 0, 0, 0, 10, 10, 20, 20))

我尝试过使用rep()lapply()取得的成功非常有限,并且已经明确指出如何实现这一目标。我理解rep()之类的内容我将不得不重复编码我的重复值(例如rep(0,2)rep(10,2)),这就是我所期望的。我正在努力创建一个包含每列重复的列表或向量。

4 个答案:

答案 0 :(得分:16)

这是另一种data.table方式(假设唯一ID):

dt[, median(rep(c(0, 10, 20), c(none, ten, twenty))), by=ID]
#    ID V1
# 1:  1 10
# 2:  2  0
# 3:  3 10
# 4:  4 10

这只是试图在没有重塑的情况下获得@ eddi的答案(我倾向于将其作为最后的手段)。

答案 1 :(得分:12)

你需要一本字典来将列名翻译成相应的数字,然后它相当简单:

module.exports

答案 2 :(得分:6)

这是一种避免行间操作和重新整形的方法:

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'样式,例如https://stackoverflow.com/a/30513197/

我已经跳过了列名的翻译,但这非常简单。您最后可以使用c(0,10,20)代替names(.SD)

答案 3 :(得分:3)

以下是rowwise 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