Extraire uniquement le mois et l'année séparément de la colonne Pandas Datetime

221

J'ai un Dataframe, df, avec la colonne suivante:

df['ArrivalDate'] =
...
936   2012-12-31
938   2012-12-29
965   2012-12-31
966   2012-12-31
967   2012-12-31
968   2012-12-31
969   2012-12-31
970   2012-12-29
971   2012-12-31
972   2012-12-29
973   2012-12-29
...

Les éléments de la colonne sont pandas.tslib.Timestamp.

Je veux juste inclure l'année et le mois. Je pensais qu'il y aurait un moyen simple de le faire, mais je ne peux pas le comprendre.

Voici ce que j'ai essayé:

df['ArrivalDate'].resample('M', how = 'mean')

J'ai eu l'erreur suivante:

Only valid with DatetimeIndex or PeriodIndex 

J'ai ensuite essayé:

df['ArrivalDate'].apply(lambda(x):x[:-2])

J'ai eu l'erreur suivante:

'Timestamp' object has no attribute '__getitem__' 

Aucune suggestion?

Edit: j'ai en quelque sorte compris.

df.index = df['ArrivalDate']

Ensuite, je peux rééchantillonner une autre colonne en utilisant l'index.

Mais j'aimerais toujours une méthode pour reconfigurer la colonne entière. Des idées?

monkeybiz7
la source
11
la meilleure réponse est clairement .. df ['mnth_yr'] = df.date_column.dt.to_period ('M') comme ci-dessous de @ jaknap32
ihightower
1
Vous n'avez même pas à faire to_period: df.date_column.dt.month(ou .year, ou .day) travaux
elz
2
@elphz: .dt.monthperd cependant l'année. Et .dt.to_period('M')change le type de données en quelque chose qui n'est plus un datetime64. J'ai fini par utiliser la réponse de Juan suggérant .astype('datetime64[M]')de tronquer les valeurs.
Nickolay
Pouvez-vous changer la meilleure réponse?
Gonzalo Garcia

Réponses:

306

Si vous souhaitez de nouvelles colonnes affichant l'année et le mois séparément, vous pouvez le faire:

df['year'] = pd.DatetimeIndex(df['ArrivalDate']).year
df['month'] = pd.DatetimeIndex(df['ArrivalDate']).month

ou...

df['year'] = df['ArrivalDate'].dt.year
df['month'] = df['ArrivalDate'].dt.month

Ensuite, vous pouvez les combiner ou travailler avec eux tels quels.

KieranPC
la source
7
Existe-t-il un moyen de le faire sur une seule ligne? Je veux éviter de parcourir plusieurs fois la même colonne.
fixxxer
2
Une analyse comparative rapide avec timeitsuggère que l' DatetimeIndexapproche est beaucoup plus rapide que l'un .map/.applyou l' autre .dt.
Snorfalorpagus
2
la meilleure réponse est clairement .. df ['mnth_yr'] = df.date_column.dt.to_period ('M') comme ci-dessous de @ jaknap32
ihightower
que fait réellement pd.Datetimeindex?
JOHN
Je fais parfois ceci: df['date_column_trunc'] = df[date_column'].apply(lambda s: datetime.date(s.year, s.month, 1)
Stewbaca
229

Le meilleur moyen trouvé !!

le df['date_column']doit être au format date-heure.

df['month_year'] = df['date_column'].dt.to_period('M')

Vous pouvez également utiliser Dpour le jour, 2Mpendant 2 mois, etc. pour différents intervalles d'échantillonnage, et dans le cas où l'on a des données de série chronologique avec horodatage, nous pouvons opter pour des intervalles d'échantillonnage granulaires tels que 45Min45 min, 15Min15 min d'échantillonnage, etc.

kabrapankaj32
la source
8
Notez que la colonne résultante n'est plus du type datetime64dtype. Utiliser df.my_date_column.astype('datetime64[M]'), comme dans @ Juan, la réponse se convertit en dates représentant le premier jour de chaque mois.
Nickolay
3
Je suis surpris que ce soit là-bas.
Tim
154

Vous pouvez accéder directement aux attributs yearet month, ou demander datetime.datetime:

In [15]: t = pandas.tslib.Timestamp.now()

In [16]: t
Out[16]: Timestamp('2014-08-05 14:49:39.643701', tz=None)

In [17]: t.to_pydatetime() #datetime method is deprecated
Out[17]: datetime.datetime(2014, 8, 5, 14, 49, 39, 643701)

In [18]: t.day
Out[18]: 5

In [19]: t.month
Out[19]: 8

In [20]: t.year
Out[20]: 2014

Une façon de combiner année et mois est de faire un entier les encodant, comme: 201408pour août 2014. Le long d'une colonne entière, vous pouvez le faire comme:

df['YearMonth'] = df['ArrivalDate'].map(lambda x: 100*x.year + x.month)

ou de nombreuses variantes de celui-ci.

Cependant, je ne suis pas un grand fan de cela, car cela rend l'alignement des dates et l'arithmétique douloureux plus tard et particulièrement douloureux pour les autres qui rencontrent votre code ou vos données sans cette même convention. Une meilleure façon est de choisir une convention de jour du mois, comme le dernier jour de semaine non américain, ou le premier jour, etc., et de laisser les données dans un format date / heure avec la convention de date choisie.

Le calendarmodule est utile pour obtenir la valeur numérique de certains jours comme le dernier jour de la semaine. Ensuite, vous pourriez faire quelque chose comme:

import calendar
import datetime
df['AdjustedDateToEndOfMonth'] = df['ArrivalDate'].map(
    lambda x: datetime.datetime(
        x.year,
        x.month,
        max(calendar.monthcalendar(x.year, x.month)[-1][:5])
    )
)

Si vous cherchez un moyen de résoudre le problème plus simple de simplement formater la colonne datetime en une représentation chaîne, pour cela, vous pouvez simplement utiliser la strftimefonction de la datetime.datetimeclasse, comme ceci:

In [5]: df
Out[5]: 
            date_time
0 2014-10-17 22:00:03

In [6]: df.date_time
Out[6]: 
0   2014-10-17 22:00:03
Name: date_time, dtype: datetime64[ns]

In [7]: df.date_time.map(lambda x: x.strftime('%Y-%m-%d'))
Out[7]: 
0    2014-10-17
Name: date_time, dtype: object
ely
la source
4
Les performances peuvent être mauvaises, il est donc toujours bon de faire le meilleur usage possible des fonctions d'assistance, des opérations vectorisées et des pandastechniques de fractionnement-application-combinaison. Mes suggestions ci-dessus ne sont pas censées être considérées comme une approbation du fait que ce sont les approches les plus performantes pour votre cas - juste qu'elles sont des choix Pythoniques stylistiquement valables pour une gamme de cas.
ely
La réponse ci-dessous par @KieranPC est beaucoup plus rapide
Ben
2
la meilleure réponse est clairement .. df ['mnth_yr'] = df.date_column.dt.to_period ('M') comme ci-dessous de @ jaknap32
ihightower
2
Vous êtes censé multiplier par 100 po df['YearMonth'] = df['ArrivalDate'].map(lambda x: 1000*x.year + x.month).
Git Gud
1
@ zthomas.nc Je pense qu'ils fonctionnent mieux comme deux réponses distinctes, car ils offrent deux façons très différentes de le résoudre.
le
34

Si vous voulez la paire unique mois-année, l'utilisation de Apply est assez élégante.

df['mnth_yr'] = df['date_column'].apply(lambda x: x.strftime('%B-%Y')) 

Sorties mois-année dans une colonne.

N'oubliez pas de changer d'abord le format en date-heure avant, j'oublie généralement.

df['date_column'] = pd.to_datetime(df['date_column'])
kabrapankaj32
la source
Vous pouvez également éviter la fonction lambda:df['month_year'] = df['date_column'].dt.strftime('%B-%Y')
Rishabh
13

Extraire le dire de l'année du ['2018-03-04']

df['Year'] = pd.DatetimeIndex(df['date']).year  

Le df ['Year'] crée une nouvelle colonne. Alors que si vous voulez extraire le mois, utilisez simplement .month

Douglas
la source
1
Merci, Cela a été très utile date_1 = pd.DatetimeIndex (df ['date']) --year = date_1.year # Pour les années-- --month = date_1.month # Pour les mois-- --dy = date_1. day # Pendant jours--
Edwin Torres
7

Vous pouvez d'abord convertir vos chaînes de date avec pandas.to_datetime , ce qui vous donne accès à toutes les fonctions numpy datetime et timedelta . Par exemple:

df['ArrivalDate'] = pandas.to_datetime(df['ArrivalDate'])
df['Month'] = df['ArrivalDate'].values.astype('datetime64[M]')
Juan A. Navarro
la source
Cela a très bien fonctionné pour moi, car je cherchais des fonctionnalités analogues à celles de pyspark trunc. Y a-t-il une documentation pour la astype('datetime64[M]')convention?
h1-the-swan
6

Grâce à jaknap32 , je voulais agréger les résultats selon l'année et le mois, donc cela a fonctionné:

df_join['YearMonth'] = df_join['timestamp'].apply(lambda x:x.strftime('%Y%m'))

La sortie était soignée:

0    201108
1    201108
2    201108
Subspacien
la source
6

La solution de @ KieranPC est la bonne approche pour les pandas, mais n'est pas facilement extensible pour des attributs arbitraires. Pour cela, vous pouvez utiliser getattrau sein d'une compréhension de générateur et combiner en utilisant pd.concat:

# input data
list_of_dates = ['2012-12-31', '2012-12-29', '2012-12-30']
df = pd.DataFrame({'ArrivalDate': pd.to_datetime(list_of_dates)})

# define list of attributes required    
L = ['year', 'month', 'day', 'dayofweek', 'dayofyear', 'weekofyear', 'quarter']

# define generator expression of series, one for each attribute
date_gen = (getattr(df['ArrivalDate'].dt, i).rename(i) for i in L)

# concatenate results and join to original dataframe
df = df.join(pd.concat(date_gen, axis=1))

print(df)

  ArrivalDate  year  month  day  dayofweek  dayofyear  weekofyear  quarter
0  2012-12-31  2012     12   31          0        366           1        4
1  2012-12-29  2012     12   29          5        364          52        4
2  2012-12-30  2012     12   30          6        365          52        4
jpp
la source
1
df['year_month']=df.datetime_column.apply(lambda x: str(x)[:7])

Cela a bien fonctionné pour moi, je ne pensais pas que les pandas interpréteraient la date de chaîne résultante comme une date, mais quand j'ai fait l'intrigue, il connaissait très bien mon agenda et la chaîne year_month était correctement commandée ... je dois aimer les pandas!

TICH
la source
1

Il y a deux étapes pour extraire l'année pour toutes les trames de données sans utiliser de méthode.

Étape 1

convertir la colonne en datetime:

df['ArrivalDate']=pd.to_datetime(df['ArrivalDate'], format='%Y-%m-%d')

Étape 2

extraire l'année ou le mois en utilisant la DatetimeIndex()méthode

 pd.DatetimeIndex(df['ArrivalDate']).year
abdellah el atouani
la source
1

SINGLE LINE: Ajout d'une colonne avec des paires 'année-mois': ('pd.to_datetime' change d'abord le type de colonne en date-heure avant l'opération)

df['yyyy-mm'] = pd.to_datetime(df['ArrivalDate']).dt.strftime('%Y-%m')

En conséquence, pour une colonne supplémentaire «année» ou «mois»:

df['yyyy'] = pd.to_datetime(df['ArrivalDate']).dt.strftime('%Y')

df['mm'] = pd.to_datetime(df['ArrivalDate']).dt.strftime('%m')
Matthi9000
la source