2015-03-05 10 views
10

Ho un data.table su cui vorrei eseguire operazioni di gruppo, ma vorrei conservare le variabili nulle e utilizzare diversi gruppi di variabili di gruppo.Operazioni tabella dati con gruppo multiplo per set di variabili

Un esempio giocattolo:

library(data.table) 
set.seed(1) 
DT <- data.table(
     id = sample(c("US", "Other"), 25, replace = TRUE), 
     loc = sample(LETTERS[1:5], 25, replace = TRUE), 
     index = runif(25) 
     ) 

Mi piacerebbe trovare la somma di index da tutte le combinazioni di variabili chiave (tra cui il set null). Il concetto è analogo a "set di raggruppamenti" di Oracle SQL, ecco un esempio della mia soluzione attuale:

rbind(
    DT[, list(id = "", loc = "", sindex = sum(index)), by = NULL], 
    DT[, list(loc = "", sindex = sum(index)), by = "id"], 
    DT[, list(id = "", sindex = sum(index)), by = "loc"], 
    DT[, list(sindex = sum(index)), by = c("id", "loc")] 
)[order(id, loc)] 
     id loc  sindex 
1:   11.54218399 
2:   A 2.82172063 
3:   B 0.98639578 
4:   C 2.89149433 
5:   D 3.93292900 
6:   E 0.90964424 
7: Other  6.19514146 
8: Other A 1.12107080 
9: Other B 0.43809711 
10: Other C 2.80724742 
11: Other D 1.58392886 
12: Other E 0.24479728 
13: US  5.34704253 
14: US A 1.70064983 
15: US B 0.54829867 
16: US C 0.08424691 
17: US D 2.34900015 
18: US E 0.66484697 

Esiste un modo preferito "tabella dei dati" per raggiungere questo obiettivo?

+2

Se vuoi veramente i risultati in un 'data.table', quello che fai qui va bene. Se stai solo andando a guardare i risultati, un formato tabellare, con le tue variabili per la classificazione incrociata ai margini, è molto meglio: 'stable <- tapply (DT $ index, list (DT $ id, DT $ loc) ,somma); mstable <- rbind (cbind (stabile, applica (stabile, 1, somma)), c (applica (stabile, 2, somma), somma (stabile))) '. A proposito, si prega di utilizzare 'set.seed' quando si generano dati casuali per un esempio. – Frank

+0

Oh, in realtà è più semplice di così, dato che 'addmargins' funziona:' addmargins (stable) ' – Frank

+1

[Oracle GROUPING SETS] (https://oracle-base.com/articles/misc/rollup-cube-grouping-functions- e-grouping-set # grouping_sets) potrebbe essere fatto da un data.table funzioni di alto livello, non richiesto internals, simile a quello che hai fatto. Raccomando di riempire una richiesta di funzionalità per quella funzione. – jangorecki

risposta

0

partire dal this commit, ora è possibile con la versione dev di data.table con cube o groupingsets:

library("data.table") 
# data.table 1.10.5 IN DEVELOPMENT built 2017-08-08 18:31:51 UTC 
# The fastest way to learn (by data.table authors): https://www.datacamp.com/courses/data-analysis-the-data-table-way 
# Documentation: ?data.table, example(data.table) and browseVignettes("data.table") 
# Release notes, videos and slides: http://r-datatable.com 

cube(DT, list(sindex = sum(index)), by = c("id", "loc")) 
#  id loc  sindex 
# 1: US B 0.54829867 
# 2: US A 1.70064983 
# 3: Other B 0.43809711 
# 4: Other E 0.24479728 
# 5: Other C 2.80724742 
# 6: Other A 1.12107080 
# 7: US E 0.66484697 
# 8: US D 2.34900015 
# 9: Other D 1.58392886 
# 10: US C 0.08424691 
# 11: NA B 0.98639578 
# 12: NA A 2.82172063 
# 13: NA E 0.90964424 
# 14: NA C 2.89149433 
# 15: NA D 3.93292900 
# 16: US NA 5.34704253 
# 17: Other NA 6.19514146 
# 18: NA NA 11.54218399 

groupingsets(DT, j = list(sindex = sum(index)), by = c("id", "loc"), sets = list(character(), "id", "loc", c("id", "loc"))) 
#  id loc  sindex 
# 1: NA NA 11.54218399 
# 2: US NA 5.34704253 
# 3: Other NA 6.19514146 
# 4: NA B 0.98639578 
# 5: NA A 2.82172063 
# 6: NA E 0.90964424 
# 7: NA C 2.89149433 
# 8: NA D 3.93292900 
# 9: US B 0.54829867 
# 10: US A 1.70064983 
# 11: Other B 0.43809711 
# 12: Other E 0.24479728 
# 13: Other C 2.80724742 
# 14: Other A 1.12107080 
# 15: US E 0.66484697 
# 16: US D 2.34900015 
# 17: Other D 1.58392886 
# 18: US C 0.08424691 
+0

Mille grazie a @jangorecki per aver inserito questa correzione! – mlegge

-1

utilizzando dplyr, un adattamento di questo dovrebbe funzionare, se ho capito la tua domanda correttamente.

sum <- mtcars %>% 
    group_by(vs, am) %>% 
    summarise(Sum=sum(mpg)) 

Non ho controllare modo in cui tratta i valori missung però, ma dovrebbe solo fare un altro gruppo di loro (ultimo gruppo).

0

Ho una funzione generica che è possibile alimentare in un dataframe e un vettore di dimensioni che si desidera raggruppare, e restituirà la somma di tutti i campi numerici raggruppati per tali dimensioni.

rollSum = function(input, dimensions){ 
    #cast dimension inputs to character in case a dimension input is numeric 
    for (x in 1:length(dimensions)){ 
     input[[eval(dimensions[x])]] = as.character(input[[eval(dimensions[x])]]) 
    } 
    numericColumns = which(lapply(input,class) %in% c("integer", "numeric")) 
    output = input[,lapply(.SD, sum, na.rm = TRUE), by = eval(dimensions), 
    .SDcols = numericColumns] 
    return(output) 
} 

Così allora si può creare una lista del vostro gruppo diverso da vettori:

groupings = list(c("id"),c("loc"),c("id","loc")) 

e poi usarlo con lapply e rbindlist in termini di:

groupedSets = rbindlist(lapply(groupings, function(x){ 
    return(rollSum(DT,x))}), fill = TRUE) 
Problemi correlati