222 votes

Est-ce que pandas peut lire automatiquement les dates d'un fichier CSV ?

Aujourd'hui, j'ai été positivement surpris par le fait qu'en lisant les données d'un fichier de données (par exemple), pandas est capable de reconnaître les types de valeurs :

df = pandas.read_csv('test.dat', delimiter=r"\s+", names=['col1','col2','col3'])

Par exemple, il peut être vérifié de cette façon :

for i, r in df.iterrows():
    print type(r['col1']), type(r['col2']), type(r['col3'])

En particulier, les entiers, les flottants et les chaînes de caractères ont été reconnus correctement. Cependant, j'ai une colonne qui contient des dates au format suivant : 2013-6-4 . Ces dates ont été reconnues comme des chaînes de caractères (et non comme des objets de date python). Existe-t-il un moyen d'"apprendre" à pandas à reconnaître les dates ?

8voto

Gaurav Points 433

Oui - selon le pandas.read_csv documentation :

Note : Un chemin rapide existe pour formaté selon l'iso8601 dates.

Donc si votre csv a une colonne nommée datetime et les dates ressemblent à 2013-01-01T01:01 Par exemple, si vous exécutez cette commande, pandas (je suis en version 0.19.2) détectera automatiquement la date et l'heure :

df = pd.read_csv('test.csv', parse_dates=['datetime'])

Notez que vous devez passer explicitement parse_dates il ne fonctionne pas sans.

Vérifier avec :

df.dtypes

Vous devriez voir que le type de données de la colonne est datetime64[ns]

4voto

kamran kausar Points 311

Lors du chargement d'un fichier csv contenant une colonne de date, nous avons deux approches pour que pandas reconnaisse la colonne de date. reconnaître la colonne date, c'est-à-dire

  1. Pandas reconnaît explicitement le format par arg date_parser=mydateparser

  2. Pandas reconnaît implicitement le format par agr. infer_datetime_format=True

Certaines des données de la colonne de date

01/01/18

01/02/18

Ici, nous ne savons pas les deux premières choses. Ça peut être un mois ou un jour. Donc, dans ce cas, nous devons utiliser Méthode 1:- Passer explicitement le format

    mydateparser = lambda x: pd.datetime.strptime(x, "%m/%d/%y")
    df = pd.read_csv(file_name, parse_dates=['date_col_name'],
date_parser=mydateparser)

Méthode 2 : - Reconnaissance implicite ou automatique du format

df = pd.read_csv(file_name, parse_dates=[date_col_name],infer_datetime_format=True)

2voto

VLRoyrenn Points 426

En plus de ce que les autres réponses ont dit, si vous devez analyser de très gros fichiers avec des centaines de milliers d'horodatages, date_parser peut s'avérer être un énorme goulot d'étranglement en termes de performances, car il s'agit d'une fonction Python appelée une fois par ligne. Vous pouvez améliorer considérablement les performances en conservant les dates sous forme de texte lors de l'analyse du fichier CSV, puis en convertissant la colonne entière en dates en une seule fois :

# For a data column
df = pd.read_csv(infile, parse_dates={'mydatetime': ['date', 'time']})

df['mydatetime'] = pd.to_datetime(df['mydatetime'], exact=True, cache=True, format='%Y-%m-%d %H:%M:%S')

# For a DateTimeIndex
df = pd.read_csv(infile, parse_dates={'mydatetime': ['date', 'time']}, index_col='mydatetime')

df.index = pd.to_datetime(df.index, exact=True, cache=True, format='%Y-%m-%d %H:%M:%S')

# For a MultiIndex
df = pd.read_csv(infile, parse_dates={'mydatetime': ['date', 'time']}, index_col=['mydatetime', 'num'])

idx_mydatetime = df.index.get_level_values(0)
idx_num = df.index.get_level_values(1)
idx_mydatetime = pd.to_datetime(idx_mydatetime, exact=True, cache=True, format='%Y-%m-%d %H:%M:%S')
df.index = pd.MultiIndex.from_arrays([idx_mydatetime, idx_num])

Pour mon cas d'utilisation sur un fichier de 200 000 lignes (un horodatage par ligne), cela a réduit le temps de traitement d'environ une minute à moins d'une seconde.

1voto

Mr_and_Mrs_D Points 4569

Si la performance est importante pour vous, assurez-vous de prendre le temps :

import sys
import timeit
import pandas as pd

print('Python %s on %s' % (sys.version, sys.platform))
print('Pandas version %s' % pd.__version__)

repeat = 3
numbers = 100

def time(statement, _setup=None):
    print (min(
        timeit.Timer(statement, setup=_setup or setup).repeat(
            repeat, numbers)))

print("Format %m/%d/%y")
setup = """import pandas as pd
import io

data = io.StringIO('''\
ProductCode,Date
''' + '''\
x1,07/29/15
x2,07/29/15
x3,07/29/15
x4,07/30/15
x5,07/29/15
x6,07/29/15
x7,07/29/15
y7,08/05/15
x8,08/05/15
z3,08/05/15
''' * 100)"""

time('pd.read_csv(data); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"]); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
     'infer_datetime_format=True); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
     'date_parser=lambda x: pd.datetime.strptime(x, "%m/%d/%y")); data.seek(0)')

print("Format %Y-%m-%d %H:%M:%S")
setup = """import pandas as pd
import io

data = io.StringIO('''\
ProductCode,Date
''' + '''\
x1,2016-10-15 00:00:43
x2,2016-10-15 00:00:56
x3,2016-10-15 00:00:56
x4,2016-10-15 00:00:12
x5,2016-10-15 00:00:34
x6,2016-10-15 00:00:55
x7,2016-10-15 00:00:06
y7,2016-10-15 00:00:01
x8,2016-10-15 00:00:00
z3,2016-10-15 00:00:02
''' * 1000)"""

time('pd.read_csv(data); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"]); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
     'infer_datetime_format=True); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
     'date_parser=lambda x: pd.datetime.strptime(x, "%Y-%m-%d %H:%M:%S")); data.seek(0)')

des empreintes :

Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 03:13:28) 
[Clang 6.0 (clang-600.0.57)] on darwin
Pandas version 0.23.4
Format %m/%d/%y
0.19123052499999993
8.20691274
8.143124389
1.2384357139999977
Format %Y-%m-%d %H:%M:%S
0.5238807110000039
0.9202787830000005
0.9832778819999959
12.002349824999996

Ainsi, avec une date formatée iso8601 ( %Y-%m-%d %H:%M:%S est apparemment une date au format iso8601, je suppose que le T peut être abandonné et remplacé par un espace), vous devez no spécifier infer_datetime_format (ce qui ne fait pas de différence avec les plus courants apparemment) et le fait de passer votre propre analyseur syntaxique ne fait qu'entraver les performances. D'un autre côté, date_parser fait une différence avec les formats de jours non standard. Veillez à chronométrer avant d'optimiser, comme d'habitude.

1voto

Mykola Zotko Points 1929

Vous pouvez utiliser le paramètre date_parser avec une fonction permettant de convertir un séquence de colonnes de chaînes de caractères à un tableau d'instances de dates :

parser = lambda x: pd.to_datetime(x, format='%Y-%m-%d %H:%M:%S')
pd.read_csv('path', date_parser=parser, parse_dates=['date_col1', 'date_col2'])

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X