web-dev-qa-db-fra.com

Comment convertir des colonnes en une seule colonne datetime dans pandas?

J'ai une trame de données où les 3 premières colonnes sont "MOIS", "JOUR", "ANNÉE"

Dans chaque colonne, il y a un entier. Existe-t-il un moyen Pythonic de convertir les trois colonnes en datetimes alors qu'il y en a dans le dataframe?

De:

M    D    Y    Apples   Oranges
5    6  1990      12        3
5    7  1990      14        4
5    8  1990      15       34
5    9  1990      23       21

dans:

Datetimes    Apples   Oranges
1990-6-5        12        3
1990-7-5        14        4
1990-8-5        15       34
1990-9-5        23       21
41
user1367204

En 0.13 (à venir très bientôt), ceci est fortement optimisé et assez rapide (mais toujours assez rapide en 0.12); les deux ordres de grandeur plus rapidement que le bouclage

In [3]: df
Out[3]: 
   M  D     Y  Apples  Oranges
0  5  6  1990      12        3
1  5  7  1990      14        4
2  5  8  1990      15       34
3  5  9  1990      23       21

In [4]: df.dtypes
Out[4]: 
M          int64
D          int64
Y          int64
Apples     int64
Oranges    int64
dtype: object

# in 0.12, use this
In [5]: pd.to_datetime((df.Y*10000+df.M*100+df.D).apply(str),format='%Y%m%d')

# in 0.13 the above or this will work
In [5]: pd.to_datetime(df.Y*10000+df.M*100+df.D,format='%Y%m%d')
Out[5]: 
0   1990-05-06 00:00:00
1   1990-05-07 00:00:00
2   1990-05-08 00:00:00
3   1990-05-09 00:00:00
dtype: datetime64[ns]
42
Jeff

Dans la version 0.18.1 vous pouvez utiliser to_datetime , mais:

  • les noms des colonnes doivent être year, month, day, hour, minute et second:
  • les colonnes minimales sont year, month et day

Échantillon:

import pandas as pd

df = pd.DataFrame({'year': [2015, 2016],
                   'month': [2, 3],
                    'day': [4, 5],
                    'hour': [2, 3],
                    'minute': [10, 30],
                    'second': [21,25]})

print df
   day  hour  minute  month  second  year
0    4     2      10      2      21  2015
1    5     3      30      3      25  2016

print pd.to_datetime(df[['year', 'month', 'day']])
0   2015-02-04
1   2016-03-05
dtype: datetime64[ns]

print pd.to_datetime(df[['year', 'month', 'day', 'hour']])
0   2015-02-04 02:00:00
1   2016-03-05 03:00:00
dtype: datetime64[ns]

print pd.to_datetime(df[['year', 'month', 'day', 'hour', 'minute']])
0   2015-02-04 02:10:00
1   2016-03-05 03:30:00
dtype: datetime64[ns]

print pd.to_datetime(df)
0   2015-02-04 02:10:21
1   2016-03-05 03:30:25
dtype: datetime64[ns]

Une autre solution est convertie en dictionary:

print df
   M  D     Y  Apples  Oranges
0  5  6  1990      12        3
1  5  7  1990      14        4
2  5  8  1990      15       34
3  5  9  1990      23       21

print pd.to_datetime(dict(year=df.Y, month=df.M, day=df.D))
0   1990-05-06
1   1990-05-07
2   1990-05-08
3   1990-05-09
dtype: datetime64[ns]
54
jezrael

Voici une alternative qui utilise arithmétique NumPy datetime64 et timedelta64 . Il semble être un peu plus rapide pour les petits DataFrames et beaucoup plus rapide pour les plus grands DataFrames:

import numpy as np
import pandas as pd

df = pd.DataFrame({'M':[1,2,3,4], 'D':[6,7,8,9], 'Y':[1990,1991,1992,1993]})
#    D  M     Y
# 0  6  1  1990
# 1  7  2  1991
# 2  8  3  1992
# 3  9  4  1993

y = np.array(df['Y']-1970, dtype='<M8[Y]')
m = np.array(df['M']-1, dtype='<m8[M]')
d = np.array(df['D']-1, dtype='<m8[D]')
dates2 = pd.Series(y+m+d)
# 0   1990-01-06
# 1   1991-02-07
# 2   1992-03-08
# 3   1993-04-09
# dtype: datetime64[ns]

In [214]: df = pd.concat([df]*1000)

In [215]: %timeit pd.to_datetime((df['Y']*10000+df['M']*100+df['D']).astype('int'), format='%Y%m%d')
100 loops, best of 3: 4.87 ms per loop

In [216]: %timeit pd.Series(np.array(df['Y']-1970, dtype='<M8[Y]')+np.array(df['M']-1, dtype='<m8[M]')+np.array(df['D']-1, dtype='<m8[D]'))
1000 loops, best of 3: 839 µs per loop

Voici une fonction d'aide pour rendre cela plus facile à utiliser:

def combine64(years, months=1, days=1, weeks=None, hours=None, minutes=None,
              seconds=None, milliseconds=None, microseconds=None, nanoseconds=None):
    years = np.asarray(years) - 1970
    months = np.asarray(months) - 1
    days = np.asarray(days) - 1
    types = ('<M8[Y]', '<m8[M]', '<m8[D]', '<m8[W]', '<m8[h]',
             '<m8[m]', '<m8[s]', '<m8[ms]', '<m8[us]', '<m8[ns]')
    vals = (years, months, days, weeks, hours, minutes, seconds,
            milliseconds, microseconds, nanoseconds)
    return sum(np.asarray(v, dtype=t) for t, v in Zip(types, vals)
               if v is not None)

In [437]: combine64(df['Y'], df['M'], df['D'])
Out[437]: array(['1990-01-06', '1991-02-07', '1992-03-08', '1993-04-09'], dtype='datetime64[D]')
7
unutbu

J'ai ré-abordé le problème et je pense avoir trouvé une solution. J'ai initialisé le fichier csv de la manière suivante:

pandas_object = DataFrame(read_csv('/Path/to/csv/file', parse_dates=True, index_col = [2,0,1] ))

Où le:

index_col = [2,0,1]

représente les colonnes de [année, mois, jour]

Le seul problème maintenant, c'est que j'ai maintenant trois nouvelles colonnes d'index, une représentant l'année, une autre le mois et une autre le jour.

2
user1367204
 [pd.to_datetime(str(a)+str(b)+str(c),
                 format='%m%d%Y'
                ) for a,b,c in Zip(df.M, df.D, df.Y)]
1
A.Kot

Convertissez la trame de données en chaînes pour une concaténation facile des chaînes:

df=df.astype(str)

puis convertissez en datetime, spécifiez le format:

df.index=pd.to_datetime(df.Y+df.M+df.D,format="%Y%m%d")

qui remplace l'index plutôt que de créer une nouvelle colonne.

0
Q-man

Supposons que vous ayez un dictionnaire foo avec chaque colonne de dates en parallèle. Si oui, voici votre doublure:

>>> from datetime import datetime
>>> foo = {"M": [1,2,3], "D":[30,30,21], "Y":[1980,1981,1982]}
>>>
>>> df = pd.DataFrame({"Datetime": [datetime(y,m,d) for y,m,d in Zip(foo["Y"],foo["M"],foo["D"])]})

Les vraies entrailles sont ce peu:

>>> [datetime(y,m,d) for y,m,d in Zip(foo["Y"],foo["M"],foo["D"])]
[datetime.datetime(1980, 1, 30, 0, 0), datetime.datetime(1981, 2, 28, 0, 0), datetime.datetime(1982, 3, 21, 0, 0)]

C'est le genre de chose pour laquelle Zip a été conçue. Il prend des listes parallèles et les transforme en tuples. Ensuite, ils obtiennent Tuple déballé (le for y,m,d in bit) par la compréhension de la liste, puis introduit dans le constructeur d'objet datetime.

pandas semble satisfait des objets datetime.

0
Dan