Donc, j'ai un fichier de données (séparé par des points-virgules) qui a beaucoup de détails et des lignes incomplètes (ce qui conduit Access et SQL à étrangler). C'est 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. En bref, c'est énorme, et ça ne va pas aller 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 année (et juste le plus haut niveau de segment… conduisant à environ 100 000 lignes au final), quelle serait la meilleure façon d’obtenir ce cumul dans R?
Actuellement, j'essaie de réduire les années non pertinentes avec Python, en contournant la limite de taille de fichier en lisant et en opérant sur une ligne à la fois, mais je préférerais une solution R-only (CRAN packages OK). Existe-t-il une manière similaire de lire dans les fichiers pièce par pièce dans R?
Toutes les idées seraient grandement appréciées.
Mettre à jour:
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 couper certaines colonnes et choisir deux des 40 années disponibles (2009-2010 de 1980 à 2020), afin que les données puissent s'intégrer à 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 mieux. J'ai donné le chèque à Marek parce qu'il a donné un exemple d'implémentation.
J'ai reproduit ici une version légèrement adaptée de l'implémentation de Marek pour ma réponse finale, en utilisant strsplit et cat pour ne conserver que les colonnes que je veux.
Il faut aussi 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 vous n’avez que R alors c'est le billet.
## 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)
Echecs par approche:
Mon essai avec readLines
. Ce morceau de code crée csv
avec les 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)
Existe-t-il une manière similaire de lire dans les fichiers pièce par pièce dans R?
Oui. La fonction readChar () lira un bloc de caractères sans supposer qu'ils sont terminés par un caractère nul. Si vous voulez lire des données ligne par ligne, 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. Cependant, si vous avez envie de lancer 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 utilisez une grande instance de mémoire sur EC2, vous devriez examiner le package multicœur pour utiliser tous les cœurs d'une machine.
Si vous avez envie de lire de nombreux concerts de données délimitées dans R, vous devez au moins rechercher le paquetage sqldf qui vous permet d'importer directement dans sqldf à partir de R, puis d'exploiter les données de R. J'ai trouvé que sqldf en était un. des moyens les plus rapides pour importer des concerts de données dans R, comme indiqué dans cette question précédente .
Je ne suis pas un expert en la matière, mais vous pourriez envisager d'essayer MapReduce , ce qui voudrait dire en gros que vous devez adopter une approche "diviser pour régner". R a plusieurs options pour cela, notamment:
Sinon, R fournit plusieurs packages pour traiter des données volumineuses qui sortent de la mémoire (sur le disque). Vous pourriez probablement charger l'intégralité du jeu de données dans un objet bigmemory
et effectuer la réduction complètement dans R. Voir http://www.bigmemory.org/ pour un ensemble d'outils permettant de gérer cela.
Le paquetage ff
est un moyen transparent de traiter des fichiers volumineux.
Vous pouvez voir le paquet website et/ou une présentation à ce sujet.
J'espère que ça aide
Qu'en est-il d'utiliser readr
et le read_*_chunked
family?
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 actuel
require(readr)
f <- function(x, pos) subset(x, Year %in% c(2009, 2010))
read_csv2_chunked("testfile.csv", DataFrameCallback$new(f), chunk_size = 1)
Ceci applique f
à chaque morceau, en mémorisant les noms de colonnes et en combinant les résultats filtrés. Voir ?callback
qui 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.
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/
Elle transmet tous les arguments à read.table. La combinaison devrait donc vous permettre de créer des sous-ensembles assez serrés.
Vous pouvez importer des données dans la base de données SQLite , puis utiliser RSQLite pour sélectionner des sous-ensembles.
scan () a un argument nlines et un argument skip. Y a-t-il une raison pour laquelle vous pouvez simplement utiliser cela pour lire une ligne de lignes en une fois, en vérifiant la date pour voir si elle convient? Si le fichier d'entrée est classé par date, vous pouvez stocker un index qui vous indique ce que devraient être vos sauts et lignes, ce qui accélérerait le processus à l'avenir.
Peut-être pouvez-vous 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 basé sur DBI (disponible sur CRAN).
De nos jours, 3,5 Go n’est tout simplement pas si gros que ça, je peux avoir accès à une machine avec 244 Go RAM (r3.8xlarge) sur le cloud Amazon pour 2,80 $/heure. Combien d’heures vous faudra-t-il pour déterminer 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 premières lignes dans R pour le vérifier, puis vous pouvez lancer une grande instance de mémoire comme r3.8xlarge et lisez le tout! Juste mon 2c.
Maintenant, 2017, je suggérerais d'aller pour l'étincelle et l'étincelle.
la syntaxe peut être écrite d'une manière simple, plutôt similaire à celle de Dplyr
cela correspond assez bien à une petite mémoire (petite au sens de 2017)
Cependant, cela peut être une expérience intimidante de commencer ...