Así que tengo un archivo de datos (separado por punto y coma) que tiene muchos detalles y filas incompletas (lo que hace que Access y SQL se bloqueen). Es un conjunto de datos a nivel de condado dividido en segmentos, subsegmentos y subsegmentos (para un total de ~ 200 factores) durante 40 años. En resumen, es enorme y no va a caber en la memoria si intento simplemente leerlo.
Entonces mi pregunta es esta, dado que quiero todos los condados, pero solo un año (y solo el nivel más alto de segmento ... lo que lleva a aproximadamente 100,000 filas al final), ¿cuál sería la mejor manera de obtener este resumen en R?
Actualmente estoy tratando de eliminar años irrelevantes con Python, superando el límite leyendo y operando en una línea a la vez, pero preferiría una solución solo R (paquetes CRAN OK). ¿Existe una forma similar de leer en archivos un fragmento a la vez en R?
Cualquier idea será muy apreciada.
Actualizar:
- Restricciones
- Necesita usar mi máquina, por lo que no hay instancias EC2
- Tan solo R como sea posible. La velocidad y los recursos no son una preocupación en este caso ... siempre que mi máquina no explote ...
- Como puede ver a continuación, los datos contienen tipos mixtos, en los que necesito operar más tarde
- Datos
- Los datos son de 3,5 GB, con aproximadamente 8,5 millones de filas y 17 columnas.
- Un par de miles de filas (~ 2k) están mal formadas, con solo una columna en lugar de 17
- Estos son completamente insignificantes y pueden descartarse
- Solo necesito ~ 100,000 filas de este archivo (ver más abajo)
Ejemplo de datos:
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]
Quiero cortar algunas columnas y elegir dos de los 40 años disponibles (2009-2010 de 1980-2020), para que los datos puedan caber en 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]
Resultados:
Después de jugar con todas las sugerencias hechas, decidí que readLines, sugerido por JD y Marek, funcionaría mejor. Le di a Marek el cheque porque dio una implementación de muestra.
Reproduje una versión ligeramente adaptada de la implementación de Marek para mi respuesta final aquí, usando strsplit y cat para mantener solo las columnas que quiero.
También debe tenerse en cuenta que esto es MUCHO menos eficiente que Python ... como en, Python muerde el archivo de 3.5GB en 5 minutos mientras que R toma alrededor de 60 ... pero si todo lo que tiene es R, entonces este es el boleto.
## 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)
Fallos por enfoque:
- sqldf
- Esto es definitivamente lo que usaré para este tipo de problema en el futuro si los datos están bien formados. Sin embargo, si no es así, SQLite se ahoga.
- Mapa reducido
- Para ser honesto, los médicos me intimidaron un poco en este caso, así que no pude intentarlo. Parecía que también requería que el objeto estuviera en la memoria, lo que anularía el punto si ese fuera el caso.
- gran memoria
- Este enfoque está claramente vinculado a los datos, pero solo puede manejar un tipo a la vez. Como resultado, todos mis vectores de caracteres cayeron cuando se pusieron en una tabla grande. Sin embargo, si necesito diseñar grandes conjuntos de datos para el futuro, consideraría usar solo números para mantener viva esta opción.
- escanear
- El escaneo parecía tener problemas de tipo similares a los de la memoria grande, pero con todos los mecanismos de readLines. En resumen, esta vez no encajaba bien.
sed
y / oawk
creando una versión reducida del CSV que pueda leer directamente. Dado que esto es más una solución que una respuesta, lo dejaré como comentario.fread
función es mucho más rápida queread.table
. Usa algo comox = fread(file_path_here, data.table=FALSE)
para cargarlo como undata.frame
objeto.Respuestas:
Mi intento con
readLines
. Esta parte de un código se creacsv
con años seleccionados.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)
fuente
No soy un experto en esto, pero podría considerar probar MapReduce , lo que básicamente significaría adoptar un enfoque de "divide y vencerás". R tiene varias opciones para esto, que incluyen:
Alternativamente, R proporciona varios paquetes para manejar datos grandes que salen de la memoria (al disco). Probablemente podría cargar todo el conjunto de datos en un
bigmemory
objeto y hacer la reducción completamente dentro de R. Consulte http://www.bigmemory.org/ para obtener un conjunto de herramientas para manejar esto.fuente
bigmemory
puede ser más fácil para ti probar primero, en ese caso.Si. La función readChar () leerá en un bloque de caracteres sin asumir que terminan en nulo. Si desea leer datos en una línea a la vez, puede usar readLines () . Si lee un bloque o una línea, realiza una operación y luego escribe los datos, puede evitar el problema de la memoria. Aunque si tiene ganas de activar una gran instancia de memoria en el EC2 de Amazon, puede obtener hasta 64 GB de RAM. Eso debería contener su archivo y mucho espacio para manipular los datos.
Si necesita más velocidad, la recomendación de Shane de usar Map Reduce es muy buena. Sin embargo, si sigue la ruta de usar una instancia de memoria grande en EC2, debe mirar el paquete multinúcleo para usar todos los núcleos en una máquina.
Si desea leer muchos gigas de datos delimitados en R, al menos debería investigar el paquete sqldf que le permite importar directamente a sqldf desde R y luego operar con los datos desde dentro de R. He encontrado que sqldf es uno de las formas más rápidas de importar gigas de datos en R, como se mencionó en esta pregunta anterior .
fuente
Hay un paquete completamente nuevo llamado colbycol que le permite leer solo las variables que desea de archivos de texto enormes:
http://colbycol.r-forge.r-project.org/
Pasa cualquier argumento a read.table, por lo que la combinación debería permitirle subconjuntos bastante ajustados.
fuente
El
ff
paquete es una forma transparente de tratar archivos de gran tamaño.Puede ver el sitio web del paquete y / o una presentación al respecto.
espero que esto ayude
fuente
Puede importar datos a la base de datos SQLite y luego usar RSQLite para seleccionar subconjuntos.
fuente
¿Qué pasa con el uso
readr
y laread_*_chunked
familia?Entonces, en tu caso:
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
Código real
require(readr) f <- function(x, pos) subset(x, Year %in% c(2009, 2010)) read_csv2_chunked("testfile.csv", DataFrameCallback$new(f), chunk_size = 1)
Esto se aplica
f
a cada fragmento, recordando los nombres de las columnas y combinando los resultados filtrados al final. Vea?callback
cuál es la fuente de este ejemplo.Esto resulta en:
# 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
Incluso puede aumentar,
chunk_size
pero en este ejemplo solo hay 4 líneas.fuente
¿Has tenido una gran memoria ? Mira esto y esto .
fuente
Quizás pueda migrar a MySQL o PostgreSQL para evitar las limitaciones de MS Access.
Es bastante fácil conectar R a estos sistemas con un conector de base de datos basado en DBI (disponible en CRAN).
fuente
scan () tiene un argumento de nlines y un argumento de omisión. ¿Hay alguna razón por la que pueda usar eso para leer un fragmento de líneas a la vez, verificando la fecha para ver si es apropiada? Si el archivo de entrada está ordenado por fecha, puede almacenar un índice que le indique cuáles deberían ser sus omisiones y líneas que acelerarían el proceso en el futuro.
fuente
En estos días, 3.5GB simplemente no es tan grande, puedo acceder a una máquina con 244GB de RAM (r3.8xlarge) en la nube de Amazon por $ 2.80 / hora. ¿Cuántas horas le tomará descubrir cómo resolver el problema usando soluciones de tipo big data? ¿Cuánto vale su tiempo? Sí, le llevará una o dos horas descubrir cómo usar AWS, pero puede aprender los conceptos básicos en un nivel gratuito, cargar los datos y leer las primeras 10k líneas en R para verificar que funcionó y luego puede iniciar un instancia de memoria grande como r3.8xlarge y leerlo todo! Solo mi 2c.
fuente
Ahora, 2017, sugeriría ir por Spark y SparkR.
la sintaxis se puede escribir de una manera simple bastante similar a dplyr
encaja bastante bien en la memoria pequeña (pequeña en el sentido de 2017)
Sin embargo, comenzar puede ser una experiencia intimidante ...
fuente
Buscaría una base de datos y luego haría algunas consultas para extraer las muestras que necesita a través de DBI
Evite importar un archivo csv de 3,5 GB en SQLite. O al menos verifique que su enorme base de datos se ajuste a los límites de SQLite, http://www.sqlite.org/limits.html
Es una base de datos muy grande la que tienes. Optaría por MySQL si necesita velocidad. Pero prepárate para esperar muchas horas hasta que finalice la importación. A menos que tenga algún hardware poco convencional o esté escribiendo desde el futuro ...
El EC2 de Amazon podría ser una buena solución también para crear instancias de un servidor que ejecute R y MySQL.
mis dos humildes centavos valen.
fuente