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?


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.


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.


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

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'])

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


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]')

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

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

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!


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

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')
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.