web-dev-qa-db-fra.com

pandas read_csv et filtre les colonnes avec des utilisateurs

J'ai un fichier csv qui n'entre pas correctement avec pandas.read_csv lorsque je filtre les colonnes avec usecols et 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, à l'exception de 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

Utiliser des 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'un mauvais usage de l'en-tête.

76
chip

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

  • noms n'est nécessaire qu'en l'absence d'en-tête et que vous souhaitez spécifier d'autres arguments en utilisant des noms de colonnes plutôt que des index entiers.
  • secols est supposé 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
89
Mack

Ce code réalise ce que vous voulez - aussi son étrange et certainement buggy:

J'ai observé que ça marche quand:

a) vous spécifiez le index_col rel. au nombre de colonnes que vous utilisez réellement - donc ses trois colonnes dans cet exemple, pas quatre (vous supprimez dummy et commencez à compter à partir de ce moment)

b) idem pour parse_dates

c) pas du tout pour usecols;) pour des raisons évidentes

d) ici j'ai adapté la names pour 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
21
Theodros Zelleke

Si votre fichier csv contient des données supplémentaires, les colonnes peuvent être supprimées à partir du DataFrame après 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
8
chip

Vous devez simplement ajouter le paramètre index_col=False

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
0
Auday Berro