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
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]
Dans la version 0.18.1
vous pouvez utiliser to_datetime
, mais:
year
, month
, day
, hour
, minute
et second
: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]
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]')
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.
[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)]
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.
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.