2015-06-19 7 views
5

Ho un data.table come:R data.table: sottogruppo per cento ponderato di gruppo

library(data.table) 
widgets <- data.table(serial_no=1:100, 
         color=rep_len(c("red","green","blue","black"),length.out=100), 
         style=rep_len(c("round","pointy","flat"),length.out=100), 
         weight=rep_len(1:5,length.out=100)) 

Anche se io non sono sicuro che questo è il modo più data.table, posso calcolare la frequenza dei sottogruppi per gruppo utilizzando table e length in un singolo passaggio, ad esempio, per rispondere alla domanda "Quale percentuale dei widget rossi è rotonda?"

edit: questo codice non prevede la risposta giusta

# example A 
widgets[, list(style = unique(style), 
       style_pct_of_color_by_count = 
       as.numeric(table(style)/length(style))), by=color] 

# color style style_pct_of_color_by_count 
# 1: red round      0.32 
# 2: red pointy      0.32 
# 3: red flat      0.36 
# 4: green pointy      0.32 
# ... 

ma non posso usare questo approccio per rispondere a domande come "In peso, quale percentuale di widget rossi sono rotondi?" Posso venire solo con un approccio in due fasi:

# example B 
widgets[,list(cs_weight=sum(weight)),by=list(color,style)][,list(style, style_pct_of_color_by_weight=cs_weight/sum(cs_weight)),by=color] 

# color style style_pct_of_color_by_weight 
# 1: red round     0.3466667 
# 2: red pointy     0.3466667 
# 3: red flat     0.3066667 
# 4: green pointy     0.3333333 
# ... 

sto cercando un approccio unico passaggio a B, e A se migliorabile, in una spiegazione che approfondisce la mia comprensione di data.table sintassi per sottoprodotti di origine operazioni di gruppo. Si noti che questa domanda è diversa da Weighted sum of variables by groups with data.table perché la mia implica sottogruppi ed evita più passaggi. TYVM.

+0

Guardando risposta da @Frank seguito ho notato che il mio tentativo A è non solo imbarazzante ma non corretto - per esempio, ho controllato 'widget [, sum (style == "round" & color == "red")/sum (color == "red")] # 0.36' – C8H10N4O2

risposta

7

Questo è quasi un unico passaggio:

# A 
widgets[,{ 
    totwt = .N 
    .SD[,.(frac=.N/totwt),by=style] 
},by=color] 
    # color style frac 
# 1: red round 0.36 
# 2: red pointy 0.32 
# 3: red flat 0.32 
# 4: green pointy 0.36 
# 5: green flat 0.32 
# 6: green round 0.32 
# 7: blue flat 0.36 
# 8: blue round 0.32 
# 9: blue pointy 0.32 
# 10: black round 0.36 
# 11: black pointy 0.32 
# 12: black flat 0.32 

# B 
widgets[,{ 
    totwt = sum(weight) 
    .SD[,.(frac=sum(weight)/totwt),by=style] 
},by=color] 
# color style  frac 
# 1: red round 0.3466667 
# 2: red pointy 0.3466667 
# 3: red flat 0.3066667 
# 4: green pointy 0.3333333 
# 5: green flat 0.3200000 
# 6: green round 0.3466667 
# 7: blue flat 0.3866667 
# 8: blue round 0.2933333 
# 9: blue pointy 0.3200000 
# 10: black round 0.3733333 
# 11: black pointy 0.3333333 
# 12: black flat 0.2933333 

Come funziona: Crea la denominatore per il gruppo di primo livello (color) prima di andare al gruppo più fine (color con style) per catalogare.


Alternative. Se style s ripetizione all'interno di ogni color e questo è solo per scopi di visualizzazione, provare una table:

# A 
widgets[, 
    prop.table(table(color,style),1) 
] 
#  style 
# color flat pointy round 
# black 0.32 0.32 0.36 
# blue 0.36 0.32 0.32 
# green 0.32 0.36 0.32 
# red 0.32 0.32 0.36 

# B 
widgets[,rep(1L,sum(weight)),by=.(color,style)][, 
    prop.table(table(color,style),1) 
] 

#  style 
# color  flat pointy  round 
# black 0.2933333 0.3333333 0.3733333 
# blue 0.3866667 0.3200000 0.2933333 
# green 0.3200000 0.3333333 0.3466667 
# red 0.3066667 0.3466667 0.3466667 

Per B, questo espande i dati in modo che ci sia un'osservazione per ciascuna unità di peso. Con grandi dati, una tale espansione sarebbe una cattiva idea (dal momento che costa così tanta memoria). Inoltre, weight deve essere un numero intero; altrimenti, la sua somma verrà silenziosamente troncata a una (ad esempio, prova rep(1,2.5) # [1] 1 1).

+0

Questo è quello che faccio, ma sarei interessato anche a trovare un modo migliore. – Frank

+1

Grazie a @Frank: mi ci vorrà un po 'di tempo prima che la notazione dei punti e gli incarichi incorporati siano affascinanti, ma questo è un ottimo approccio. – C8H10N4O2

+1

La prima versione può essere riscritta senza variabile temp come segue: 'widget [,. (Frac = .SD [, .N, per = stile] $ N/.N), per = colore]' – Arun

0

Può essere una buona idea di utilizzare dplyr

df <- widgets %>% 
    group_by(color, style) %>% 
    summarise(count = n()) %>% 
    mutate(freq = count/sum(count)) 

df2 <- widgets %>% 
    group_by(color, style) %>% 
    summarise(count_w = sum(weight)) %>% 
    mutate(freq = count_w/sum(count_w)) 
+0

Grazie @ drsh1 apprezzo che 'dplyr' sia intuitivo e utile qui. La mia domanda specifica era come usare la sintassi 'data.table'. – C8H10N4O2