R: Wie man zwei riesige Datenrahmen gibt, ohne den Speicher auszulaufen
-
16-10-2019 - |
Frage
Ich habe zwei Datenrahmen df1
und df2
Das hat jeweils rund 10 Millionen Zeilen und 4 Säulen. Ich las sie mit Rodbc/sqlQuery ohne Probleme in R ein, aber wenn ich es versuche, versuche ich es rbind
Ich bekomme das am meisten gefürchtete R -Fehlermeldungen: cannot allocate memory
. Es muss effizientere Möglichkeiten geben, eine zu tun rbind
Effizienter - hat jemand seine Lieblingstricks dazu, die er teilen möchte? Zum Beispiel fand ich dieses Beispiel im DOC für sqldf
:
# rbind
a7r <- rbind(a5r, a6r)
a7s <- sqldf("select * from a5s union all select * from a6s")
Ist das der beste/empfohlene Weg, dies zu tun?
AKTUALISIERENIch habe es mit dem entscheidenden zum Laufen gebracht dbname = tempfile()
Argument in der sqldf
Rufen Sie oben an, wie JD Long in seiner Antwort darauf vorschlägt diese Frage
Lösung
Anstatt sie am Anfang in R zu lesen und sie dann zu kombinieren, könnten Sie SQLite lesen lassen und kombinieren, bevor Sie sie an R senden, auf diese Weise werden die Dateien niemals individuell in R geladen.
# create two sample files
DF1 <- data.frame(A = 1:2, B = 2:3)
write.table(DF1, "data1.dat", sep = ",", quote = FALSE)
rm(DF1)
DF2 <- data.frame(A = 10:11, B = 12:13)
write.table(DF2, "data2.dat", sep = ",", quote = FALSE)
rm(DF2)
# now we do the real work
library(sqldf)
data1 <- file("data1.dat")
data2 <- file("data2.dat")
sqldf(c("select * from data1",
"insert into data1 select * from data2",
"select * from data1"),
dbname = tempfile())
Das gibt:
> sqldf(c("select * from data1", "insert into data1 select * from data2", "select * from data1"), dbname = tempfile())
A B
1 1 2
2 2 3
3 10 12
4 11 13
Diese kürzere Version funktioniert auch, wenn die Zeilenbestellung unwichtig ist:
sqldf("select * from data1 union select * from data2", dbname = tempfile())
Siehe die SQLDF -Startseite http://sqldf.googlecode.com und ?sqldf
Für mehr Information. Achten Sie besonders auf die Argumente des Dateiformates, da sie eng, aber nicht identisch sind mit read.table
. Hier haben wir die Standardeinstellungen verwendet, also war es weniger ein Problem.
Andere Tipps
Beachten Sie die data.table
R -Paket für effiziente Vorgänge bei Objekten mit über mehreren Millionen Datensätzen.
Version 1.8.2 dieses Pakets bietet die rbindlist
Funktion, durch die Sie das erreichen können, was Sie sehr effizient wollen. Also statt von rbind(a5r, a6r)
du kannst:
library(data.table)
rbindlist(list(a5r, a6r))
Versuchen Sie, a zu erstellen data.frame
der gewünschten Größe, importieren Sie daher Ihre Daten mit Einweisungen.
dtf <- as.data.frame(matrix(NA, 10, 10))
dtf1 <- as.data.frame(matrix(1:50, 5, 10, byrow=TRUE))
dtf2 <- as.data.frame(matrix(51:100, 5, 10, byrow=TRUE))
dtf[1:5, ] <- dtf1
dtf[6:10, ] <- dtf2
Ich vermute, dass rbind
Das Objekt wächst, ohne seine Dimensionen zu verbessern ... Ich bin mir nicht sicher sicher, dass dies nur eine Vermutung ist. Ich werde heute Abend "The R Inferno" oder "Datenmanipulation mit R" niederkämmen. Vielleicht merge
Wird den Trick machen ...
BEARBEITEN
Und Sie sollten bedenken, dass Ihr System und/oder R (vielleicht) nicht mit etwas so Großem fertig werden können. Versuchen Sie es mit Revolutionr, vielleicht können Sie Zeit/Ressourcen verschaffen.
Für die Vollständigkeit in diesem Thread zum Thema Union: Ing große Dateien verwenden Sie Shell -Befehle in den Dateien, um sie zu kombinieren. In Windows, das den Befehl "Kopieren" mit "/B" -Flag ist. Beispiel:
system(command =
paste0(
c("cmd.exe /c COPY /Y"
, '"file_1.csv" /B'
, '+ "file_2.csv" /B'
, '"resulting_file.csv" /B'
), collapse = " "
)
)#system
Erfordert, dass Dateien keinen Kopfzeile haben und gleiche Trennzeichen usw. usw. Die Geschwindigkeit und Vielseitigkeit von Shell-Befehlen sind manchmal ein großer Vorteil. Vergessen Sie also nicht die Cli-Commands, wenn Sie Datenflows abbilden.