Pandas read_csv low_memory y dtype opciones


320

Cuando llame

df = pd.read_csv('somefile.csv')

Yo obtengo:

/Users/josh/anaconda/envs/py27/lib/python2.7/site-packages/pandas/io/parsers.py:1130: DtypeWarning: Las columnas (4,5,7,16) tienen tipos mixtos. Especifique la opción dtype al importar o establezca low_memory = False.

¿Por qué está dtyperelacionada la opción low_memoryy por qué Falseayudarla con este problema?


2
Tengo una pregunta sobre esta advertencia. ¿El índice de las columnas mencionado está basado en 0? Por ejemplo, la columna 4 que tiene un tipo mixto, es que df [:, 4] o df [:, 3]
maziar

@maziar al leer un csv, por defecto se crea y utiliza un nuevo índice basado en 0.
firelynx

Respuestas:


433

La opción obsoleta low_memory

La low_memoryopción no está desaprobada correctamente, pero debería serlo, ya que en realidad no hace nada diferente [ fuente ]

La razón por la que recibe esta low_memoryadvertencia es porque adivinar los tipos de letra para cada columna requiere mucha memoria. Pandas intenta determinar qué dtype establecer mediante el análisis de los datos en cada columna.

Dtype Guessing (muy mal)

Los pandas solo pueden determinar qué tipo de columna debe tener una columna una vez que se lee todo el archivo. Esto significa que nada se puede analizar antes de leer todo el archivo a menos que corra el riesgo de tener que cambiar el tipo de esa columna cuando lea el último valor.

Considere el ejemplo de un archivo que tiene una columna llamada user_id. Contiene 10 millones de filas donde user_id siempre son números. Dado que los pandas no pueden saber que son solo números, probablemente lo mantendrá como las cadenas originales hasta que haya leído todo el archivo.

Especificar dtypes (siempre se debe hacer)

agregando

dtype={'user_id': int}

la pd.read_csv()llamada hará que los pandas sepan cuando comienza a leer el archivo, que esto es solo números enteros.

También vale la pena señalar que si la última línea del archivo se hubiera "foobar"escrito en la user_idcolumna, la carga se bloquearía si se especificara el dtype anterior.

Ejemplo de datos rotos que se rompen cuando se definen los tipos

import pandas as pd
try:
    from StringIO import StringIO
except ImportError:
    from io import StringIO


csvdata = """user_id,username
1,Alice
3,Bob
foobar,Caesar"""
sio = StringIO(csvdata)
pd.read_csv(sio, dtype={"user_id": int, "username": "string"})

ValueError: invalid literal for long() with base 10: 'foobar'

Los dtypes suelen ser algo complicado, lea más sobre ellos aquí: http://docs.scipy.org/doc/numpy/reference/generated/numpy.dtype.html

¿Qué tipos existen?

Tenemos acceso a tipos de numpy: float, int, bool, timedelta64 [ns] y datetime64 [ns]. Tenga en cuenta que los tipos de fecha / hora numpy no son conscientes de la zona horaria.

Pandas extiende este conjunto de dtypes con los suyos:

'datetime64 [ns,]' Que es una marca de tiempo que reconoce la zona horaria.

'categoría' que es esencialmente una enumeración (cadenas representadas por teclas enteras para guardar

'period []' No debe confundirse con un timedelta, estos objetos están realmente anclados a períodos de tiempo específicos

'Sparse', 'Sparse [int]', 'Sparse [float]' es para datos dispersos o 'Datos que tienen muchos agujeros'. En lugar de guardar el NaN o Ninguno en el marco de datos, omite los objetos, ahorrando espacio .

'Intervalo' es un tema en sí mismo, pero su uso principal es para indexar. Ver más aquí

'Int8', 'Int16', 'Int32', 'Int64', 'UInt8', 'UInt16', 'UInt32', 'UInt64' son todos enteros específicos de pandas que son anulables, a diferencia de la variante numpy.

'string' es un dtype específico para trabajar con datos de cadena y da acceso al .stratributo en la serie.

'boolean' es como el 'bool' numpy pero también admite datos faltantes.

Lea la referencia completa aquí:

Referencia dtype de pandas

Gotchas, advertencias, notas

La configuración dtype=objectsilenciará la advertencia anterior, pero no hará que sea más eficiente en cuanto a memoria, solo procesará eficientemente en todo caso.

La configuración dtype=unicodeno hará nada, ya que a numpy, a unicodese representa como object.

Uso de convertidores

@sparrow señala correctamente el uso de convertidores para evitar que los pandas exploten cuando se encuentran 'foobar'en una columna especificada como int. Me gustaría agregar que los convertidores son realmente pesados ​​e ineficientes para usar en pandas y deberían usarse como último recurso. Esto se debe a que el proceso read_csv es un proceso único.

Los archivos CSV pueden procesarse línea por línea y, por lo tanto, pueden ser procesados ​​por múltiples convertidores en paralelo de manera más eficiente simplemente cortando el archivo en segmentos y ejecutando múltiples procesos, algo que los pandas no admiten. Pero esta es una historia diferente.


66
Entonces, dado que la configuración de a dtype=objectno es más eficiente con la memoria, ¿hay alguna razón para meterse con ella además de deshacerse del error?
zthomas.nc

66
@ zthomas.nc sí, Pandas no necesita molestarse en probar lo que está en la columna. Teóricamente guardando algo de memoria durante la carga (pero nada después de que la carga se haya completado) y teóricamente guardando algunos ciclos de CPU (lo cual no notará ya que la E / S del disco será el cuello de botella.)
firelynx

55
"También vale la pena señalar que si la última línea del archivo tuviera" foobar "escrito en la columna user_id, la carga se bloquearía si se especificara el dtype anterior". ¿Hay alguna opción de "coacción" que podría usarse para tirar esta fila en lugar de estrellarse?
gorrión

55
@sparrow puede haber, pero la última vez que lo usé tenía errores. Se puede solucionar en la última versión de pandas. error_bad_lines=False, warn_bad_lines=Truedebería hacer el truco. La documentación dice que solo es válido con el analizador C. También dice que el analizador predeterminado es Ninguno, lo que dificulta saber cuál es el predeterminado.
firelynx

55
@nealmcb Puede leer el marco de datos nrows=100como argumento y luego df.dtypesver los tipos de letra que obtiene. Sin embargo, cuando lea todo el marco de datos con estos tipos de d, asegúrese de hacer una try/exceptpara que adivine las suposiciones de dtype defectuosas. Los datos están sucios, ya sabes.
firelynx

50

Tratar:

dashboard_df = pd.read_csv(p_file, sep=',', error_bad_lines=False, index_col=False, dtype='unicode')

De acuerdo con la documentación de los pandas:

dtype: escriba el nombre o dict de la columna -> tipo

En cuanto a low_memory, es True por defecto y aún no está documentado. Sin embargo, no creo que sea relevante. El mensaje de error es genérico, por lo que no debería tener que meterse con low_memory de todos modos. Espero que esto ayude y avíseme si tiene más problemas.


1
Adición de dtype=unicodeProducción: NameError: name 'unicode' is not defined. ¡Pero poner unicodecomillas (como en 'unicode') parece funcionar!
sedeh

55
@sedeh Puede especificar dtypes como tipos de python o como numpy.dtype('unicode'). Cuando asigna una cadena a la opción dtype, intentará emitirla de numpy.dtype()fábrica de manera predeterminada. Especificar en 'unicode'realidad no hará nada, solo se incluyen los Unicodes objects. Obtendrádtype='object'
firelynx

43
df = pd.read_csv('somefile.csv', low_memory=False)

Esto debería resolver el problema. Obtuve exactamente el mismo error al leer 1.8M filas de un CSV.


51
Esto silencia el error, pero en realidad no cambia nada más.
firelynx

2
Tengo el mismo problema al ejecutar un archivo de datos de 1.5 gb
Sitz Blogz

18

Como se mencionó anteriormente por firelynx si dtype se especifica explícitamente y hay datos mixtos que no son compatibles con ese dtype, la carga se bloqueará. Utilicé un convertidor como este como solución alternativa para cambiar los valores con un tipo de datos incompatible para que los datos aún pudieran cargarse.

def conv(val):
    if not val:
        return 0    
    try:
        return np.float64(val)
    except:        
        return np.float64(0)

df = pd.read_csv(csv_file,converters={'COL_A':conv,'COL_B':conv})

2

Tuve un problema similar con un archivo de ~ 400 MB. Configuración low_memory=Falsehizo el truco para mí. Primero haga las cosas simples, verificaría que su marco de datos no sea más grande que la memoria de su sistema, reinicie, borre la RAM antes de continuar. Si aún se encuentra con errores, vale la pena asegurarse de que su .csvarchivo esté bien, eche un vistazo rápido en Excel y asegúrese de que no haya corrupción obvia. Los datos originales rotos pueden causar estragos ...


1

Estaba enfrentando un problema similar al procesar un gran archivo csv (6 millones de filas). Tuve tres problemas: 1. el archivo contenía caracteres extraños (arreglado usando codificación) 2. el tipo de datos no se especificó (arreglado usando la propiedad dtype) 3. Usando lo anterior, todavía enfrenté un problema relacionado con el formato de archivo que no podía ser definido en base al nombre de archivo (corregido usando try .. excepto ..)

df = pd.read_csv(csv_file,sep=';', encoding = 'ISO-8859-1',
                 names=['permission','owner_name','group_name','size','ctime','mtime','atime','filename','full_filename'],
                 dtype={'permission':str,'owner_name':str,'group_name':str,'size':str,'ctime':object,'mtime':object,'atime':object,'filename':str,'full_filename':str,'first_date':object,'last_date':object})

try:
    df['file_format'] = [Path(f).suffix[1:] for f in df.filename.tolist()]
except:
    df['file_format'] = ''

-1

Me funcionó low_memory = Falsemientras importaba un DataFrame. Ese es todo el cambio que funcionó para mí:

df = pd.read_csv('export4_16.csv',low_memory=False)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.