panda read_csv e filtra le colonne con usecols


97

Ho un file csv che non arriva correttamente pandas.read_csvquando filtro le colonne con usecolse utilizzo più indici.

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

Mi aspetto che df1 e df2 dovrebbero essere gli stessi tranne per la colonna fittizia mancante, ma le colonne vengono etichettate male. Anche la data viene analizzata come una data.

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

Usare i numeri di colonna invece dei nomi mi dà lo stesso problema. Posso risolvere il problema rilasciando la colonna fittizia dopo il passaggio read_csv, ma sto cercando di capire cosa non va. Sto usando i panda 0.10.1.

modifica: corretto utilizzo errato dell'intestazione.


1
Qualcos'altro, il tuo utilizzo delle parole chiave headere namesnon è corretto (ecco perché la prima riga manca nel tuo esempio. Si headeraspetta un int (valore predefinito 0) come riga con l'intestazione. Perché dai "True" che viene interpretato come 1, la seconda riga (prima riga di dati) viene utilizzata come intestazione e manca. Tuttavia i nomi delle colonne sono corretti perché vengono sovrascritti con l' namesargomento. Ma puoi lasciarli entrambi e la prima riga viene utilizzata per i nomi delle colonne per impostazione predefinita. Tuttavia, non risolve la tua domanda iniziale.
joris

1
Sembra un usecolsbug. Possibilmente correlato al bug 2654 ?
abudis

bug è ancora lì senza nomi e argomenti di intestazione, buona scoperta.
Andy Hayden,

@andy lo darò un po 'di più e lo sottoporrò agli insetti panda. Apprezzo il controllo di sanità mentale.
chip

Risposte:


113

La risposta di @chip manca completamente il punto di due argomenti di parole chiave.

  • nomi è necessario solo quando non è presente un'intestazione e si desidera specificare altri argomenti utilizzando i nomi delle colonne anziché gli indici interi.
  • usecols dovrebbe fornire un filtro prima di leggere l'intero DataFrame in memoria; se usato correttamente, non dovrebbe mai essere necessario eliminare le colonne dopo la lettura.

Questa soluzione corregge quelle stranezze:

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"])

Il che ci dà:

                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
Questa è la soluzione da manuale per analizzare i dati CSV, ma all'epoca ero intenzionato a utilizzare l' argomento dei nomi perché i dati reali non avevano intestazione.
chip

2
In tal caso, non specificheresti header=0. Ti consigliamo di utilizzare header=Nonee quindi utilizzare namesin aggiunta.
Mack

Ma usi ancora usecolscon indici interi per le colonne che vuoi mantenere @Mack?
Mr_and_Mrs_D

22

Questo codice ottiene ciò che desideri, inoltre è strano e sicuramente pieno di bug:

Ho notato che funziona quando:

a) si specifica il index_colrel. al numero di colonne che usi realmente, quindi le sue tre colonne in questo esempio, non quattro (lasci cadere dummye inizi a contare da quel momento in poi)

b) lo stesso per parse_dates

c) non è così per usecols;) per ovvi motivi

d) qui ho adattato il namesper rispecchiare questo comportamento

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

che stampa

                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
Grazie. Non ho mai capito la giusta combinazione di riorganizzare i namesnumeri e in base a in usecolsmodo che i dati arrivassero correttamente.
chip

8

Se il file csv contiene dati aggiuntivi, le colonne possono essere eliminate da DataFrame dopo l'importazione.

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']

Il che ci dà:

                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

perché index_col sta creando problemi nel mio caso, ho provato a usare il nome della colonna come hai suggerito, ma ha funzionato se ho passato il numero della colonna.
YouAreAwesome

4
questo è tuttavia uno spreco di risorse
Mr_and_Mrs_D

0

Devi solo aggiungere il index_col=Falseparametro

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

importa prima csv e usa csv.DictReader è facile da elaborare ...


2
Potrebbe essere più facile, ma è anche estremamente più lento. Quando lavori su set di dati di grandi dimensioni (attualmente sto lavorando con un singolo file CSV da 13 GB), non dover attendere ore per il caricamento del file diventa molto più importante.
Fake Name
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.