2011-11-15 7 views
11

ho un set di dati con circa 3 milioni di righe e la seguente struttura:modo più veloce per rimodellare i valori delle variabili come colonne

PatientID| Year | PrimaryConditionGroup 
--------------------------------------- 
1  | Y1 | TRAUMA 
1  | Y1 | PREGNANCY 
2  | Y2 | SEIZURE 
3  | Y1 | TRAUMA 

Essendo abbastanza nuovo per R, ho qualche difficoltà a trovare il modo giusto per rimodellare i dati nella struttura delineata:

PatientID| Year | TRAUMA | PREGNANCY | SEIZURE 
---------------------------------------------- 
1  | Y1 | 1  | 1   | 0 
2  | Y2 | 0  | 0   | 1 
3  | Y1 | 1  | 0   | 1 

la mia domanda è: Qual è il/modo più veloce più elegante per creare un data.frame, dove i valori di PrimaryConditionGroup diventano colonne, raggruppati per PatientID e Anno (contando il numero di occorrenze)?

risposta

12

Probabilmente ci sono modi più succinta di fare questo, ma per la velocità pura, è difficile da battere una soluzione basata su data.table:

df <- read.table(text="PatientID Year PrimaryConditionGroup 
1   Y1 TRAUMA 
1   Y1 PREGNANCY 
2   Y2 SEIZURE 
3   Y1 TRAUMA", header=T) 

library(data.table) 
dt <- data.table(df, key=c("PatientID", "Year")) 

dt[ , list(TRAUMA = sum(PrimaryConditionGroup=="TRAUMA"), 
      PREGNANCY = sum(PrimaryConditionGroup=="PREGNANCY"), 
      SEIZURE = sum(PrimaryConditionGroup=="SEIZURE")), 
    by = list(PatientID, Year)] 

#  PatientID Year TRAUMA PREGNANCY SEIZURE 
# [1,]   1 Y1  1   1  0 
# [2,]   2 Y2  0   0  1 
# [3,]   3 Y1  1   0  0 

EDIT:aggregate() fornisce una soluzione 'base R' che potrebbero o potrebbe non essere più idiomatico. (L'unica complicazione è che aggregato restituisce una matrice, piuttosto che un data.frame, la seconda riga sottostante correzioni che fino.)

out <- aggregate(PrimaryConditionGroup ~ PatientID + Year, data=df, FUN=table) 
out <- cbind(out[1:2], data.frame(out[3][[1]])) 

2nd EDIT Infine, una soluzione succinta utilizzando il pacchetto reshape si arriva a lo stesso posto.

library(reshape) 
mdf <- melt(df, id=c("PatientID", "Year")) 
cast(PatientID + Year ~ value, data=j, fun.aggregate=length) 
+0

+1 'ddply' non sarà molto meno digitato, davvero, e sarà ovviamente molto più lento. – joran

+1

Perché dovresti anche considerare ddply per questo problema? – hadley

+0

Ciao Josh, grazie, funziona come previsto e funziona bene. Quale sarebbe il modo più sintetico/idiomatico per rimodellare i dati (se le prestazioni non fossero un problema) – Matt

1

Ci sono veloci e meltdcast metodi specifici data.table implementati in C, nelle versioni >=1.9.0. Ecco un confronto con altre risposte eccellenti del post di @ Josh su dati di 3 milioni di righe (escludendo l'aggregato base ::: come richiedeva da un po 'di tempo).

Per ulteriori informazioni sulla voce NEWS, andare here.

Immagino che tu abbia 1000 pazienti e 5 anni in totale. È possibile regolare le variabili patients e year di conseguenza.

require(data.table) ## >= 1.9.0 
require(reshape2) 

set.seed(1L) 
patients = 1000L 
year = 5L 
n = 3e6L 
condn = c("TRAUMA", "PREGNANCY", "SEIZURE") 

# dummy data 
DT <- data.table(PatientID = sample(patients, n, TRUE), 
       Year = sample(year, n, TRUE), 
       PrimaryConditionGroup = sample(condn, n, TRUE)) 

DT_dcast <- function(DT) { 
    dcast.data.table(DT, PatientID ~ Year, fun.aggregate=length) 
} 

reshape2_dcast <- function(DT) { 
    reshape2:::dcast(DT, PatientID ~ Year, fun.aggregate=length) 
} 

DT_raw <- function(DT) { 
    DT[ , list(TRAUMA = sum(PrimaryConditionGroup=="TRAUMA"), 
      PREGNANCY = sum(PrimaryConditionGroup=="PREGNANCY"), 
       SEIZURE = sum(PrimaryConditionGroup=="SEIZURE")), 
    by = list(PatientID, Year)] 
} 

# system.time(.) timed 3 times 
#   Method Time_rep1 Time_rep2 Time_rep3 
#  dcast_DT  0.393  0.399  0.396 
# reshape2_DT  3.784  3.457  3.605 
#   DT_raw  0.647  0.680  0.657 

dcast.data.table è circa 1,6 volte più veloce di aggregazione normale utilizzando data.table e 8.8x più veloce di reshape2:::dcast.

Problemi correlati