2017-11-29 3 views
0

ich einen Datenrahmen wie diese:umformen breit zu lange mit Kontrollvektor

df <- data.frame(v11=rnorm(1), v12=rnorm(1), v21=rnorm(1), v31=rnorm(1), v41=rnorm(1), v42=rnorm(1), v43=rnorm(1)) 

dieser Datenrahmen hat nur eine Zeile

df 
#   v11  v12  v21  v31  v41  v42  v43 
# 1 -0.4425873 0.6062714 -0.3816921 0.2477926 0.1292103 0.2801346 0.4290997 

Einige Spalten Beobachtungen für das gleiche Thema wiederholt werden, für Beispiel v11 und v12 sind zwei Beobachtungen aus dem gleichen Thema. v21 und v32 sind nur einzelne Beobachtungen. v4x hat drei Beobachtungen.

Ich möchte den Datenrahmen neu zu gestalten wie folgt aussehen:

v11 v21 v31 v41 
v12 NA NA v42 
NA NA NA v43 

Beachten Sie, dass sie die Werte der Variablen nicht ihre Namen enthalten sollte.

Ich habe einen Indikator Vektor, der Marken, die Beobachtung ist, was:

v <- c(1, 2, 1, 1, 1, 2, 3) 

Jede „1“ den Beginn einer neuen Spalte markiert.

Meine erste Idee war jede Zeile auf seine eigene bauen:

row1 <- df[, v == 1] 
row2 <- df[, v == 2] 
row3 <- df[, v == 3] 

aber enthält nicht die nationalen Agenturen. Es muss einen einfacheren Weg geben.

Hinweis: Eine Lösung sollte nicht v11 auf den ursprünglichen Spaltennamen abhängen müssen, v41, etc, aber nur auf dem Vektor v.

+0

Es ist nichts unklar über diese Frage. – Alex

Antwort

2

Hier ist eine Lösung mit dplyr + tidyr:

library(dplyr) 
library(tidyr) 

v <- c(1,2,1,1,1,2,3) 

df %>% 
    gather(var, value) %>% 
    mutate(row_num = v, 
     col_num = paste0("v", cumsum(v==1))) %>% 
    select(-var) %>% 
    spread(col_num, value) 

Ergebnis:

row_num   v1  v2   v3  v4 
1  1 -0.5604756 1.558708 0.07050839 0.1292877 
2  2 -0.2301775  NA   NA 1.7150650 
3  3   NA  NA   NA 0.4609162 

Daten:

df = structure(list(v11 = -0.560475646552213, v12 = -0.23017748948328, 
    v21 = 1.55870831414912, v32 = 0.070508391424576, v41 = 0.129287735160946, 
    v42 = 1.71506498688328, v43 = 0.460916205989202), .Names = c("v11", 
"v12", "v21", "v32", "v41", "v42", "v43"), row.names = c(NA, 
-1L), class = "data.frame") 
+0

danke, aber es ist verallgemeinerbar? In meinem realen Datensatz sind die Variablennamen völlig verschieden und haben keine Endungen, die anzeigen, welche Beobachtungen sie sind. Es ist nur in dem Vektor 'v' – spore234

+1

@ spore234 Ohne die Variablennamen, wie sonst würden Sie wissen, welche Spalte/Zeile ein Element sein sollte? Ich dachte, die Prämisse Ihrer Frage ist, dass Sie diese konsistenten Variablennamen haben. Nehmen wir zum Beispiel an, dass Ihre Variablennamen jetzt von "a" bis "g" sind. Wie sollen Sie wissen, dass "a" und "b" in Spalte 1 stehen? – useR

+0

Sie haben Recht, ich habe einen Fehler in meinem Beispiel gemacht. Die erste Zeile ist immer vollständig. Jede neue "1" zeigt also den Beginn einer neuen Spalte an. – spore234

0

Sie auch dieses wi tun könnte th melt und dcast von reshape2 und transform:

library(reshape2) 
dcast(transform(melt(df), 
       rownum = substr(variable,3,3), 
       cols = substr(variable,1,2)), 
     rownum ~ cols, value.var = 'value') 

Das Ergebnis:

rownum   v1  v2  v3   v4 
1  1 1.43420148 0.7391372 -1.758605 -0.06982523 
2  2 -0.07729196  NA  NA 0.45190553 
3  3   NA  NA  NA -1.95836646 

Daten:

set.seed(2017) 
df <- data.frame(v11=rnorm(1), v12=rnorm(1), v21=rnorm(1), v31=rnorm(1), v41=rnorm(1), v42=rnorm(1), v43=rnorm(1)) 
+0

Dies ist ähnlich meiner ursprünglichen Antwort, aber OP erwähnt, dass die Umformung sollte nicht auf den ursprünglichen Spaltennamen basieren, sondern nur auf dem Indikator Vektor 'v' zur Verfügung gestellt. – useR

0

Dies ist eine Lösung in der Basis R, und nur auf dem Vektor hängt v das gruppiert die Messdaten:

Zuerst Beispieldaten:

set.seed(0) 
df <- data.frame(v11=rnorm(1), v12=rnorm(1), v21=rnorm(1), v31=rnorm(1), v41=rnorm(1), v42=rnorm(1), v43=rnorm(1)) 

#  v11  v12  v21  v31  v41  v42  v43 
#1 1.262954 -0.3262334 1.329799 1.272429 0.4146414 -1.53995 -0.928567 


v <- c(1,2,1,1,1,2,3) 

Dann tun:

v_grp <- cumsum(v == 1) # create index that groups the measurement data 

out <- split(unlist(df), v_grp) # split vector of measurements by group 

## following required to pad split vectors with `NA`. 
## There are packages that give functions that do this 

max_in_group <- max(summary(factor(v_grp)))  
out <- lapply(out, function(v) { 
    num_in_vec <- length(v) 
    if (num_in_vec < max_in_group) { 
     v <- c(v, rep(NA, max_in_group - num_in_vec)) 
    } 
    return(unname(v)) 
}) 


out <- do.call(cbind, out) 

out 
#    1  2  3   4 
# v11 1.2629543 1.329799 1.272429 0.4146414 
# v12 -0.3262334  NA  NA -1.5399500 
#    NA  NA  NA -0.9285670 
+0

Das funktioniert, und ist schneller als der "tidyr" Ansatz, aber scheint wie Overkill! – A5C1D2H2I1M1N2O1R2T1

0

Dies ist ein perfektes Beispiel ist Matrix Indizierung für die Verwendung, wie Sie bereits Ihre Zeilenindizes haben.

Hier ist, wie es getan werden kann:

M <- matrix(NA, nrow = max(v), ncol = sum(v == 1)) 
M[cbind(v, cumsum(v == 1))] <- unlist(df, use.names = FALSE) 
M 
#   [,1]  [,2]  [,3]  [,4] 
# [1,] -0.5604756 1.558708 0.07050839 0.1292877 
# [2,] -0.2301775  NA   NA 1.7150650 
# [3,]   NA  NA   NA 0.4609162 

Im Wesentlichen Sie beginnen mit einem matrix mit NA Werten gefüllt erstellen, dann verwenden Sie „v“ (Ihre Zeilenindizes) Ihre Spaltenindizes zu erstellen und , Teilmenge in dieser Matrix, und ersetze die Werte durch die nicht aufgelisteten Werte von "df".


df in dieser Antwort ist von Antwort des Nutzers.

Verwandte Themen