web-dev-qa-db-fra.com

calculer la différence de date/heure en années, mois, etc. dans une nouvelle colonne du cadre de données pandas

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.

13
beta

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
6
omri_saadon

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)
9
DeepSpace

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.

7
Avi Gelbgiser

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'))
2
Pranav Kansara

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
0
Anand S Kumar

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
0
scottlittle