вычислить медиану по данным.столбцы таблицы в р

Я пытаюсь вычислить медианное значение по ряду столбцов, однако мои данные немного напуганы. Это выглядит следующим примером.

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 ответов


вот еще data.table путь (при условии unique 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 без изменения формы (который я, как правило, использую в крайнем случае).


вам нужен словарь для перевода имен столбцов на соответствующие числа, а затем это довольно просто:

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

вот способ, который позволяет избежать операций по строкам и переформирования:

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) В конце.


здесь 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