2016-06-01 4 views
14

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

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)), и это то, что я ожидаю. Я просто пытаюсь создать список или вектор с повторениями из каждого столбца.

+0

Код для создания 'dt' в вашем примере не соответствует описанию проблемы. Это только опечатка, но смутила меня изначально, потому что все ответы отличаются от ожидаемого результата. Для ID = 2 числа для '' none ''и' "двадцать" 'меняются. С вашим кодом вы получите для ID = 2 'median (0,0,0,0,0,10,10,20,20)'. – Uwe

+0

@Uwe Хорошо, хорошо поймать. Я попытался исправить это, так что отображаемый материал соответствует примеру ввода. Я сомневаюсь, что OP будет исправлять ошибки, если есть проблемы; они всегда могут отбросить их назад, если мы ошибаемся. – Frank

ответ

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

+0

Хорошая чистая единственная строка кода, которой я пытался достичь. Мне нужно жестко кодировать мои значения, поэтому это наилучшим образом отвечает на вопрос, хотя я также могу видеть, как это было бы удобно, если бы мои значения находились в столбце. – Dan

12

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

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 
3

Вот rowwisedplyr путь:

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 

Вдохновленный @ ответ Арун, это также работает:

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

+0

Я не уверен, нужен ли мне пол или потолок, но вы получите идею ... – Frank

+0

«.SDcols = none: двадцать» отлично. Не знал, что ты можешь это сделать. Кроме того, что такое '.N'? – Bazz

+2

@Bazz Да, этот ярлык для .SDcols - довольно недавнее дополнение. '.N' относится к числу строк в таблице или, если есть предложение' by = '(как в ответе Аруна), это относится к числу строк в группе. – Frank