вычислить разницу даты и времени в годах, месяцах и т. д. в новом столбце фрейма данных pandas

У меня есть фреймворк pandas, который выглядит так:

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

Я хочу добавить новый столбец, в котором будет указана разница между столбцами start и end в годах, месяцах и днях.

Итак, результат должен выглядеть так:

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

столбец diff также может быть объектом datetime или timedelta, но ключевым моментом для меня является то, что я могу легко получить из него год и месяц.

До сих пор я пробовал:

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

В результате появится новый столбец, содержащий 10848 days. Однако я не знаю, как преобразовать дни в 29y9m и т. Д.


person beta    schedule 18.07.2015    source источник


Ответы (7)


С помощью простой функции вы можете достичь своей цели.

Функция вычисляет разницу в годах и месяцах с помощью простого вычисления.

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
person omri_saadon    schedule 18.07.2015

Вы можете попробовать создать новый столбец с годами следующим образом:

df['diff_year'] = df['diff'] / np.timedelta64(1, 'Y')
person jomesoke    schedule 29.01.2020

С 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)
person DeepSpace    schedule 18.07.2015

Более простой способ - использовать функцию date_range и рассчитать длину того же

startdt=pd.to_datetime('2017-01-01')
enddt = pd.to_datetime('2018-01-01')
len(pd.date_range(start=startdt,end=enddt,freq='M'))
person Pranav Kansara    schedule 04.04.2017
comment
Это действительно простое решение, если вы уже работаете с пандами в проекте. - person Gunay Anach; 06.09.2017

Я думаю, что это самый «пандийский» способ сделать это без использования циклов for или определения внешних функций:

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

Пришлось использовать карту вместо применения из-за pandas timedelda64, который не позволяет простое добавление к объекту datetime.

person Avi Gelbgiser    schedule 18.07.2015

Вы можете попробовать следующую функцию, чтобы вычислить разницу -

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)

Где строка - это фрейм данных row. Я предполагаю, что ваши столбцы start и end являются объектами datetime. Затем вы можете использовать функцию DataFrame.apply(), чтобы применить ее к каждой строке.

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
person Anand S Kumar    schedule 18.07.2015
comment
"I cannot think of any direct functions that give the difference in years and months" См. relativedelta в моем ответе - person DeepSpace; 18.07.2015

Подобно ответу @ DeepSpace, здесь реализация в стиле 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

Использование:

>> years, months = intck_month('1960-01-01', '1970-03-01')
>> print(years)
10
>> print(months)
2
person scottlittle    schedule 22.03.2017