J'ai un cadre de données de pandas ressemblant à ceci:
Name start end
A 2000-01-10 1970-04-29
Je souhaite ajouter une nouvelle colonne indiquant la différence entre les colonnes start
et end
en années, mois et jours.
Donc, le résultat devrait ressembler à:
Name start end diff
A 2000-01-10 1970-04-29 29y9m etc.
la colonne diff peut également être un objet datetime
ou un objet timedelta
, mais le point clé pour moi est que je peux facilement obtenir le Année et Mois le.
Ce que j'ai essayé jusqu'à présent c'est:
df['diff'] = df['end'] - df['start']
Cela se traduit par la nouvelle colonne contenant 10848 days
. Cependant, je ne sais pas comment convertir les jours en 29y9m etc.
Avec une fonction simple, vous pouvez atteindre votre objectif.
La fonction calcule la différence d'années et la différence de mois avec un calcul simple.
import pandas as pd
import datetime
def parse_date(td):
resYear = float(td.days)/364.0 # get the number of years including the the numbers after the dot
resMonth = int((resYear - int(resYear))*364/30) # get the number of months, by multiply the number after the dot by 364 and divide by 30.
resYear = int(resYear)
return str(resYear) + "Y" + str(resMonth) + "m"
df = pd.DataFrame([("2000-01-10", "1970-04-29")], columns=["start", "end"])
df["delta"] = [parse_date(datetime.datetime.strptime(start, '%Y-%m-%d') - datetime.datetime.strptime(end, '%Y-%m-%d')) for start, end in Zip(df["start"], df["end"])]
print df
start end delta
0 2000-01-10 1970-04-29 29Y9m
Plutôt simple avec relativedelta
:
from dateutil import relativedelta
>> end start
>> 0 1970-04-29 2000-01-10
for i in df.index:
df.at[i, 'diff'] = relativedelta.relativedelta(df.ix[i, 'start'], df.ix[i, 'end'])
>> end start diff
>> 0 1970-04-29 2000-01-10 relativedelta(years=+29, months=+8, days=+12)
Je pense que c’est la manière la plus courante de procéder, sans utiliser de boucles for ou définir des fonctions externes:
>>> df = pd.DataFrame({'Name': ['A'], 'start': [datetime(2000, 1, 10)], 'end': [datetime(1970, 4, 29)]})
>>> df['diff'] = map(lambda td: datetime(1, 1, 1) + td, list(df['start'] - df['end']))
>>> df['diff'] = df['diff'].apply(lambda d: '{0}y{1}m'.format(d.year - 1, d.month - 1))
>>> df
Name end start diff
0 A 1970-04-29 2000-01-10 29y8m
J'ai dû utiliser map au lieu d'appliquer en raison de timedelda64 des pandas, qui ne permet pas un simple ajout à un objet datetime.
Une méthode beaucoup plus simple consiste à utiliser la fonction date_range et à calculer la longueur de la même
startdt=pd.to_datetime('2017-01-01')
enddt = pd.to_datetime('2018-01-01')
len(pd.date_range(start=startdt,end=enddt,freq='M'))
Vous pouvez essayer la fonction suivante pour calculer la différence -
def yearmonthdiff(row):
s = row['start']
e = row['end']
y = s.year - e.year
m = s.month - e.month
d = s.day - e.day
if m < 0:
y = y - 1
m = m + 12
if m == 0:
if d < 0:
m = m -1
Elif d == 0:
s1 = s.hour*3600 + s.minute*60 + s.second
s2 = e.hour*3600 + e.minut*60 + e.second
if s1 < s2:
m = m - 1
return '{}y{}m'.format(y,m)
Où rangée est le dataframe row
. Je suppose que vos colonnes start
et end
sont des objets datetime
. Ensuite, vous pouvez utiliser la fonction DataFrame.apply()
pour l’appliquer à chaque ligne.
df
Out[92]:
start end
0 2000-01-10 00:00:00.000000 1970-04-29 00:00:00.000000
1 2015-07-18 17:54:59.070381 2014-01-11 17:55:10.053381
df['diff'] = df.apply(yearmonthdiff, axis=1)
In [97]: df
Out[97]:
start end diff
0 2000-01-10 00:00:00.000000 1970-04-29 00:00:00.000000 29y9m
1 2015-07-18 17:54:59.070381 2014-01-11 17:55:10.053381 1y6m
Semblable à la réponse de @ DeepSpace, voici une implémentation de type SAS:
import pandas as pd
from dateutil import relativedelta
def intck_month( start, end ):
rd = relativedelta.relativedelta( pd.to_datetime( end ), pd.to_datetime( start ) )
return rd.years, rd.months
Usage:
>> years, months = intck_month('1960-01-01', '1970-03-01')
>> print(years)
10
>> print(months)
2