11 votes

Le moyen le plus rapide de remodeler les valeurs des variables en colonnes

J'ai un ensemble de données avec environ 3 millions de lignes et la structure suivante :

PatientID| Année | GroupeConditionPrimaire
---------------------------------------
1        | Y1   | TRAUMA
1        | Y1   | GROSSESSE
2        | Y2   | CRISE
3        | Y1   | TRAUMA

Étant assez novice en R, j'ai du mal à trouver la bonne façon de remodeler les données dans la structure décrite ci-dessous :

PatientID| Année | TRAUMA | GROSSESSE | CRISE
----------------------------------------------
1        | Y1   | 1      | 1         | 0
2        | Y2   | 0      | 0         | 1
3        | Y1   | 1      | 0         | 1

Ma question est : Quel est le moyen le plus rapide/le plus élégant de créer un data.frame, où les valeurs de GroupeConditionPrimaire deviennent des colonnes, regroupées par PatientID et Année (en comptant le nombre d'occurrences) ?

12voto

Josh O'Brien Points 68397

Il existe probablement des moyens plus succincts de faire cela, mais pour la vitesse pure, il est difficile de battre une solution basée sur 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() fournit une solution 'base R' qui pourrait ou non être plus idiomatique. (La seule complication est que aggregate renvoie une matrice, plutôt qu'un data.frame ; la deuxième ligne ci-dessous corrige cela.)

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

2nd EDIT Enfin, une solution succincte utilisant le package reshape vous amène au même résultat.

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

1voto

Arun Points 41689

Il existe des méthodes spécifiques rapides melt et dcast implémentées en C dans les versions >=1,9,0. Voici une comparaison avec d'autres excellentes réponses de @Josh sur un jeu de données de 3 millions de lignes (en excluant base:::aggregate car cela prenait beaucoup de temps).

Pour plus d'informations sur l'entrée NEWS, allez ici.

Je suppose que vous avez 1000 patients et un total de 5 ans. Vous pouvez ajuster les variables patients et année en conséquence.

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 est environ 1,6 fois plus rapide que l'agrégation normale en utilisant data.table et 8,8 fois plus rapide que reshape2:::dcast.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X