在新的 pandas 数据框列中以年、月等计算日期时间差异
calculate datetime-difference in years, months, etc. in a new pandas dataframe column
我有一个 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
对象,但对我来说关键是,我可以轻松获得 Year和月份。
到目前为止我尝试的是:
df['diff'] = df['end'] - df['start']
这导致包含 10848 days
的新列。但是,我不知道如何将天数转换为 29y9m 等
一个简单的功能就可以达到你的目标。
函数计算年差和月差,计算简单
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
使用 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)
你可以试试下面的函数来计算差值-
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 是数据框 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
我认为这是最'pandas'的方法,无需使用任何 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 不允许对日期时间对象进行简单添加,因此不得不使用 map 而不是 apply。
与@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
一种更简单的方法是使用 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'))
您可以尝试以这种方式创建一个包含年份的新列:
df['diff_year'] = df['diff'] / np.timedelta64(1, 'Y')
你实际上做的是减去日期,然后你得到天数,将天数转换成一个字符串并用“”分割,从结果列表中,天数是列表中的第一项。将其转换为整数并除以 365。
ad['yrs']=(ad.last_dt-ad.dt).apply(lambda x: str(x).split(' ')[0]).apply(lambda x: int(x)/365)
我有一个 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
对象,但对我来说关键是,我可以轻松获得 Year和月份。
到目前为止我尝试的是:
df['diff'] = df['end'] - df['start']
这导致包含 10848 days
的新列。但是,我不知道如何将天数转换为 29y9m 等
一个简单的功能就可以达到你的目标。
函数计算年差和月差,计算简单
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
使用 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)
你可以试试下面的函数来计算差值-
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 是数据框 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
我认为这是最'pandas'的方法,无需使用任何 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 不允许对日期时间对象进行简单添加,因此不得不使用 map 而不是 apply。
与@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
一种更简单的方法是使用 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'))
您可以尝试以这种方式创建一个包含年份的新列:
df['diff_year'] = df['diff'] / np.timedelta64(1, 'Y')
你实际上做的是减去日期,然后你得到天数,将天数转换成一个字符串并用“”分割,从结果列表中,天数是列表中的第一项。将其转换为整数并除以 365。
ad['yrs']=(ad.last_dt-ad.dt).apply(lambda x: str(x).split(' ')[0]).apply(lambda x: int(x)/365)