2017-09-07 2 views
3

Ich habe an vielen neuen Projekten gearbeitet, in denen ich viel ungewohnte Datenvorbereitung und -verwaltung mache.lapply - Erstellen neuer Variablen, basierend auf aktuellen Variablen, bedingt basierend auf Informationen im 2. Datenrahmen

Ich habe zwei Datenrahmen: 1) das ist sehr groß mit Tausenden von Beobachtungen und Variablen (df1), und 2) ein Datenrahmen, der Bereiche der Sammlung Jahre für eine Teilmenge der Variablen in df1 (df2) auflistet. Ich muss eine neue Variable in df1 für eine große Teilmenge von Variablen/Spalten in df1 erstellen. Die neuen Variablen, die für df1 erstellt wurden, prüfen, ob ein Wert vorhanden ist (1), ein Wert für ein Jahr, das gesammelt wurde (0), oder ein Wert nicht vorhanden ist und das Jahr außerhalb des aufgelisteten Erfassungsbereichs liegt in df2 ("NA").

Ich habe ein paar Tage damit verbracht, eine Tonne zu lesen, aber ich kann keinen finden, der meine Bedürfnisse anspricht oder sich mit Art von Komplexität befasst, so dass ich das nicht mit roher Gewalt machen muss.

Hier ist mein tragfähige Ausgangsdatenrahmen:

grp <- c('a', 'a', 'a', 'b', 'b') 
year <- c(1991, 1992, 1993, 2005, 2010) 
v1 <- c(20.5, 30.5, 29.6, 28.7, 26.1) 
v2 <- c(100.0, 101.5, 105.1, 'NA', 95.0) 
v3 <- c(47.2, 'NA', 'NA', 'NA', 'NA') 
df1 <- data.frame(grp = grp, year = year, v1 = v1, v2 = v2, v3 = v3) 
df1 

grp year v1 v2 v3 
a 1991 20.5 100 47.2 
a 1992 30.5 101.5 NA 
a 1993 29.6 105.1 NA 
b 2005 28.7 NA NA 
b 2010 26.1 95 NA 

hier mit Bedeckungen für Variablen in df1 mein Referenzdatenrahmen:

vars <- c('v1', 'v2', 'v3') 
start <- c(1989, 2004, 1980) 
end <- c(2015, 2011, 1994) 
df2 <- data.frame(vars = vars, start = start, end = end) 
df2 

vars start end 
v1 1989 2015 
v2 2004 2011 
v3 1980 1994 

Ich habe mit ‚lapply mit einfachen Sachen zu lernen() 'wie:

Ich schrieb in R, was ich denke, sind die Arten von Bedingungen tha t müssen erfüllt werden. Ich werde mit geschriebenem Englisch erzählen:

  1. ein Wert für ein Jahr vorhanden ist, die gesammelt wurde (1)

    if (!is.na(x)) { x <- 1 } 
    
  2. ein Wert ist für ein Jahr nicht vorhanden, die in dem Bereich fällt aufgeführt in DF2 (0)

    if (is.na(x) & year %in% seq(df2$start[df2$vars == names(df1[x]), ], df2$end[df2$vars == names(df1[x]), ], 1)) { x <- 0 } 
    
  3. ein Wert nicht vorhanden ist und das Jahr fällt außerhalb des Sammelbereichs in DF2 aufgeführt ('NA')

    if (is.na(x) & !(year %in% seq(df2$start[df2$vars == names(df1[x]), ], df2$end[df2$vars == names(df1[x]), ], 1))) { x <- 'NA' } 
    

Ich habe mein Bestes mit der Syntax und Indizierung, aber wir schnell aus meiner Komfortzone zu bekommen.

Nach dem Ausführen sollte die bedingten prüft die gewünschte Ausgabe/modifizierte df1 wie folgt aussehen:

grp year v1 v2 v3 v1.cov v2.cov v3.cov 
    a 1991 20.5 100 47.2  1  1  1 
    a 1992 30.5 101.5 NA  1  1  0 
    a 1993 29.6 105.1 NA  1  1  0 
    b 2005 28.7 NA NA  1  0  NA 
    b 2010 26.1 95 NA  1  1  NA 

ich auf eine Vielzahl von Lösungen offen bin, aber dies schien den wahrscheinlichen Weg durch zu bewegen. Danke nochmal für die Hilfe. Ich bin ein erfahrener R-Modellierer/Wissenschaftler, aber ich habe so viel Datenvorbereitung, "data.table" und "dplyr" im letzten Monat mit all Ihrer Hilfe gelernt.

+0

Verwenden Sie "NA", nicht "NA", was nur eine Zeichenfolge ist. – Frank

Antwort

2

Mit data.table:

library(data.table) 
setDT(df1) 
DT = melt(df1, id = c("grp", "year"), meas = patterns("^v"))[, value := type.convert(as.character(value))] 

# mark based on whether found or not within collection periods 
DT[df2, on=.(variable = vars, year >= start, year <= end), 
    found := as.integer(!is.na(value))] 

# also mark if found outside collection periods 
DT[!is.na(value) & is.na(found), found := 1L ] 

die gibt

grp year variable value found 
1: a 1991  v1 20.5  1 
2: a 1992  v1 30.5  1 
3: a 1993  v1 29.6  1 
4: b 2005  v1 28.7  1 
5: b 2010  v1 26.1  1 
6: a 1991  v2 100.0  1 
7: a 1992  v2 101.5  1 
8: a 1993  v2 105.1  1 
9: b 2005  v2 NA  0 
10: b 2010  v2 95.0  1 
11: a 1991  v3 47.2  1 
12: a 1992  v3 NA  0 
13: a 1993  v3 NA  0 
14: b 2005  v3 NA NA 
15: b 2010  v3 NA NA 

(type.convert wird verwendet, mit String 'NA' OPs Codierung von fehlenden Daten zu überschreiben.

)

Der melt Schritt macht hier nur Sinn, weil die Variablen scheinen vom gleichen Typ zu sein (numerisch). Wenn dies nicht der Fall ist, kann etwas Ähnliches durchgeführt werden, indem jede Spalte durchlaufen wird:

setDT(df1) 
setDT(df2) 
for (v in unique(df2$vars)){ 
    df1[, (v) := type.convert(as.character(get(v)))] 

    fcol = paste0("found.",v) 
    df1[df2[vars == v], on=.(year >= start, year <= end), 
    (fcol) := as.integer(!is.na(get(v)))] 
    df1[!is.na(get(v)) & is.na(get(fcol)), (fcol) := 1L ] 
} 

    grp year v1 v2 v3 found.v1 found.v2 found.v3 
1: a 1991 20.5 100.0 47.2  1  1  1 
2: a 1992 30.5 101.5 NA  1  1  0 
3: a 1993 29.6 105.1 NA  1  1  0 
4: b 2005 28.7 NA NA  1  0  NA 
5: b 2010 26.1 95.0 NA  1  1  NA 
+1

Super, ich werde das überprüfen, wenn ich zurückkomme. Die Variablen werden fast alle kontinuierlich sein, so wird dies in Ordnung sein. Alles, was ich von Hand machen kann. Ich weiß das wirklich zu schätzen, und ich werde später mit dem ganzen Set nachsehen. –

+1

Das hat am skalierten Datensatz perfekt funktioniert; müssen Sie einfach einholen und verstehen, dass für Schleife ein wenig besser. Vielen Dank. –

Verwandte Themen