2013-03-24 13 views
5

Ich versuche, einen binären Vektor basierend auf der Schnittmenge von zwei data.frames auf mehrere Kriterien zu füllen.R schneiden data.frame auf mehreren Kriterien

Ich habe den Code funktioniert, aber ich fühle, dass es Speicher übermäßig ist, nur um den binären Vektor zu bekommen.

Wenn ich meinen Code auf meine vollständigen Daten (40mm + Zeilen) anwenden. Ich habe Probleme mit dem Gedächtnis.

Gibt es eine einfachere Möglichkeit, den Vektor zu erzeugen?

Hier einige Beispieldaten (zB wird Unter Probe nur obs enthält in voller Probe.):

ob1_1 <- as.data.frame(cbind(c(1999),c("111","222","666","777")),stringsAsFactors=FALSE) 
ob2_1 <- as.data.frame(cbind(c(2000),c("111","333","555","777")),stringsAsFactors=FALSE) 
ob3_1 <- as.data.frame(cbind(c(2001),c("111","222","333","777")),stringsAsFactors=FALSE) 
ob4_1 <- as.data.frame(cbind(c(2002),c("111","444","555","777")),stringsAsFactors=FALSE) 

full_sample <- rbind(ob1_1,ob2_1,ob3_1,ob4_1) 
colnames(full_sample) <- c("yr","ID") 

ob1_2 <- as.data.frame(cbind(c(1999),c("111","222","777")),stringsAsFactors=FALSE) 
ob2_2 <- as.data.frame(cbind(c(2000),c("333")),stringsAsFactors=FALSE) 
ob3_2 <- as.data.frame(cbind(c(2001),c("888")),stringsAsFactors=FALSE) 
ob4_2 <- as.data.frame(cbind(c(2002),c("111","444","555","777")),stringsAsFactors=FALSE) 

sub_sample <- rbind(ob1_2,ob2_2,ob3_2,ob4_2) 
colnames(sub_sample) <- c("yr","ID") 

Hier ist mein Arbeitscode:

q_intersect <- "" 
q_intersect <- paste(q_intersect , "select  a.yr, a.ID  ", sep=" ") 
q_intersect <- paste(q_intersect , "from   full_sample a ", sep=" ") 
q_intersect <- paste(q_intersect , "intersect      ", sep=" ") 
q_intersect <- paste(q_intersect , "select  b.yr, b.ID  ", sep=" ") 
q_intersect <- paste(q_intersect , "from   sub_sample b ", sep=" ") 
q_intersect <- trim(gsub(" {2,}", " ", q_intersect)) 

intersect_temp <- cbind(sqldf(q_intersect),1) 
colnames(intersect_temp) <- c("yr","ID","in_both") 

q_expand <- "" 
q_expand <- paste(q_expand , "select  in_both   ", sep=" ") 
q_expand <- paste(q_expand , "from   full_sample a  ", sep=" ") 
q_expand <- paste(q_expand , "left join intersect_temp b ", sep=" ") 
q_expand <- paste(q_expand , "on   a.yr=b.yr   ", sep=" ") 
q_expand <- paste(q_expand , "and   a.ID=b.ID   ", sep=" ") 
q_expand <- trim(gsub(" {2,}", " ", q_expand)) 

solution <- as.integer(sqldf(q_expand)[,1]) 
solution [is.na(solution)] <- 0 

Dank im Voraus für jeden Hilfe!

+1

sollten Sie erklären, was Sie in natürlicher Sprache wollen. (Der Code, den Sie sagen, arbeitet gerade meine Sitzung von R gesperrt, möglicherweise, weil es keine 'trimmen' Funktion gibt?) Nein, der erste' sqldf' Anruf sperrt es. –

+0

@Dwin, ich hatte gerade das gleiche Lockup-Problem. Aber nur innerhalb der ersten 4 Zeilen des 'q_intersect' Teils. Übrigens, Brad, in deiner vorherigen Frage hast du 'data.table' benutzt und hier benutzt du' dat.frame'. Ist das Absicht? –

+0

@RicardoSaporta Hallo. Habe die Datentabelle einfach getaggt. Sehen Sie sich die Diskussion im Chatroom gestern an, die mich korrigiert hat. Könnte einen größeren untagging Sweep machen. Die SO-Ansicht besagt, dass Tags für Fragen und nicht für Antworten stehen. Mit frischen Augen sehe ich nun und stimme zu, dass die Suche "[data.table] data.table is: question" lautet, wie "[data.table]" alleine aussehen sollte. Es scheint jedoch in Ordnung zu sein (siehe Chat), akzeptierte Antworten mit 'data.table' zu ​​kennzeichnen, wobei auch votes> 10 sind. Um mit data.table nach Antworten zu suchen, können wir "[r] - [data.table] data.table is: answer" verwenden. –

Antwort

4

Es ist nicht ganz klar, was Sie zu erreichen versuchen, aber ich glaube, so etwas wäre viel einfacher.

library(data.table) 
fullDT <- data.table(full_sample, key=c("yr", "ID")) 
subDT <- data.table(sub_sample, key=c("yr", "ID")) 

fullDT[ , intersect := 0L] 
fullDT[subDT, intersect := 1, nomatch=0] 

Die Idee ist, dass Sie die key jeder data.table setzen die Spalten, die Sie schneiden wollen. Wenn Sie full[sub], nomatch=0] aufrufen, erhalten Sie Ihren inneren Join, und wir setzen nur diese Werte auf 1; Die Werte, die nicht in der inneren Verbindung identifiziert werden, bleiben als 0, wie in der vorherigen Zeile festgelegt.

fullDT 
#  yr ID intersect 
# 1: 1999 111   1 
# 2: 1999 222   1 
# 3: 1999 666   0 
# 4: 1999 777   1 
# 5: 2000 111   0 
# 6: 2000 333   1 
# 7: 2000 555   0 
# 8: 2000 777   0 
# 9: 2001 111   0 
# 10: 2001 222   0 
# 11: 2001 333   0 
# 12: 2001 777   0 
# 13: 2002 111   1 
# 14: 2002 444   1 
# 15: 2002 555   1 
# 16: 2002 777   1 
+0

Ricardo, das sieht gut aus. Ich habe data.frames verwendet, um die Beispieldaten zu erstellen, aber ich bevorzuge data.tables, wenn möglich. – Brad

+2

Das ist definitiv viel einfacher als mein Ansatz. Danke nochmal! – Brad

+0

@Brad, überhaupt kein Problem. Ich habe in meinen obigen Ausführungen gefragt, einfach weil es das Problem viel einfacher macht. –

2

Einfachere SQL I sammeln, dass man eine ein Spaltendatenrahmen mit der gleichen Anzahl von Zeilen wie full_sample solche erstellen möchten, dass eine gegebene Zeile in der Ausgabe enthält 1, wenn die entsprechende Zeile in full_sample eine passende hat sub_sample Zeile und 0 andernfalls.

In diesem Fall können die multiplen SQL-Anweisungen zu einer einzigen einfacheren SQL-Anweisung zusammengefasst werden, wie unten gezeigt. Der linke Join stellt sicher, dass alle Zeilen von full_sample enthalten sind und der natürliche Join bewirkt, dass der Join bei allen Spaltennamen auftritt, die zwischen den beiden Eingabedatenrahmen üblich sind.

sqldf("select s.yr is not null as solution 
     from full_sample f natural left join sub_sample s") 

(By the way, beachten Sie, dass Zeichenketten über mehrere Zeilen fließen kann, da dies so zeigt es ist nicht notwendig, mehrere Linien zusammen einzufügen.)

Out of Memory Database sqldf verwendet standardmäßig ein in der Speicherdatenbank, aber Sie können einen Dateinamen angeben (der nicht vor der Zeit bestehen muss) über das Argument dbname=, um als Datenbank des nicht benötigten Speichers zu verwenden. In diesem Fall werden Sie nicht durch das Gedächtnis eingeschränkt.

sqldf("select s.yr is not null as solution 
     from full_sample f natural left join sub_sample s", dbname = "mydb") 

(Sie können auch die Leistung in einigen Fällen verbessern, indem Indizes unter Verwendung finden Sie in der sqldf home page für Beispiele..)

UPDATE: hinzugefügt einfacher SQL-Lösung