pandas read_csv y filtrar columnas con usecols


97

Tengo un archivo csv que no aparece correctamente pandas.read_csvcuando filtro las columnas usecolsy uso varios índices.

import pandas as pd
csv = r"""dummy,date,loc,x
   bar,20090101,a,1
   bar,20090102,a,3
   bar,20090103,a,5
   bar,20090101,b,1
   bar,20090102,b,3
   bar,20090103,b,5"""

f = open('foo.csv', 'w')
f.write(csv)
f.close()

df1 = pd.read_csv('foo.csv',
        header=0,
        names=["dummy", "date", "loc", "x"], 
        index_col=["date", "loc"], 
        usecols=["dummy", "date", "loc", "x"],
        parse_dates=["date"])
print df1

# Ignore the dummy columns
df2 = pd.read_csv('foo.csv', 
        index_col=["date", "loc"], 
        usecols=["date", "loc", "x"], # <----------- Changed
        parse_dates=["date"],
        header=0,
        names=["dummy", "date", "loc", "x"])
print df2

Espero que df1 y df2 sean iguales excepto por la columna ficticia que falta, pero las columnas vienen mal etiquetadas. Además, la fecha se analiza como una fecha.

In [118]: %run test.py
               dummy  x
date       loc
2009-01-01 a     bar  1
2009-01-02 a     bar  3
2009-01-03 a     bar  5
2009-01-01 b     bar  1
2009-01-02 b     bar  3
2009-01-03 b     bar  5
              date
date loc
a    1    20090101
     3    20090102
     5    20090103
b    1    20090101
     3    20090102
     5    20090103

Usar números de columna en lugar de nombres me da el mismo problema. Puedo solucionar el problema eliminando la columna ficticia después del paso read_csv, pero estoy tratando de comprender qué es lo que está mal. Estoy usando pandas 0.10.1.

editar: se corrigió el mal uso del encabezado.


1
Algo más, su uso de las palabras clave headery namesno es correcto (es por eso que falta la primera fila en su ejemplo. headerEspera un int (predeterminado 0) como la fila con el encabezado. Debido a que da "Verdadero", que se interpreta como 1, la segunda fila (la primera fila de datos) se usa como encabezado y falta. Sin embargo, los nombres de las columnas son correctos porque los sobrescribe con el namesargumento. Pero ambos pueden dejarlos y la primera fila se usa para los nombres de las columnas de manera predeterminada. Sin embargo, no resuelve su pregunta inicial.
joris

1
Esto parece un usecolserror. ¿Posiblemente relacionado con el error 2654 ?
abudis

El error sigue ahí sin nombres y argumentos de encabezado, buen hallazgo.
Andy Hayden

@andy Lo pincharé un poco más y se lo enviaré a los bichos de los pandas. Agradezco el control de cordura.
chip

Respuestas:


113

La respuesta de @chip pierde completamente el sentido de dos argumentos de palabras clave.

  • names solo es necesario cuando no hay un encabezado y desea especificar otros argumentos usando nombres de columna en lugar de índices enteros.
  • Se supone que usecols proporciona un filtro antes de leer todo el DataFrame en la memoria; si se usa correctamente, nunca debería ser necesario eliminar columnas después de leer.

Esta solución corrige esas rarezas:

import pandas as pd
from StringIO import StringIO

csv = r"""dummy,date,loc,x
bar,20090101,a,1
bar,20090102,a,3
bar,20090103,a,5
bar,20090101,b,1
bar,20090102,b,3
bar,20090103,b,5"""

df = pd.read_csv(StringIO(csv),
        header=0,
        index_col=["date", "loc"], 
        usecols=["date", "loc", "x"],
        parse_dates=["date"])

Lo que nos da:

                x
date       loc
2009-01-01 a    1
2009-01-02 a    3
2009-01-03 a    5
2009-01-01 b    1
2009-01-02 b    3
2009-01-03 b    5

1
Esta es la solución de libro de texto para analizar los datos CSV, pero en ese momento tenía la intención de usar el argumento de nombres porque los datos reales no tenían encabezado.
chip

2
En ese caso, no especificaría header=0. Querría usar header=Noney luego usar namesademás.
Mack

¿Pero todavía se usa usecolscon índices enteros para las columnas que uno quiere mantener @Mack?
Mr_and_Mrs_D

22

Este código logra lo que desea --- también es extraño y ciertamente tiene errores:

Observé que funciona cuando:

a) especificas el index_colrel. a la cantidad de columnas que realmente usa, por lo que son tres columnas en este ejemplo, no cuatro (suelta dummyy comienza a contar a partir de ese momento)

b) lo mismo para parse_dates

c) no es así usecols;) por razones obvias

d) aquí adapté el namespara reflejar este comportamiento

import pandas as pd
from StringIO import StringIO

csv = """dummy,date,loc,x
bar,20090101,a,1
bar,20090102,a,3
bar,20090103,a,5
bar,20090101,b,1
bar,20090102,b,3
bar,20090103,b,5
"""

df = pd.read_csv(StringIO(csv),
        index_col=[0,1],
        usecols=[1,2,3], 
        parse_dates=[0],
        header=0,
        names=["date", "loc", "", "x"])

print df

que imprime

                x
date       loc   
2009-01-01 a    1
2009-01-02 a    3
2009-01-03 a    5
2009-01-01 b    1
2009-01-02 b    3
2009-01-03 b    5

1
Gracias. Nunca descubrí la combinación correcta de reorganizar los namesnúmeros y según usecolslos datos para que los datos fueran correctos.
chip

8

Si su archivo csv contiene datos adicionales, las columnas se pueden eliminar del DataFrame después de la importación.

import pandas as pd
from StringIO import StringIO

csv = r"""dummy,date,loc,x
bar,20090101,a,1
bar,20090102,a,3
bar,20090103,a,5
bar,20090101,b,1
bar,20090102,b,3
bar,20090103,b,5"""

df = pd.read_csv(StringIO(csv),
        index_col=["date", "loc"], 
        usecols=["dummy", "date", "loc", "x"],
        parse_dates=["date"],
        header=0,
        names=["dummy", "date", "loc", "x"])
del df['dummy']

Lo que nos da:

                x
date       loc
2009-01-01 a    1
2009-01-02 a    3
2009-01-03 a    5
2009-01-01 b    1
2009-01-02 b    3
2009-01-03 b    5

Por qué index_col está creando un problema en mi caso, intenté usar el nombre de la columna como sugirió, pero funcionó si pasé el número de columna.
YouAreAwesome

4
Sin embargo
Mr_and_Mrs_D

0

Solo tienes que agregar el index_col=Falseparámetro

df1 = pd.read_csv('foo.csv',
     header=0,
     index_col=False,
     names=["dummy", "date", "loc", "x"], 
     index_col=["date", "loc"], 
     usecols=["dummy", "date", "loc", "x"],
     parse_dates=["date"])
  print df1

-4

importar csv primero y usar csv.DictReader es fácil de procesar ...


2
Esto puede ser más fácil, pero también mucho más lento. Cuando trabajas en conjuntos de datos grandes (actualmente estoy trabajando con un solo archivo CSV de 13 GB), no tener que esperar horas para que se cargue el archivo se vuelve mucho más importante.
Nombre falso
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.