Flujos de trabajo de "datos grandes" usando pandas [cerrado]
Frecuentes
Visto 342,096 equipos
1160
He tratado de descifrar una respuesta a esta pregunta durante muchos meses mientras aprendía pandas. Uso SAS para mi trabajo diario y es excelente por su soporte fuera del núcleo. Sin embargo, SAS es horrible como pieza de software por muchas otras razones.
Algún día espero reemplazar mi uso de SAS con python y pandas, pero actualmente carezco de un flujo de trabajo fuera del núcleo para grandes conjuntos de datos. No estoy hablando de "grandes datos" que requieren una red distribuida, sino de archivos demasiado grandes para caber en la memoria pero lo suficientemente pequeños para caber en un disco duro.
Mi primer pensamiento es usar HDFStore
para mantener grandes conjuntos de datos en el disco y extraer solo las piezas que necesito en marcos de datos para el análisis. Otros han mencionado a MongoDB como una alternativa más fácil de usar. Mi pregunta es esta:
¿Cuáles son algunos flujos de trabajo de mejores prácticas para lograr lo siguiente?
- Carga de archivos planos en una estructura de base de datos permanente en disco
- Consultar esa base de datos para recuperar datos para alimentar una estructura de datos de pandas
- Actualizando la base de datos después de manipular piezas en pandas
Los ejemplos del mundo real serían muy apreciados, especialmente de cualquiera que use pandas en "grandes datos".
Editar: un ejemplo de cómo me gustaría que esto funcione:
- Importe iterativamente un archivo plano grande y guárdelo en una estructura de base de datos permanente en disco. Estos archivos suelen ser demasiado grandes para caber en la memoria.
- Para usar Pandas, me gustaría leer subconjuntos de estos datos (generalmente solo unas pocas columnas a la vez) que puedan caber en la memoria.
- Crearía nuevas columnas realizando varias operaciones en las columnas seleccionadas.
- Entonces tendría que agregar estas nuevas columnas a la estructura de la base de datos.
Estoy tratando de encontrar una forma de mejores prácticas para realizar estos pasos. Al leer enlaces sobre pandas y pytables, parece que agregar una nueva columna podría ser un problema.
Editar: respondiendo específicamente a las preguntas de Jeff:
- Estoy construyendo modelos de riesgo de crédito al consumo. Los tipos de datos incluyen características de teléfono, SSN y dirección; valores de propiedad; información despectiva como antecedentes penales, quiebras, etc... Los conjuntos de datos que uso todos los días tienen casi 1,000 a 2,000 campos en promedio de tipos de datos mixtos: variables continuas, nominales y ordinales de datos numéricos y de caracteres. Rara vez agrego filas, pero realizo muchas operaciones que crean nuevas columnas.
- Las operaciones típicas implican combinar varias columnas usando lógica condicional en una nueva columna compuesta. Por ejemplo,
if var1 > 2 then newvar = 'A' elif var2 = 4 then newvar = 'B'
. El resultado de estas operaciones es una nueva columna para cada registro en mi conjunto de datos. - Finalmente, me gustaría agregar estas nuevas columnas a la estructura de datos en el disco. Repetiría el paso 2, explorando los datos con tabulaciones cruzadas y estadísticas descriptivas tratando de encontrar relaciones interesantes e intuitivas para modelar.
- Un archivo de proyecto típico suele ser de aproximadamente 1 GB. Los archivos se organizan de tal manera que una fila consta de un registro de datos del consumidor. Cada fila tiene el mismo número de columnas para cada registro. Este siempre será el caso.
- Es bastante raro que subdivida por filas al crear una nueva columna. Sin embargo, es bastante común para mí crear subconjuntos en filas al crear informes o generar estadísticas descriptivas. Por ejemplo, es posible que desee crear una frecuencia simple para una línea de negocio específica, por ejemplo, tarjetas de crédito minoristas. Para hacer esto, seleccionaría solo aquellos registros donde la línea de negocio = minorista además de las columnas sobre las que quiero informar. Sin embargo, al crear nuevas columnas, extraería todas las filas de datos y solo las columnas que necesito para las operaciones.
- El proceso de modelado requiere que analice cada columna, busque relaciones interesantes con alguna variable de resultado y cree nuevas columnas compuestas que describan esas relaciones. Las columnas que exploro generalmente se hacen en pequeños conjuntos. Por ejemplo, me centraré en un conjunto de, digamos, 20 columnas que solo se ocupan de los valores de las propiedades y observaré cómo se relacionan con el incumplimiento de pago de un préstamo. Una vez que se exploran y se crean nuevas columnas, paso a otro grupo de columnas, digamos educación universitaria, y repito el proceso. Lo que estoy haciendo es crear variables candidatas que expliquen la relación entre mis datos y algún resultado. Al final de este proceso, aplico algunas técnicas de aprendizaje que crean una ecuación a partir de esas columnas compuestas.
Es raro que alguna vez agregue filas al conjunto de datos. Casi siempre crearé nuevas columnas (variables o funciones en el lenguaje de estadísticas/aprendizaje automático).
16 Respuestas
706
Rutinariamente uso decenas de gigabytes de datos de esta manera, por ejemplo, tengo tablas en el disco que leo a través de consultas, creo datos y las agrego.
Vale la pena leer los docs y tarde en este hilo para obtener varias sugerencias sobre cómo almacenar sus datos.
Detalles que afectarán la forma en que almacena sus datos, como:
Proporcione tantos detalles como pueda; y puedo ayudarte a desarrollar una estructura.
- Tamaño de datos, # de filas, columnas, tipos de columnas; ¿Está agregando filas o solo columnas?
- Cómo serán las operaciones típicas. Por ejemplo, haga una consulta en columnas para seleccionar un grupo de filas y columnas específicas, luego haga una operación (en memoria), cree nuevas columnas, guárdelas.
(Dar un ejemplo de juguete podría permitirnos ofrecer recomendaciones más específicas). - Después de ese procesamiento, ¿qué haces? ¿El paso 2 es ad hoc o repetible?
- Archivos planos de entrada: cuántos, tamaño total aproximado en Gb. ¿Cómo se organizan, por ejemplo, por registros? ¿Cada uno contiene diferentes campos, o tienen algunos registros por archivo con todos los campos en cada archivo?
- ¿Alguna vez selecciona subconjuntos de filas (registros) en función de criterios (p. ej., seleccione las filas con el campo A > 5)? y luego hacer algo, o simplemente selecciona los campos A, B, C con todos los registros (y luego hace algo)?
- ¿'Trabaja en' todas sus columnas (en grupos), o hay una buena proporción que solo puede usar para informes (por ejemplo, desea mantener los datos, pero no necesita extraer esa columna explícitamente hasta que tiempo de resultados finales)?
Solución
Asegúrate de que tienes al menos pandas 0.10.1
instalado.
Leer iterando archivos trozo a trozo y consultas de varias tablas.
Dado que pytables está optimizado para operar en filas (que es lo que consulta), crearemos una tabla para cada grupo de campos. De esta manera, es fácil seleccionar un pequeño grupo de campos (que funcionará con una tabla grande, pero es más eficiente hacerlo de esta manera... Creo que puedo solucionar esta limitación en el futuro... esto es más intuitivo de todos modos):
(Lo siguiente es pseudocódigo).
import numpy as np
import pandas as pd
# create a store
store = pd.HDFStore('mystore.h5')
# this is the key to your storage:
# this maps your fields to a specific group, and defines
# what you want to have as data_columns.
# you might want to create a nice class wrapping this
# (as you will want to have this map and its inversion)
group_map = dict(
A = dict(fields = ['field_1','field_2',.....], dc = ['field_1',....,'field_5']),
B = dict(fields = ['field_10',...... ], dc = ['field_10']),
.....
REPORTING_ONLY = dict(fields = ['field_1000','field_1001',...], dc = []),
)
group_map_inverted = dict()
for g, v in group_map.items():
group_map_inverted.update(dict([ (f,g) for f in v['fields'] ]))
Leer los archivos y crear el almacenamiento (esencialmente hacer lo que append_to_multiple
lo hace):
for f in files:
# read in the file, additional options may be necessary here
# the chunksize is not strictly necessary, you may be able to slurp each
# file into memory in which case just eliminate this part of the loop
# (you can also change chunksize if necessary)
for chunk in pd.read_table(f, chunksize=50000):
# we are going to append to each table by group
# we are not going to create indexes at this time
# but we *ARE* going to create (some) data_columns
# figure out the field groupings
for g, v in group_map.items():
# create the frame for this group
frame = chunk.reindex(columns = v['fields'], copy = False)
# append it
store.append(g, frame, index=False, data_columns = v['dc'])
Ahora tiene todas las tablas en el archivo (en realidad, podría almacenarlas en archivos separados si lo desea, probablemente tendría que agregar el nombre del archivo a group_map, pero probablemente esto no sea necesario).
Así es como obtienes columnas y creas otras nuevas:
frame = store.select(group_that_I_want)
# you can optionally specify:
# columns = a list of the columns IN THAT GROUP (if you wanted to
# select only say 3 out of the 20 columns in this sub-table)
# and a where clause if you want a subset of the rows
# do calculations on this frame
new_frame = cool_function_on_frame(frame)
# to 'add columns', create a new group (you probably want to
# limit the columns in this new_group to be only NEW ones
# (e.g. so you don't overlap from the other tables)
# add this info to the group_map
store.append(new_group, new_frame.reindex(columns = new_columns_created, copy = False), data_columns = new_columns_created)
Cuando esté listo para el posprocesamiento:
# This may be a bit tricky; and depends what you are actually doing.
# I may need to modify this function to be a bit more general:
report_data = store.select_as_multiple([groups_1,groups_2,.....], where =['field_1>0', 'field_1000=foo'], selector = group_1)
Acerca de data_columns, en realidad no necesita definir CUALQUIER columnas_datos; le permiten subseleccionar filas en función de la columna. Por ejemplo, algo como:
store.select(group, where = ['field_1000=foo', 'field_1001>0'])
Pueden ser más interesantes para usted en la etapa final de generación del informe (esencialmente, una columna de datos está segregada de otras columnas, lo que podría afectar un poco la eficiencia si define mucho).
También es posible que desee:
- cree una función que tome una lista de campos, busque los grupos en el mapa de grupos, luego los seleccione y concatene los resultados para obtener el marco resultante (esto es esencialmente lo que hace select_as_multiple). De esta manera, la estructura sería bastante transparente para usted.
- índices en ciertas columnas de datos (hace que el subconjunto de filas sea mucho más rápido).
- habilitar la compresión.
¡Avísame cuando tengas preguntas!
respondido 11 mar '20, 20:03
Gracias por los enlaces. El segundo enlace me preocupa un poco que no puedo agregar nuevas columnas a las tablas en HDFStore. ¿Es eso correcto? Además, agregué un ejemplo de cómo usaría esta configuración. - Zelazny7
La estructura real en el hdf depende de usted. Pytables está orientado a filas, con columnas fijas en el momento de la creación. No puede agregar columnas una vez que se crea una tabla. Sin embargo, puede crear una nueva tabla indexada igual que su tabla existente. (ver los ejemplos select_as_multiple en los documentos). De esta manera, puede crear objetos de tamaño arbitrario mientras tiene consultas bastante eficientes. La forma en que usa los datos es clave para saber cómo se deben organizar en el disco. Envíame un correo electrónico fuera de la lista con un pseudocódigo de un ejemplo más específico. - Jeff
He actualizado mi pregunta para responder a sus puntos detallados. Trabajaré en un ejemplo para enviarlo fuera de la lista. ¡Gracias! - Zelazny7
@Jeff, con Pandas en 0.17.x, ¿ahora se han resuelto los problemas descritos anteriormente en Pandas? - Ctrl-Alt-Supr
@Jeff interesado en agregar una actualización rápida en su respuesta para promover dask? - Zeugma
167
Creo que a las respuestas anteriores les falta un enfoque simple que he encontrado muy útil.
Cuando tengo un archivo que es demasiado grande para cargarlo en la memoria, divido el archivo en varios archivos más pequeños (ya sea por filas o columnas)
Ejemplo: en el caso de 30 días de datos comerciales de ~ 30 GB de tamaño, los divido en un archivo por día de ~ 1 GB de tamaño. Posteriormente, proceso cada archivo por separado y agrego los resultados al final.
Una de las mayores ventajas es que permite el procesamiento paralelo de los archivos (ya sea múltiples hilos o procesos)
La otra ventaja es que la manipulación de archivos (como agregar/eliminar fechas en el ejemplo) se puede lograr mediante comandos regulares de shell, lo que no es posible en formatos de archivo más avanzados/complicados.
Este enfoque no cubre todos los escenarios, pero es muy útil en muchos de ellos.
Respondido el 23 de diciembre de 13 a las 15:12
Acordado. Con todo el bombo, es fácil olvidar que las herramientas de línea de comandos pueden ser 235 veces más rápidas que un clúster de Hadoop - zelusp
Enlace actualizado: adamdrake.com/… - amin_nejad
120
Ahora, dos años después de la pregunta, hay un equivalente de pandas 'fuera del núcleo': anochecer. ¡Es excelente! Aunque no es compatible con todas las funciones de pandas, puede llegar muy lejos con él. Actualización: en los últimos dos años se ha mantenido constantemente y existe una comunidad de usuarios sustancial que trabaja con Dask.
Y ahora, cuatro años después de la pregunta, hay otro equivalente de pandas 'out-of-core' de alto rendimiento en Vaex. "Utiliza mapeo de memoria, política de copia de memoria cero y cálculos perezosos para un mejor rendimiento (sin desperdicio de memoria)". Puede manejar conjuntos de datos de miles de millones de filas y no los almacena en la memoria (lo que hace posible incluso realizar análisis en hardware subóptimo).
Respondido el 25 de enero de 21 a las 19:01
y para un ejemplo completamente resuelto con dask, solo eche un vistazo aquí stackoverflow.com/questions/37979167/… - ℕʘʘḆḽḘ
¿Siempre está "fuera del núcleo"? (es decir, no RAM intensiva?). Si no tiene un clúster a mano, Dask no es una buena solución, en mi humilde opinión. Citando de la Documentación de Dask en sí: "Si está buscando administrar un terabyte o menos de datos CSV o JSON tabulares, entonces debe olvidarse de Spark y Dask y usar Postgres o MongoDB". - michele piccolini
72
Si sus conjuntos de datos tienen entre 1 y 20 GB, debe obtener una estación de trabajo con 48 GB de RAM. Luego, Pandas puede almacenar todo el conjunto de datos en la RAM. Sé que no es la respuesta que está buscando aquí, pero hacer computación científica en una computadora portátil con 4 GB de RAM no es razonable.
respondido 02 nov., 13:07
"hacer computación científica en una computadora portátil con 4GB de RAM no es razonable" Defina razonable. Creo que UNIVAC tendría una opinión diferente. arstechnica.com/tech-policy/2011/09/… - william_grisaitis
¡Acordado! intente continuar trabajando en la memoria incluso si cuesta $$ por adelantado. Si su trabajo genera un rendimiento financiero, con el tiempo recuperará los gastos a través de su mayor eficiencia. - respuesta
Hacer computación científica en una estación de trabajo con 48 GB de RAM no es razonable. - Yaroslav Nikitenko
@YaroslavNikitenko Un r4.2xlarge con 61 GB/RAM cuesta $532/hora. ¿Qué tipo de computación científica estás haciendo que no es tan valiosa? Suena inusual, si no irrazonable. - rjurney
@rjurney lo siento, tal vez debería haber eliminado mi comentario. Su juicio sobre la computadora científica "irrazonable" parece muy subjetivo. Hago mis cálculos científicos durante años en computadoras portátiles, y eso me parece suficiente, porque la mayor parte del tiempo escribo código. Mis algoritmos son mucho más difíciles desde el punto de vista de la programación que desde el punto de vista computacional. También estoy bastante seguro de que para escribir algoritmos escalables uno no debe confiar en las limitaciones actuales del hardware. Tu comentario sobre la informática de otras personas puede sonar un poco ofensivo (aparte de la subjetividad), ¿te importaría borrar estas pocas palabras? - Yaroslav Nikitenko
66
Sé que este es un hilo viejo, pero creo que el Blaze Vale la pena echarle un vistazo a la biblioteca. Está diseñado para este tipo de situaciones.
De los documentos:
Blaze amplía la usabilidad de NumPy y Pandas a la informática distribuida y fuera del núcleo. Blaze proporciona una interfaz similar a la de NumPy ND-Array o Pandas DataFrame, pero asigna estas interfaces familiares a una variedad de otros motores computacionales como Postgres o Spark.
Edit: Por cierto, cuenta con el apoyo de ContinuumIO y Travis Oliphant, autor de NumPy.
Respondido el 03 de diciembre de 14 a las 22:12
Otra biblioteca que podría valer la pena mirar es GraphLab Create: tiene una estructura similar a DataFrame eficiente que no está limitada por la capacidad de la memoria. blog.dato.com/… - impermeable
59
Este es el caso de pymongo. También he creado prototipos usando sql server, sqlite, HDF, ORM (SQLAlchemy) en python. En primer lugar, pymongo es una base de datos basada en documentos, por lo que cada persona sería un documento (dict
de atributos). Muchas personas forman una colección y puedes tener muchas colecciones (personas, bolsa, ingresos).
pd.dateframe -> pymongo Nota: Yo uso el chunksize
in read_csv
para mantenerlo en 5 a 10k registros (pymongo deja caer el zócalo si es más grande)
aCollection.insert((a[1].to_dict() for a in df.iterrows()))
consultando: gt = mayor que...
pd.DataFrame(list(mongoCollection.find({'anAttribute':{'$gt':2887000, '$lt':2889000}})))
.find()
devuelve un iterador, por lo que comúnmente uso ichunked
para cortar en iteradores más pequeños.
¿Qué tal una unión ya que normalmente obtengo 10 fuentes de datos para pegar juntas?
aJoinDF = pandas.DataFrame(list(mongoCollection.find({'anAttribute':{'$in':Att_Keys}})))
entonces (en mi caso a veces tengo que agregar aJoinDF
primero antes de su "combinable".)
df = pandas.merge(df, aJoinDF, on=aKey, how='left')
Y luego puede escribir la nueva información en su colección principal a través del método de actualización a continuación. (colección lógica vs fuentes de datos físicas).
collection.update({primarykey:foo},{key:change})
En búsquedas más pequeñas, simplemente desnormalice. Por ejemplo, tiene un código en el documento y simplemente agrega el texto del código de campo y hace una dict
buscar a medida que crea documentos.
Ahora que tiene un buen conjunto de datos basado en una persona, puede desatar su lógica en cada caso y crear más atributos. Finalmente, puede leer en pandas sus indicadores clave de 3 a memoria máxima y hacer pivots/agg/exploración de datos. Esto me funciona para 3 millones de registros con números/texto grande/categorías/códigos/flotantes/...
También puede usar los dos métodos integrados en MongoDB (MapReduce y framework agregado). Consulte aquí para obtener más información sobre el marco agregado, ya que parece ser más fácil que MapReduce y parece útil para un trabajo agregado rápido. Tenga en cuenta que no necesitaba definir mis campos o relaciones, y puedo agregar elementos a un documento. En el estado actual del conjunto de herramientas numpy, pandas, python que cambia rápidamente, MongoDB me ayuda a ponerme a trabajar :)
Respondido 14 ago 14, 14:08
Hola, también estoy jugando con tu ejemplo y me encuentro con este error cuando intento insertar en una base de datos: In [96]: test.insert((a[1].to_dict() for a in df.iterrows())) --------------- InvalidDocument: Cannot encode object: 0
. ¿Alguna idea de lo que podría estar mal? Mi marco de datos consta de todos los tipos de datos int64 y es muy simple. - Zelazny7
Sí, hice lo mismo para un DF de rango simple y el int64 de numpy parece molestar a pymongo. Todos los datos con los que he jugado se convierten de CSV (vs artificialmente a través de range()) y tienen tipos largos y, por lo tanto, no tienen problemas. En numpy puedes convertir, pero lo veo como una desventaja. Debo admitir que los elementos 10.1 para HDF parecen emocionantes. - brian_the_bungler
55
Un truco que encontré útil para grandes datos casos de uso es reducir el volumen de los datos al reducir la precisión flotante a 32 bits. No es aplicable en todos los casos, pero en muchas aplicaciones la precisión de 64 bits es excesiva y vale la pena ahorrar el doble de memoria. Para hacer un punto obvio aún más obvio:
>>> df = pd.DataFrame(np.random.randn(int(1e8), 5))
>>> df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100000000 entries, 0 to 99999999
Data columns (total 5 columns):
...
dtypes: float64(5)
memory usage: 3.7 GB
>>> df.astype(np.float32).info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100000000 entries, 0 to 99999999
Data columns (total 5 columns):
...
dtypes: float32(5)
memory usage: 1.9 GB
respondido 03 nov., 18:06
En términos generales, creo que debería pensar en cada tipo de columna y tener un dictado que los maneje de manera consistente. Esto permite una mayor reducción (a una categoría de int pequeño, o incluso mejor). Dependiendo del propósito, incluso puede usar algún 'truco' como cambiar la unidad que usa (usar k $ podría ayudarlo a reducir todo a int16) o agrupar cosas en categoría. Idealmente, eso debería hacerse antes de la primera exportación. - lcrmorin
49
Me di cuenta de esto un poco tarde, pero trabajo con un problema similar (modelos de prepago de hipoteca). Mi solución ha sido omitir la capa HDFStore de pandas y usar pytables directos. Guardo cada columna como una matriz HDF5 individual en mi archivo final.
Mi flujo de trabajo básico es obtener primero un archivo CSV de la base de datos. Lo comprimo con gzip, asi que no es tan grande. Luego, lo convierto en un archivo HDF5 orientado a filas, iterándolo en python, convirtiendo cada fila en un tipo de datos real y escribiéndolo en un archivo HDF5. Eso toma algunas decenas de minutos, pero no usa memoria, ya que solo está operando fila por fila. Luego "transpongo" el archivo HDF5 orientado a filas en un archivo HDF5 orientado a columnas.
La transposición de la tabla se ve así:
def transpose_table(h_in, table_path, h_out, group_name="data", group_path="/"):
# Get a reference to the input data.
tb = h_in.getNode(table_path)
# Create the output group to hold the columns.
grp = h_out.createGroup(group_path, group_name, filters=tables.Filters(complevel=1))
for col_name in tb.colnames:
logger.debug("Processing %s", col_name)
# Get the data.
col_data = tb.col(col_name)
# Create the output array.
arr = h_out.createCArray(grp,
col_name,
tables.Atom.from_dtype(col_data.dtype),
col_data.shape)
# Store the data.
arr[:] = col_data
h_out.flush()
Leerlo de nuevo entonces parece:
def read_hdf5(hdf5_path, group_path="/data", columns=None):
"""Read a transposed data set from a HDF5 file."""
if isinstance(hdf5_path, tables.file.File):
hf = hdf5_path
else:
hf = tables.openFile(hdf5_path)
grp = hf.getNode(group_path)
if columns is None:
data = [(child.name, child[:]) for child in grp]
else:
data = [(child.name, child[:]) for child in grp if child.name in columns]
# Convert any float32 columns to float64 for processing.
for i in range(len(data)):
name, vec = data[i]
if vec.dtype == np.float32:
data[i] = (name, vec.astype(np.float64))
if not isinstance(hdf5_path, tables.file.File):
hf.close()
return pd.DataFrame.from_items(data)
Ahora, generalmente ejecuto esto en una máquina con una tonelada de memoria, por lo que es posible que no sea lo suficientemente cuidadoso con el uso de mi memoria. Por ejemplo, de forma predeterminada, la operación de carga lee todo el conjunto de datos.
Por lo general, esto funciona para mí, pero es un poco torpe y no puedo usar la elegante magia de pytables.
Editar: la ventaja real de este enfoque, sobre el valor predeterminado de pytables de matriz de registros, es que luego puedo cargar los datos en R usando h5r, que no puede manejar tablas. O, al menos, no he podido hacer que cargue tablas heterogéneas.
respondido 22 mar '13, 15:03
¿Te importaría compartir conmigo algo de tu código? Estoy interesado en cómo carga los datos desde algún formato de texto plano sin conocer los tipos de datos antes de pasar a pytables. Además, parece que solo trabaja con datos de un tipo. ¿Es eso correcto? - Zelazny7
En primer lugar, supongo que conozco los tipos de columnas antes de cargar, en lugar de intentar adivinar a partir de los datos. Guardo un archivo JSON de "especificaciones de datos" con los nombres y tipos de columna y lo uso al procesar los datos. (El archivo suele ser una salida BCP horrible sin ninguna etiqueta). Los tipos de datos que uso son cadenas, flotantes, enteros o fechas mensuales. Convierto las cadenas en enteros guardando una tabla de enumeración y convierto las fechas en enteros (meses posteriores a 2000), así que solo me quedan enteros y flotantes en mis datos, además de la enumeración. Guardo los flotadores como float64 ahora, pero experimenté con float32. - johann hibschmann
si tiene tiempo, intente esto para una compatibilidad externa con R: pandas.pydata.org/pandas-docs/dev/…, y si tiene dificultades, tal vez podamos modificarlo: Jeff
Lo intentaré, si puedo. rhdf5 es un fastidio, ya que es un paquete bioconductor, en lugar de estar simplemente en CRAN como h5r. Estoy a merced de nuestro equipo de arquitectura técnica y hubo un problema con rhdf5 la última vez que lo pedí. En cualquier caso, parece un error orientarse por filas en lugar de por columnas con una tienda OLAP, pero ahora estoy divagando. - johann hibschmann
37
Como señalaron otros, después de algunos años ha surgido un equivalente de pandas 'fuera del núcleo': anochecer. Aunque dask no es un reemplazo directo de pandas y toda su funcionalidad, se destaca por varias razones:
Dask es una biblioteca de computación paralela flexible para computación analítica que está optimizada para la programación dinámica de tareas para cargas de trabajo computacionales interactivas de colecciones de "Big Data" como arreglos paralelos, marcos de datos y listas que extienden interfaces comunes como NumPy, Pandas o iteradores de Python a más grandes. Entornos que no sean de memoria o distribuidos y escalables desde portátiles hasta clústeres.
Dask destaca las siguientes virtudes:
- Familiar: proporciona una matriz NumPy paralelizada y objetos Pandas DataFrame
- Flexible: proporciona una interfaz de programación de tareas para cargas de trabajo más personalizadas e integración con otros proyectos.
- Nativo: permite la computación distribuida en Pure Python con acceso a la pila de PyData.
- Rápido: funciona con poca sobrecarga, baja latencia y serialización mínima necesaria para algoritmos numéricos rápidos
- Escala hacia arriba: se ejecuta de manera resistente en clústeres con miles de núcleos. Escala hacia abajo: trivial para configurar y ejecutar en una computadora portátil en un solo proceso.
- Receptivo: diseñado con la informática interactiva en mente, proporciona comentarios y diagnósticos rápidos para ayudar a los humanos.
y para agregar una muestra de código simple:
import dask.dataframe as dd
df = dd.read_csv('2015-*-*.csv')
df.groupby(df.user_id).value.mean().compute()
reemplaza algunos códigos de pandas como este:
import pandas as pd
df = pd.read_csv('2015-01-01.csv')
df.groupby(df.user_id).value.mean()
y, especialmente destacable, proporciona a través de la concurrent.futures
interfaz una infraestructura general para el envío de tareas personalizadas:
from dask.distributed import Client
client = Client('scheduler:port')
futures = []
for fn in filenames:
future = client.submit(load, fn)
futures.append(future)
summary = client.submit(summarize, futures)
summary.result()
Respondido el 08 de enero de 20 a las 17:01
He agregado esta respuesta ya que la publicación de @Private aparece regularmente en la lista de sugerencias para eliminar por contenido y longitud. - wp78de
Dask es excelente a menos que necesite multiindexación. La falta de indexación múltiple en el momento de escribir este artículo es un problema importante. - tropa misan
26
Vale la pena mencionar aquí Ray también,
es un marco de computación distribuida, que tiene su propia implementación para pandas de forma distribuida.
Simplemente reemplace la importación de pandas, y el código debería funcionar como está:
# import pandas as pd
import ray.dataframe as pd
# use pd as usual
Puede leer más detalles aquí:
https://rise.cs.berkeley.edu/blog/pandas-on-ray/
Actualización: la parte que maneja la distribución de pandas, ha sido extraída al modín proyecto.
la forma correcta de usarlo ahora es:
# import pandas as pd
import modin.pandas as pd
Respondido el 11 de junio de 21 a las 09:06
21
Una variación más
Muchas de las operaciones realizadas en pandas también se pueden realizar como una consulta de base de datos (sql, mongo)
El uso de un RDBMS o mongodb le permite realizar algunas de las agregaciones en DB Query (que está optimizado para grandes datos y usa caché e índices de manera eficiente)
Más tarde, puede realizar un procesamiento posterior utilizando pandas.
La ventaja de este método es que obtiene las optimizaciones de la base de datos para trabajar con datos de gran tamaño, al mismo tiempo que define la lógica en una sintaxis declarativa de alto nivel, y no tiene que lidiar con los detalles de decidir qué hacer en la memoria y qué hacer. de núcleo.
Y aunque el lenguaje de consulta y los pandas son diferentes, no suele ser complicado traducir parte de la lógica de uno a otro.
Respondido 28 Abr '15, 06:04
14
Imagine Ruffus si sigue el camino simple de crear una canalización de datos que se divide en varios archivos más pequeños.
Respondido 09 Oct 14, 20:10
13
Me gustaría señalar el paquete Vaex.
Vaex es una biblioteca de python para marcos de datos perezosos fuera del núcleo (similar a Pandas), para visualizar y explorar grandes conjuntos de datos tabulares. Puede calcular estadísticas como la media, la suma, el conteo, la desviación estándar, etc., en una cuadrícula N-dimensional de hasta mil millones (109) objetos/filas por segundo. La visualización se realiza mediante histogramas, diagramas de densidad y representación de volumen 3D, lo que permite la exploración interactiva de big data. Vaex utiliza mapeo de memoria, política de copia de memoria cero y cálculos perezosos para un mejor rendimiento (sin desperdicio de memoria).
Eche un vistazo a la documentación: https://vaex.readthedocs.io/en/latest/ La API está muy cerca de la API de pandas.
Respondido el 03 de junio de 19 a las 10:06
11
Recientemente me encontré con un problema similar. Descubrí que simplemente leer los datos en fragmentos y agregarlos mientras los escribo en fragmentos en el mismo csv funciona bien. Mi problema fue agregar una columna de fecha basada en información en otra tabla, usando el valor de ciertas columnas de la siguiente manera. Esto puede ayudar a aquellos confundidos por dask y hdf5 pero más familiarizados con pandas como yo.
def addDateColumn():
"""Adds time to the daily rainfall data. Reads the csv as chunks of 100k
rows at a time and outputs them, appending as needed, to a single csv.
Uses the column of the raster names to get the date.
"""
df = pd.read_csv(pathlist[1]+"CHIRPS_tanz.csv", iterator=True,
chunksize=100000) #read csv file as 100k chunks
'''Do some stuff'''
count = 1 #for indexing item in time list
for chunk in df: #for each 100k rows
newtime = [] #empty list to append repeating times for different rows
toiterate = chunk[chunk.columns[2]] #ID of raster nums to base time
while count <= toiterate.max():
for i in toiterate:
if i ==count:
newtime.append(newyears[count])
count+=1
print "Finished", str(chunknum), "chunks"
chunk["time"] = newtime #create new column in dataframe based on time
outname = "CHIRPS_tanz_time2.csv"
#append each output to same csv, using no header
chunk.to_csv(pathlist[2]+outname, mode='a', header=None, index=None)
Respondido 04 Oct 16, 16:10
0
El formato de archivo de parquet es ideal para el caso de uso que describió. Puede leer eficientemente en un subconjunto específico de columnas con pd.read_parquet(path_to_file, columns=["foo", "bar"])
https://pandas.pydata.org/docs/reference/api/pandas.read_parquet.html
Respondido 01 ago 21, 20:08
-2
En este momento estoy trabajando "como" usted, solo que en una escala más baja, por lo que no tengo un PoC para mi sugerencia.
Sin embargo, parece que tengo éxito al usar pickle como sistema de almacenamiento en caché y subcontratar la ejecución de varias funciones en archivos, ejecutando estos archivos desde mi comando/archivo principal; Por ejemplo, uso un prepare_use.py para convertir tipos de objetos, dividir un conjunto de datos en un conjunto de datos de prueba, validación y predicción.
¿Cómo funciona el almacenamiento en caché con pickle? Utilizo cadenas para acceder a los archivos pickle que se crean dinámicamente, según los parámetros y conjuntos de datos que se pasaron (con eso trato de capturar y determinar si el programa ya se ejecutó, usando .shape para el conjunto de datos, dict para pasado parámetros). Respetando estas medidas, obtengo una cadena para tratar de encontrar y leer un archivo .pickle y puedo, si lo encuentra, omitir el tiempo de procesamiento para saltar a la ejecución en la que estoy trabajando en este momento.
Al usar bases de datos, encontré problemas similares, por lo que me alegró usar esta solución; sin embargo, hay muchas limitaciones, por ejemplo, almacenar grandes conjuntos de pepinillos debido a la redundancia. La actualización de una tabla de antes a después de una transformación se puede hacer con la indexación adecuada: la validación de la información abre otro libro (intenté consolidar los datos de alquiler rastreados y dejé de usar una base de datos después de 2 horas básicamente, ya que me hubiera gustado volver atrás después cada proceso de transformación)
Espero que mis 2 centavos te ayuden de alguna manera.
Saludos.
Respondido el 08 de enero de 20 a las 14:01
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas python mongodb pandas hdf5 large-data or haz tu propia pregunta.
¿Es la relación tamaño del núcleo/tamaño completo 1 %, 10 %? ¿Importa? Si pudiera comprimir cols a int8, o filtrar filas ruidosas, ¿cambiaría eso su ciclo de cálculo-pensamiento de, digamos, horas a minutos? (También agregue la etiqueta de datos grandes). - denis
Almacenar float32 en lugar de float64 e int8 donde sea posible, debemos ser trivial (sin embargo, no sé qué herramientas / funciones hacen float64 internamente) - denis
¿Puedes dividir tu tarea en partes de trabajo? - Andrew Scott Evans
una buena solución de 2019 para hacer pandas como operaciones en datos "medios" que no caben en la memoria es anochecer - lunguini
duckdb se perfila como una buena alternativa para trabajar en conjuntos de datos de tamaño mediano en una sola máquina. - Zelazny7