pandas read_csv et filtre les colonnes avec les codes utilisateur

97

J'ai un fichier csv qui ne vient pas correctement pandas.read_csvlorsque je filtre les colonnes avec usecolset que j'utilise plusieurs index.

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

Je m'attends à ce que df1 et df2 soient identiques, sauf pour la colonne factice manquante, mais les colonnes sont mal étiquetées. De plus, la date est analysée comme une date.

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

L'utilisation de numéros de colonne au lieu de noms me pose le même problème. Je peux contourner le problème en supprimant la colonne factice après l'étape read_csv, mais j'essaie de comprendre ce qui ne va pas. J'utilise pandas 0.10.1.

edit: correction d'une mauvaise utilisation de l'en-tête.

puce
la source
1
Autre chose, votre utilisation des mots clés headeret namesn'est pas correcte (c'est pourquoi la première ligne est manquante dans votre exemple. headerAttend un int (0 par défaut) comme ligne avec l'en-tête. Parce que vous donnez "True" qui est interprété comme 1, la deuxième ligne (première ligne de données) est utilisée comme en-tête et est manquante. Cependant, les noms de colonnes sont corrects car vous les écrasez avec l' namesargument. Mais vous pouvez les laisser tous les deux et la première ligne est utilisée par défaut pour les noms de colonnes. Cependant, cela ne résout pas votre question initiale.
joris
1
Cela ressemble à un usecolsbug. Peut-être lié au bogue 2654 ?
abudis
le bogue est toujours là sans noms et arguments d'en-tête, bonne trouvaille.
Andy Hayden
@andy Je vais le pousser un peu plus et le soumettre aux bugs pandas. J'apprécie le contrôle de santé mentale.
puce du

Réponses:

113

La réponse de @chip manque complètement le point de deux arguments de mot-clé.

  • names n'est nécessaire que lorsqu'il n'y a pas d'en-tête et que vous souhaitez spécifier d'autres arguments en utilisant des noms de colonnes plutôt que des indices entiers.
  • usecols est censé fournir un filtre avant de lire l'intégralité du DataFrame en mémoire; s'il est utilisé correctement, il ne devrait jamais être nécessaire de supprimer des colonnes après la lecture.

Cette solution corrige ces bizarreries:

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

Ce qui nous donne:

                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
Mack
la source
1
C'est la solution classique pour analyser les données CSV, mais à l'époque, j'avais l'intention d'utiliser l' argument names car les données réelles n'avaient pas d'en-tête.
puce du
2
Dans ce cas, vous ne spécifierez pas header=0. Vous voudriez utiliser header=Nonepuis utiliser namesen plus.
Mack
Mais toujours utiliser usecolsavec des index entiers pour les colonnes que l'on veut garder @Mack?
Mr_and_Mrs_D
22

Ce code réalise ce que vous voulez - aussi c'est bizarre et certainement bogué:

J'ai observé que ça marche quand:

a) vous spécifiez le index_colrel. au nombre de colonnes que vous utilisez vraiment - donc ses trois colonnes dans cet exemple, pas quatre (vous déposez dummyet commencez à compter à partir de là)

b) idem pour parse_dates

c) pas le cas usecols;) pour des raisons évidentes

d) ici j'ai adapté le namespour refléter ce comportement

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

qui 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
Théodros Zelleke
la source
1
Merci. Je n'ai jamais trouvé la bonne combinaison pour réorganiser les namesnombres et en fonction de usecolssorte que les données soient correctes.
puce du
8

Si votre fichier csv contient des données supplémentaires, les colonnes peuvent être supprimées du DataFrame après l'importation.

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

Ce qui nous donne:

                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
puce
la source
pourquoi l'index_col crée un problème dans mon cas, j'ai essayé d'utiliser le nom de colonne comme vous l'avez suggéré, mais cela a fonctionné si j'ai passé le numéro de colonne.
YouAreAwesome
4
c'est un gaspillage de ressources cependant
Mr_and_Mrs_D
0

Vous devez simplement ajouter le index_col=Falseparamètre

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
Auday Berro
la source
-4

importez d'abord csv et utilisez csv.DictReader, c'est facile à traiter ...

Mohan
la source
2
Cela peut être plus facile, mais c'est aussi beaucoup plus lent. Lorsque vous travaillez sur de grands ensembles de données (je travaille actuellement avec un seul fichier CSV de 13 Go moi-même), ne pas avoir à attendre des heures pour que le fichier se charge devient beaucoup plus important.
Faux nom