calculer la médiane à partir de données.colonnes du tableau en R

j'essaie de calculer une valeur médiane à travers un certain nombre de colonnes, cependant mes données sont un peu funky. Il ressemble à l'exemple suivant.

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

Dans le tableau de la colonne représente le nombre d'occurrences de cette valeur. Je veux calculer l'occurrence médiane.

par exemple pour ID = 1

median(c(10, 10, 10))

est le calcul que je veux faire.

ID = 2

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

j'ai essayé d'utiliser rep() et lapply() avec un succès très limité et je suis après quelques directives claires sur la façon dont cela pourrait être réalisé. Je comprends pour les goûts de rep() je serais d'avoir à coder en dur ma valeur à être répétée (par exemple,rep(0,2) ou rep(10,2)) et c'est ce que j'attends. Je suis juste mal pour créer une liste ou un vecteur avec les répétitions de chaque colonne.

14
demandé sur Frank 2016-06-02 00:48:36

4 réponses

en voici un autre data.table chemin (en supposant 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

c'est juste une tentative pour obtenir la réponse de @eddi sans remodeler (que j'ai tendance à utiliser en dernier recours).

16
répondu Arun 2016-06-01 22:43:35

Vous avez besoin d'un dictionnaire pour traduire les noms de colonnes en nombres correspondants, et puis c'est assez simple:

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
12
répondu eddi 2016-06-01 21:55:37

voici un moyen d'éviter les opérations de contournement et le remodelage:

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]

ce qui donne

   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

Pour la boucle, je suis d'emprunt @alexis_laz style, par exemple,https://stackoverflow.com/a/30513197/

j'ai sauté la traduction des noms de colonne, mais c'est assez simple. Vous pouvez utiliser c(0,10,20) au lieu de names(.SD) à la fin.

6
répondu Frank 2017-05-23 12:16:59

Voici un 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

inspiré par la réponse de @Arun, cela fonctionne aussi:

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
3
répondu Psidom 2016-06-01 23:21:22