2016-07-20 7 views
-1

Ich habe eine data.frame mit 32.000 Einträgen. Hier ist ein Beispiel:Zuweisen einer 1 oder 0 bedingt zu einer neuen Spalte basierend auf Werten von einem anderen Datenrahmen in R

# df1 
MINEVENT MAXEVENT  EVENTRANGE NUMEVENT cplt_flag 
2680001 2680051 2680001-2680051  51   0 
2680001 2680051 2680001-2680051  51   0 
2680001 2680051 2680001-2680051  51   0 
2680001 2680051 2680001-2680051  51   0 
2680001 2680051 2680001-2680051  51   0 
2680001 2680051 2680001-2680051  51   0 

und ein weiteres mit einer Liste von 157 Werten. Hier ist ein Beispiel:

# df2 
source_id 
    211535 
    211535 
    211535 
    211536 
    211536 
    211536 

ich von der source_id lesen möchten und prüfen, ob der Wert fällt zwischen MINEVENT und MAXEVENT. Wenn TRUE dann möchte ich einen Wert 1 in cplt_flag, sonst 0 eingeben.

Ich habe einen Code mit if-else Anweisungen, aber es läuft super langsam für die 32,000 Einträge. Ich habe auch versucht, Funktionen zu verwenden und Funktionen anzuwenden, aber das kann nicht funktionieren.

Ich bin auf der Suche nach einem effizienten Weg, um dies zu tun.

+1

@Arun die magische Kraft des r-Gold-Abzeichen ;-) – RHertel

Antwort

2

Ihr Datensatz enthält nicht wirklich Fälle, in denen es ein TRUE Szenario gibt. Aber hier ist eine Lösung mit der neuen nicht-Equi-Joins-Funktion aus der aktuellen Entwicklungsversion von data.table, v1.9.7. Siehe Installationsanweisungen here.

require(data.table) #v1.9.7+ 

setDT(df2) 
setDT(df1)[df2, cplt_flag := 1, on = .(MINEVENT <= source_id, MAXEVENT >= source_id)] 

Für jede Zeile in df2, Zeilenindizes von df1 entsprechen, werden extrahiert, wo das Argument zu on= vorgesehen Bedingung erfüllt ist. Und auf diesen Zeilenindizes wird cplt_flagvor Ort mit 1 aktualisiert.

0

Eine alternative Lösung, die eine match.criterion Funktion und eine der Funktionen verwendet, die schneller als Schleife sein sollten, sind. Ich habe einige zusätzliche Datenzeilen-Test (nicht erschöpfend, sondern veranschaulichend) hinzugefügt:

df1 <- read.table(text = " 
        MINEVENT MAXEVENT  EVENTRANGE NUMEVENT cplt_flag 
        211535 211634 211535-211634  100   0 
        2680001 2680051 2680001-2680051  51   0 
        2680001 2680051 2680001-2680051  51   0 
        2680001 2680051 2680001-2680051  51   0 
        2680001 2680051 2680001-2680051  51   0 
        2680001 2680051 2680001-2680051  51   0 
        2680001 2680051 2680001-2680051  51   0 
        2680101 2680151 2680101-2680151  51   0", header = TRUE) 

df2 <- read.table(text = " 
        source_id 
        211535 
        211535 
        211535 
        211536 
        211536 
        211536 
        2680051", header = TRUE) 

match.criterion <- function(source.id, df1) { 
    matches <- which(df1$MINEVENT <= source.id & source.id <= df1$MAXEVENT) 
    df1$cplt_flag[matches] <<- 1 
} 

sapply(df2$source_id, match.criterion, df1 = df1) 
print(df1) 
## MINEVENT MAXEVENT  EVENTRANGE NUMEVENT cplt_flag 
##1 211535 211634 211535-211634  100   1 
##2 2680001 2680051 2680001-2680051  51   1 
##3 2680001 2680051 2680001-2680051  51   1 
##4 2680001 2680051 2680001-2680051  51   1 
##5 2680001 2680051 2680001-2680051  51   1 
##6 2680001 2680051 2680001-2680051  51   1 
##7 2680001 2680051 2680001-2680051  51   1 
##8 2680101 2680151 2680101-2680151  51   0 

Hinweise:

  1. Der Schlüssel hier ist R's scoping rule zu verstehen. Um eine Variable außerhalb des Funktionsumfangs zu ändern, verwenden Sie <<- anstelle von <-. Eine Erläuterung finden Sie unter this, und beachten Sie die Warnhinweise zur Verwendung von <<-.

  2. Dies setzt voraus, dass df1$cplt_flag zunächst alle Nullen als match.criterion ist setzt nur die Zeilen, die auf 1 entsprechen. Das heißt, die Zeilen von df1, die nicht mit dem Kriterium für jeden Wert von source_id übereinstimmen, bleiben übrig.

Noch eine andere Lösung, die Vektorisierung foreach anstelle eines der Funktionen anwenden verwendet, ist:

require(foreach) 
foreach(source.id = df2$source_id) %do% match.criterion(source.id, df1) 
Verwandte Themen