2017-01-19 2 views
2

Das ProblemR: For-Schleife zu lange

Ich habe einen Datensatz mit 3 Variablen: ein ID-Variable, eine Zeitvariable und eine numerische Variable X, die nur im Datensatz dargestellt wird, wenn es anders ist Null wie in der folgenden Tabelle.

time ID X 
238 2007 A 28 
239 2008 A 80 
240 2014 A 178 
241 2012 B 88 
242 2011 C 369 
243 2003 D 28 
244 2004 D 80 

Ich mag für jede ID in einem einzigartigen Datenrahmen mit einem lign haben und jedes Jahr zwischen 2001 und 2016 mit X = 0, wenn necesary. So wäre es eine Tabelle wie die folgenden sein:

time ID X 
1 2001 A 0 
2 2002 A 0 

7 2007 A 28 
8 2008 A 80 

14 2014 A 178 
17 2001 B 0 
7 2012 B 88 

ich gefunden habe keine Möglichkeit, es in der R Dokumentation zu tun, oder in diesem Forum

Wie ich vorgehen

zu lösen dieses Problem, ich hatte die Idee, in drei Schritten vorgehen:

1) I für jede ID-Nummer nur eine Zeile zu halten, egal welche Jahreszeit es ist

data2 = data%>%group_by(ID,X)%>%distinct(.keep_all = T) 

, die der folgenden Tabelle führen:

time ID X 
238 2007 A 28 
241 2012 B 88 
242 2011 C 369 
243 2003 D 28 

2) Dann duplizieren ich jede Zeile Beobachtung für jedes Jahr für jede ID

timebis = seq(from = 2001, to = 2016, by = 1) 
dupl.data2 = data2[rep(1:nrow(data1), each=length(timebis)), ] 
dupl.data1$X = 0 

Ich habe jetzt 16 Beobachtungen zu haben.

3) Füllen Sie die dupl.data1 $ X-Säule mit einem Doppel for-Schleife

i=1 
j=1 
for(i in 1:length(dupl.data2$ID)){ 
    for(j in 1:length(data$ID)){ 
    if (dupl.data2$timebis[i]==data$time[j] & dupl.data2$ID[i]==data$ID[j]) 
     {dupl.data2$X[i]=data$X[j]} 
    j=j+1 
} 
    j=1 
    i=i+1 
} 

Fazit

Es funktioniert gut auf kleine Teilproben, aber meine ursprüngliche Datenbank hat etwa 300 000 Beobachtungen und der Datensatz mit Nullen ist viel größer. Ich müsste meine Codeeffizienz oder Ideen verbessern, um dieses Problem zu lösen.

Dank

+0

So etwas wie 'newDf <- fusionieren (df, expand.grid (id = eindeutige (df $ id), year = 2001: 2014), durch = c ("id", "Jahr"), die alle = WAHR); df $ X [is.na (df $ X)] <- 0' wird funktionieren. – lmo

+0

mit data.table, 'merge (setDT (data), setnames (data [, seq (2001, 2016), mit = data $ ID], c (" ID "," time ")), all = TRUE)' . Alles was getan werden muss, ist fehlende ersetzen. – user2957945

Antwort

2

expand alle Kombinationen von ID und Jahr zu erhalten. Dann left_join das Ergebnis auf dem Datenrahmen erneut, um die x-Werte zu erhalten.

require(dplyr) 
require(tidyr) 
df <- data.frame(time = sample(2001:2012,12,replace = F), 
       ID = sample(LETTERS[1:3],12, replace =T), 
       x = sample(10:50,12)) 


df %>% 
    expand(time,ID) %>% 
    left_join(df, c('time','ID')) %>% 
    mutate(x = ifelse(is.na(x),0,x)) 

Ergebnis:

# A tibble: 36 × 3 
time  ID  x 
<int> <fctr> <dbl> 
2001  A  0 
2001  B 39 
2001  C  0 
2002  A  0 
2002  B  0 
2002  C 24 
2003  A 35 
2003  B  0 
2003  C  0 
2004  A 47 
# ... with 26 more rows 

Wenn nicht alle Jahre in Ihrem Datenrahmen aus irgendeinem Grund sind, können Sie mit benutzerdefinierten Werten verwenden erweitern.

df %>% 
    expand(time = 2001:2012,ID) %>% 
    left_join(df, c('time','ID')) %>% 
    mutate(x = ifelse(is.na(x),0,x)) 
+1

Sie und das OP müssen beide Pakete erklären, die Sie verwenden, vorzugsweise mit einigen 'library()' Befehlen.Außerdem ist es verwirrend, dass Sie sich auf "Expand" beziehen und dann "expand" verwenden. Fyi, 'replace (x, cond, 0)' sollte äquivalent zu 'ifelse (cond, 0, x)' sein, vielleicht vorzuziehen für die Lesbarkeit und weil ifelse einen schlechten Ruf für Effizienz hat. Alternativ hat dplyr einige if_else-Funktionen. – Frank