2016-06-01 34 views
14

Sto provando a calcolare un valore mediano su un numero di colonne, tuttavia i miei dati sono un po 'funky. Sembra il seguente esempio.calcola la mediana dalle colonne data.table in 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 

Nella tabella in colonna rappresenta il numero di occorrenze di tale valore. Sto volendo calcolare l'occorrenza mediana.

Per esempio per ID = 1

median(c(10, 10, 10)) 

è il calcolo Sono voler creare.

per ID = 2

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

Ho provato con rep() e lapply() con un successo molto limitato e sono dopo qualche indicazioni chiare su come questo possa essere raggiunto. Capisco per il Mi piace di rep() Sarebbe dover codice rigido il mio valore da ripetere (ad esempio rep(0,2) o rep(10,2)) e questo è quello che mi aspetto. Sto solo cercando di creare un elenco o un vettore con le ripetizioni di ogni colonna.

+0

Il codice per creare il 'dt' nell'esempio non corrisponde alla descrizione del problema. È solo un refuso ma inizialmente mi ha confuso perché tutte le risposte differiscono dal risultato atteso. Per ID = 2 i numeri per "" none "' e '" twenty "' sono scambiati. Con il tuo codice otterrai ID = 2 'mediano (0,0,0,0,0,10,10,20,20)'. – Uwe

+0

@Uwe Ok, buona cattura. Ho provato a sistemarlo, in modo che la roba visualizzata corrisponda all'ingresso dell'esempio. Dubito che l'OP si preoccupi delle modifiche se ci sono problemi; possono sempre farli rotolare indietro se ci sbagliamo. – Frank

risposta

16

Lei e 'un altro modo data.table (assumendo unico 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 

Questo è solo un tentativo di ottenere la risposta @ di Eddi senza rimodellamento (che io tendo a usare come ultima risorsa).

+0

Nice clean single line of code che è quello che stavo cercando di ottenere. Devo codificare i miei valori in modo che questo risponda meglio alla domanda, anche se posso anche vedere come sarebbe adatto se i miei valori fossero anche in una colonna. – Dan

12

Hai bisogno di un dizionario per tradurre i nomi delle colonne ai numeri corrispondenti, e poi è abbastanza semplice:

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

Ecco un rowwisedplyr modo:

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 

Ispirato @ risposta di Arun, questo funziona anche:

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

Ecco un modo da evitare operazioni per riga e rimodulazione:

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] 

che dà

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 

Per il ciclo, sto prendendo in prestito @alexis_laz' di stile, per esempio https://stackoverflow.com/a/30513197/

Ho saltato la traduzione dei nomi delle colonne, ma è piuttosto semplice. È possibile utilizzare c(0,10,20) anziché names(.SD) alla fine.

+0

Non sono sicuro di aver bisogno di pavimento o soffitto, ma l'idea ... – Frank

+0

'.SDcols = none: twenty' is nifty. Non sapevo che potevi farlo. Inoltre, che cosa è '.N'? – Bazz

+2

@Bazz Sì, quella scorciatoia per .SDcols è un'aggiunta abbastanza recente. '.N' si riferisce al numero di righe nella tabella, o, se c'è una clausola' by = '(come nella risposta di Arun), si riferisce al numero di righe nel per-gruppo. – Frank