2015-07-18 17 views
12

Ho un dataframe panda simile a questo:calcolare datetime-differenza di anni, mesi, ecc in una nuova panda dataframe colonna

Name start  end 
A  2000-01-10 1970-04-29 

voglio aggiungere una nuova colonna che fornisce la differenza tra il start e Colonna end in anni, mesi, giorni.

Così il risultato dovrebbe essere simile:

Name start  end   diff 
A  2000-01-10 1970-04-29 29y9m etc. 

colonna diff può anche essere un oggetto datetime o un oggetto di timedelta, ma il punto chiave per me è che posso facilmente ottenere l'anno e Mese fuori.

Quello che ho cercato fino ad ora è:

df['diff'] = df['end'] - df['start'] 

Il risultato è la nuova colonna contenente 10848 days. Tuttavia, non so come convertire i giorni in 29y9m ecc.

risposta

6

Con una semplice funzione è possibile raggiungere il proprio obiettivo.

La funzione calcola la differenza di anni e la differenza di mesi con un semplice calcolo.

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 
7

Praticamente semplice con 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) 
0

si può provare la seguente funzione per calcolare la differenza -

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) 

Dove riga è il dataframe row. Suppongo che le tue colonne start e end siano oggetti datetime. Quindi è possibile utilizzare la funzione DataFrame.apply() per applicarla a ciascuna riga.

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

'" Non riesco a pensare ad alcuna funzione diretta che dia il diff in anni e mesi "' Vedi 'relativedelta' nella mia risposta – DeepSpace

7

penso che questo sia il piu 'panda' modo per farlo, senza utilizzare alcun cicli for e definire le funzioni esterne:

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

dovuto usare la mappa al posto di applicazione a causa della timedelda64 panda , che non consente una semplice aggiunta a un oggetto datetime.

0

Simile a @ di DeepSpace risposta, ecco un'implementazione SAS simile:

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 
2

Un modo molto più semplice è quello di utilizzare DATE_RANGE funzione e calcolare la lunghezza dello stesso

startdt=pd.to_datetime('2017-01-01') enddt = pd.to_datetime('2018-01-01') len(pd.date_range(start=startdt,end=enddt,freq='M'))

+0

Questa è una soluzione molto semplice se si sta già lavorando con i panda nel progetto. –

Problemi correlati