J'ai donc un fichier de données (séparé par des points-virgules) qui contient beaucoup de détails et des lignes incomplètes (amenant Access et SQL à s'étouffer). Il s'agit d'un ensemble de données au niveau du comté divisé en segments, sous-segments et sous-sous-segments (pour un total d'environ 200 facteurs) pendant 40 ans. Bref, c'est énorme, et ça ne rentrera pas dans la mémoire si j'essaie simplement de le lire.
Donc ma question est la suivante, étant donné que je veux tous les comtés, mais seulement une seule année (et juste le plus haut niveau de segment ... conduisant à environ 100000 lignes à la fin), quelle serait la meilleure façon de procéder pour obtenir ce rollup en R?
Actuellement, j'essaie de couper les années non pertinentes avec Python, de contourner la limite de taille du fichier en lisant et en opérant sur une ligne à la fois, mais je préférerais une solution R-only (packages CRAN OK). Existe-t-il une manière similaire de lire dans les fichiers un morceau à la fois dans R?
Toutes les idées seraient grandement appréciées.
Mise à jour:
- Contraintes
- Doit utiliser ma machine, donc pas d'instance EC2
- Aussi R-seulement que possible. La vitesse et les ressources ne sont pas concernées dans ce cas ... à condition que ma machine n'explose pas ...
- Comme vous pouvez le voir ci-dessous, les données contiennent des types mixtes, sur lesquels je devrai opérer plus tard
- Les données
- Les données sont de 3,5 Go, avec environ 8,5 millions de lignes et 17 colonnes
- Quelques milliers de lignes (~ 2k) sont mal formées, avec une seule colonne au lieu de 17
- Ceux-ci sont totalement sans importance et peuvent être supprimés
- Je n'ai besoin que d'environ 100000 lignes de ce fichier (voir ci-dessous)
Exemple de données:
County; State; Year; Quarter; Segment; Sub-Segment; Sub-Sub-Segment; GDP; ...
Ada County;NC;2009;4;FIRE;Financial;Banks;80.1; ...
Ada County;NC;2010;1;FIRE;Financial;Banks;82.5; ...
NC [Malformed row]
[8.5 Mill rows]
Je veux découper certaines colonnes et choisir deux des 40 années disponibles (2009-2010 de 1980-2020), afin que les données puissent tenir dans R:
County; State; Year; Quarter; Segment; GDP; ...
Ada County;NC;2009;4;FIRE;80.1; ...
Ada County;NC;2010;1;FIRE;82.5; ...
[~200,000 rows]
Résultats:
Après avoir bricolé toutes les suggestions faites, j'ai décidé que readLines, suggéré par JD et Marek, fonctionnerait le mieux. J'ai donné le chèque à Marek parce qu'il a donné un exemple d'implémentation.
J'ai reproduit une version légèrement adaptée de l'implémentation de Marek pour ma réponse finale ici, en utilisant strsplit et cat pour ne garder que les colonnes que je veux.
Il convient également de noter que c'est BEAUCOUP moins efficace que Python ... comme dans, Python parcourt le fichier de 3,5 Go en 5 minutes tandis que R en prend environ 60 ... mais si tout ce que vous avez est R, c'est le ticket.
## Open a connection separately to hold the cursor position
file.in <- file('bad_data.txt', 'rt')
file.out <- file('chopped_data.txt', 'wt')
line <- readLines(file.in, n=1)
line.split <- strsplit(line, ';')
# Stitching together only the columns we want
cat(line.split[[1]][1:5], line.split[[1]][8], sep = ';', file = file.out, fill = TRUE)
## Use a loop to read in the rest of the lines
line <- readLines(file.in, n=1)
while (length(line)) {
line.split <- strsplit(line, ';')
if (length(line.split[[1]]) > 1) {
if (line.split[[1]][3] == '2009') {
cat(line.split[[1]][1:5], line.split[[1]][8], sep = ';', file = file.out, fill = TRUE)
}
}
line<- readLines(file.in, n=1)
}
close(file.in)
close(file.out)
Échecs par approche:
- sqldf
- C'est certainement ce que j'utiliserai pour ce type de problème à l'avenir si les données sont bien formées. Cependant, si ce n'est pas le cas, SQLite s'étouffe.
- MapReduce
- Pour être honnête, les documents m'ont un peu intimidé sur celui-ci, donc je n'ai pas essayé. Il semblait qu'il fallait que l'objet soit également en mémoire, ce qui irait à l'encontre du point si tel était le cas.
- grande mémoire
- Cette approche est clairement liée aux données, mais elle ne peut gérer qu'un seul type à la fois. En conséquence, tous mes vecteurs de caractères ont chuté lorsqu'ils sont placés dans une grande table. Si j'ai besoin de concevoir de grands ensembles de données pour l'avenir, j'envisagerais d'utiliser uniquement des nombres juste pour garder cette option en vie.
- analyse
- Scan semblait avoir des problèmes de type similaires à ceux de la grande mémoire, mais avec tous les mécanismes de readLines. En bref, cela ne correspondait tout simplement pas à la facture cette fois.
sed
et / ouawk
en créant une version réduite du CSV que vous pouvez lire directement. Puisqu'il s'agit plus d'une solution de contournement qu'une réponse, je vais le laisser en commentaire.fread
fonction est beaucoup plus rapide queread.table
. Utilisez quelque chose commex = fread(file_path_here, data.table=FALSE)
pour le charger en tantdata.frame
qu'objet.Réponses:
Mon essai avec
readLines
. Ce morceau de code créecsv
avec des années sélectionnées.file_in <- file("in.csv","r") file_out <- file("out.csv","a") x <- readLines(file_in, n=1) writeLines(x, file_out) # copy headers B <- 300000 # depends how large is one pack while(length(x)) { ind <- grep("^[^;]*;[^;]*; 20(09|10)", x) if (length(ind)) writeLines(x[ind], file_out) x <- readLines(file_in, n=B) } close(file_in) close(file_out)
la source
Je ne suis pas un expert en la matière, mais vous pourriez envisager d'essayer MapReduce , ce qui reviendrait essentiellement à adopter une approche «diviser pour conquérir». R a plusieurs options pour cela, notamment:
Alternativement, R fournit plusieurs packages pour traiter des données volumineuses qui sortent de la mémoire (sur le disque). Vous pourriez probablement charger l'ensemble de données dans un
bigmemory
objet et effectuer la réduction complètement dans R. Voir http://www.bigmemory.org/ pour un ensemble d'outils pour gérer cela.la source
bigmemory
peut être plus facile pour vous d'essayer en premier, dans ce cas.Oui. La fonction readChar () lira un bloc de caractères sans supposer qu'ils sont terminés par null. Si vous souhaitez lire des données sur une ligne à la fois, vous pouvez utiliser readLines () . Si vous lisez un bloc ou une ligne, effectuez une opération, puis écrivez les données, vous pouvez éviter le problème de mémoire. Bien que si vous avez envie de déclencher une grande instance de mémoire sur l'EC2 d'Amazon, vous pouvez obtenir jusqu'à 64 Go de RAM. Cela devrait contenir votre fichier et beaucoup d'espace pour manipuler les données.
Si vous avez besoin de plus de vitesse, la recommandation de Shane d'utiliser Map Reduce est très bonne. Cependant, si vous choisissez d'utiliser une grande instance de mémoire sur EC2, vous devriez regarder le package multicœur pour utiliser tous les cœurs sur une machine.
Si vous souhaitez lire de nombreux gigs de données délimitées dans R, vous devriez au moins rechercher le package sqldf qui vous permet d'importer directement dans sqldf à partir de R, puis d'opérer sur les données depuis R. J'ai trouvé que sqldf en était un. des moyens les plus rapides d'importer des gigs de données dans R, comme mentionné dans cette question précédente .
la source
Il existe un tout nouveau package appelé colbycol qui vous permet de lire uniquement les variables souhaitées à partir d'énormes fichiers texte:
http://colbycol.r-forge.r-project.org/
Il transmet tous les arguments à read.table, donc la combinaison devrait vous permettre de sous-ensemble assez étroitement.
la source
le
ff
package est un moyen transparent de traiter des fichiers volumineux.Vous pouvez voir le site Web du package et / ou une présentation à ce sujet.
J'espère que ça aide
la source
Vous pouvez importer des données dans la base de données SQLite , puis utiliser RSQLite pour sélectionner des sous-ensembles.
la source
Qu'en est-il de l'utilisation
readr
et duread_*_chunked
famille?Donc dans votre cas:
testfile.csv
County; State; Year; Quarter; Segment; Sub-Segment; Sub-Sub-Segment; GDP Ada County;NC;2009;4;FIRE;Financial;Banks;80.1 Ada County;NC;2010;1;FIRE;Financial;Banks;82.5 lol Ada County;NC;2013;1;FIRE;Financial;Banks;82.5
Code réel
require(readr) f <- function(x, pos) subset(x, Year %in% c(2009, 2010)) read_csv2_chunked("testfile.csv", DataFrameCallback$new(f), chunk_size = 1)
Cela s'applique
f
à chaque bloc, en se souvenant des noms de colonne et en combinant les résultats filtrés à la fin. Voir?callback
quelle est la source de cet exemple.Cela se traduit par:
# A tibble: 2 × 8 County State Year Quarter Segment `Sub-Segment` `Sub-Sub-Segment` GDP * <chr> <chr> <int> <int> <chr> <chr> <chr> <dbl> 1 Ada County NC 2009 4 FIRE Financial Banks 801 2 Ada County NC 2010 1 FIRE Financial Banks 825
Vous pouvez même augmenter
chunk_size
mais dans cet exemple il n'y a que 4 lignes.la source
Avez-vous pensé à la grande mémoire ? Vérifiez ceci et cela .
la source
Vous pouvez peut-être migrer vers MySQL ou PostgreSQL pour vous éviter les limitations de MS Access.
Il est assez facile de connecter R à ces systèmes avec un connecteur de base de données DBI (disponible sur CRAN).
la source
scan () a à la fois un argument nlines et un argument skip. Y a-t-il une raison pour laquelle vous pouvez simplement utiliser cela pour lire un morceau de lignes à la fois, en vérifiant la date pour voir si elle est appropriée? Si le fichier d'entrée est trié par date, vous pouvez stocker un index qui vous indique ce que votre saut et vos nlines devraient être qui accéléreraient le processus à l'avenir.
la source
De nos jours, 3,5 Go n'est tout simplement pas si gros, je peux accéder à une machine avec 244 Go de RAM (r3.8xlarge) sur le cloud Amazon pour 2,80 $ / heure. Combien d'heures vous faudra-t-il pour comprendre comment résoudre le problème à l'aide de solutions de type big data? Combien vaut votre temps? Oui, cela vous prendra une heure ou deux pour comprendre comment utiliser AWS - mais vous pouvez apprendre les bases sur un niveau gratuit, télécharger les données et lire les 10 000 premières lignes dans R pour vérifier que cela a fonctionné, puis vous pouvez lancer un grande instance de mémoire comme r3.8xlarge et tout lire! Juste mon 2c.
la source
Maintenant, 2017, je suggérerais d'opter pour Spark et SparkR.
la syntaxe peut être écrite d'une manière simple assez similaire à celle d'un dplyr
il s'adapte assez bien à une petite mémoire (petite au sens de 2017)
Cependant, cela peut être une expérience intimidante pour commencer ...
la source
J'irais chercher une base de données, puis ferais quelques requêtes pour extraire les échantillons dont vous avez besoin via DBI
Veuillez éviter d'importer un fichier csv de 3,5 Go dans SQLite. Ou au moins, vérifiez que votre énorme base de données s'inscrit dans les limites de SQLite, http://www.sqlite.org/limits.html
C'est un sacré gros DB que vous avez. J'irais pour MySQL si vous avez besoin de vitesse. Mais soyez prêt à attendre de nombreuses heures pour que l'importation se termine. À moins que vous n'ayez du matériel non conventionnel ou que vous écriviez du futur ...
L'EC2 d'Amazon pourrait également être une bonne solution pour instancier un serveur exécutant R et MySQL.
mes deux modestes centimes valent.
la source