R: comment rbind deux énormes données-cadres sans manquer de mémoire
-
16-10-2019 - |
Question
Je df1
et df2
deux données-cadres qui ont chacun environ 10 millions de lignes et 4 colonnes. Je les lis en utilisant R rodbc / sqlquery sans problème, mais lorsque je tente de les rbind
, je reçois que la plus redoutée des messages d'erreur R: cannot allocate memory
. Il y a eu à être des moyens plus efficaces pour faire un rbind
plus efficacement - quelqu'un a leurs trucs préférés sur ce qu'ils veulent partager? Par exemple, je trouve cet exemple dans le doc pour sqldf
:
# rbind
a7r <- rbind(a5r, a6r)
a7s <- sqldf("select * from a5s union all select * from a6s")
Est-ce la meilleure / méthode recommandée pour le faire?
UPDATE
Je l'ai au travail en utilisant l'argument dbname = tempfile()
crucial dans l'appel sqldf
ci-dessus, JD long suggère dans sa réponse à cette question
La solution
Au lieu de les lire en R au début, puis en les combinant, vous pourriez avoir SQLite les lire et de les combiner avant de les envoyer à R. De cette façon, les fichiers ne sont jamais chargés individuellement dans R.
# 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())
Cela donne:
> 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
Cette version plus courte fonctionne également si l'ordre des lignes est sans importance:
sqldf("select * from data1 union select * from data2", dbname = tempfile())
Voir la page d'accueil de sqldf http://sqldf.googlecode.com et ?sqldf
pour plus d'informations. Portez une attention particulière aux arguments de format de fichier, car ils sont proches mais pas identiques à read.table
. Ici, nous avons utilisé les paramètres par défaut de sorte qu'il était moins un problème.
Autres conseils
Notez que le package de R data.table
pour des opérations efficaces sur les objets avec plus de plusieurs millions d'enregistrements.
Version 1.8.2 que les offres de package la fonction rbindlist
à travers lequel vous pouvez réaliser ce que vous voulez de façon très efficace. Ainsi, au lieu de rbind(a5r, a6r)
vous pouvez:
library(data.table)
rbindlist(list(a5r, a6r))
Essayez de créer une data.frame
de taille souhaitée, importer donc vos données en utilisant les indices.
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
Je suppose que rbind
pousse objet sans pré-allocation de ses dimensions ... Je suis, ce n'est pas positivement sûr qu'une supposition. Je peigne vers le bas « La R Inferno » ou « Manipulation de données avec R » ce soir. Peut-être merge
fera l'affaire ...
EDIT
Et vous devriez nu à l'esprit que (peut-être) votre système et / ou R ne peuvent pas faire face à quelque chose de ce grand. Essayez RevolutionR, peut-être vous parvenez à épargner un certain temps / ressources.
Pour être complet dans ce fil sur le thème de l'union: ing gros fichiers, essayez d'utiliser des commandes shell sur les fichiers pour les combiner. Dans Windows qui commande « COPIE » avec le drapeau « / B ». Exemple:
system(command =
paste0(
c("cmd.exe /c COPY /Y"
, '"file_1.csv" /B'
, '+ "file_2.csv" /B'
, '"resulting_file.csv" /B'
), collapse = " "
)
)#system
Exige que les fichiers ont sans en-tête, et même delimiter etc etc. La vitesse et la polyvalence des commandes shell est parfois un grand avantage, donc ne pas oublier CLI-commandes lors de la cartographie des flux de données.