Je recherche un moyen rapide de remodeler les données du format long au format large. En ce moment, j'ai essayé un code avec des boucles nest for, bien que le travail soit fait, cela prend beaucoup de temps pour générer la sortie.
for (i in 1:lasrow){ sn <- raw_d[i,1] nn <- raw_d[i,2] en <- raw_d[i,3] lc <- 1 if(nn == en){ d[lr,lc]<-sn d[lr,lc+1]<-nn d[lr,lc+2]<-en lr <- lr+1 } else{ while(nn!=en){ d[lr,lc]<-sn lc <- lc+1 next_d <- filter(raw_d,raw_d$SN==sn,raw_d$EN==en) if(dim(next_d)[1]==0){ d[lr,lc]<-"broken bf" lc <- lc+1 break }else{ sn <- next_d$NN nn <- next_d$NN } } d[lr,lc]<-en lr<-lr+1 } }
La sortie attendue est comme ci-dessous
XXX
actuellement, le code ci-dessous fait le travail. Je suis sûr qu'il existe un moyen efficace et propre de le faire.
SN hop1 hop2 hop3 hop4 service_tier A B C economy P Q S R regular H I J K L economy
3 Réponses :
Une option consiste à créer une séquence unique en utilisant rleid
de data.table
, rassembler
le dataframe au format long, supprimer les doublons de chaque groupe, attribuez des noms de colonne et étalez
-les au format large.
library(dplyr) library(tidyr) df %>% mutate(row = data.table::rleid(Service_tier)) %>% gather(key, value, -Service_tier, -row) %>% group_by(row) %>% filter(!duplicated(value)) %>% mutate(key = c("SN", paste0("hop", 1:(n() - 1)))) %>% spread(key, value) %>% ungroup() %>% select(-row) %>% select(SN, starts_with("hop"), Service_tier) # A tibble: 3 x 6 # SN hop1 hop2 hop3 hop4 Service_tier # <chr> <chr> <chr> <chr> <chr> <fct> #1 A B C NA NA economy #2 H I J K L economy #3 P Q S R NA regular
Nous pouvons utiliser data.table
. Convertissez le 'data.frame' en 'dat.table' ( setDT (df1)
, groupé par rleid
sur le 'Service_tier', changez la valeur de 'SN' en premier
élément groupé par 'grp', puis groupé par 'Service_tier', 'SN', obtenez l'élément unique
du sous-ensemble de Data.table et dcast code> du format "long" au format "large"
df1 <- structure(list(SN = c("A", "B", "P", "Q", "S", "H", "I", "J",
"K"), NN = c("B", "C", "Q", "S", "R", "I", "J", "K", "L"), EE = c("C",
"C", "R", "R", "R", "L", "L", "L", "L"), Service_tier = c("economy",
"economy", "regular", "regular", "regular", "economy", "economy",
"economy", "economy")), class = "data.frame", row.names = c(NA,
-9L))
données
library(data.table)
dcast(setDT(df1)[, SN := first(SN), rleid(Service_tier)][,
unique(unlist(.SD)), .(SN, Service_tier)],
SN + Service_tier ~ paste0("hop", rowid(SN)), value.var = "V1", fill = "")
# SN Service_tier hop1 hop2 hop3 hop4
#1: A economy B C
#2: H economy I J K L
#3: P regular Q S R
Le point crucial ici est d'identifier quelles lignes appartiennent à quel groupe. Les réponses de Ronak et akrun les deux utilisent rleid (Service_tier)
en supposant qu'un changement dans Service_tier
indique le début d'un nouveau groupe.
Cela peut être suggéré par l'exemple d'ensemble de données mais ne peut être considéré comme garanti. IMHO, Service_tier
est plutôt un attribut qu'une clé. En fait, l'OP teste NN == EE
dans son extrait de code pour passer à un nouveau groupe.
Dans les solutions data.table ci-dessous, le regroupement est déterminé par cumsum (shift (NN == EE, fill = TRUE))
qui teste l'égalité pour NN
et EE
, retarde le résultat à la ligne suivante où commence le groupe suivant, et énumère les groupes en comptant TRUE
en utilisant cumsum()
.
Dans la version simplifiée (sans remodelage) , les sauts sont agrégés par la fonction toString ()
:
library(data.table) d <- fread("SN NN EE Service_tier A B C economy B C C economy P Q R regular Q S R regular S R R regular H I L economy I J L economy J K L economy K L L economy")
grp SN hop1 hop2 hop3 hop4 Service_tier 1: 1 A B C economy 2: 2 P Q S R regular 3: 3 H I J K L economy
Pour le remodelage du format long au format large, dcast ()
est utilisé:
library(data.table) library(magrittr) # piping used to improve readability w <- setDT(d)[, .(SN = first(SN), hops = NN, Service_tier = first(Service_tier)), by = .(grp = cumsum(shift(NN == EE, fill = TRUE)))] %>% dcast(grp + ... ~ rowid(grp, prefix = "hop"), value.var = "hops", fill = "") %>% setcolorder(c(1:2, 4:ncol(.), 3)) w
grp SN hops Service_tier 1: 1 A B, C economy 2: 2 P Q, S, R regular 3: 3 H I, J, K, L economy
setcolorder ()
est utilisé pour réorganiser les colonnes dans l'ordre attendu par l'OP. Cela se fait sur place , c'est-à-dire sans copier tout l'objet de données.
library(data.table) setDT(d)[, .(SN = first(SN), hops = toString(NN), Service_tier = first(Service_tier)), by = .(grp = cumsum(shift(NN == EE, fill = TRUE)))][]
J'obtiens une erreur ... Erreur dans [.data.frame
(x,. (SN = first (SN), hops = toString (NN), Service_tier = first (Service_tier)), : argument non utilisé (par =. (grp = cumsum (shift (NN == EE, fill = TRUE))))
@VasukiRao Il semble que j'aie oublié de forcer d
à data.table en utilisant setDT (d)
. J'ai modifié le code. S'il vous plaît, plateau à nouveau. Et merci pour le rapport.
lorsque j'exécute le code, erreur dans ncol (w): objet 'w' introuvable
Ma faute. Une autre erreur de copier-coller. Veuillez consulter le code modifié.
super, fonctionne parfaitement, chaque solution intéressante par rapport à la boucle for
Il semble que vos ensembles s'excluent mutuellement, par exemple, regular = {P, Q, R, S} mais P, Q, R et S ne font partie d'aucun autre «ensemble». Cela sera-t-il toujours vrai? "A" pourrait-il jamais faire partie de la régularité et de l'économie? La méthode appropriée pour élargir ces données dépendra de votre réponse.
économie = {P, Q, R, S} peut également apparaître en économie, mais pour une donnée P et S, nous n'aurons qu'un seul chemin et non plusieurs chemins.