熊猫:减去两个日期列,结果是一个整数
Posted
技术标签:
【中文标题】熊猫:减去两个日期列,结果是一个整数【英文标题】:Pandas: Subtracting two date columns and the result being an integer 【发布时间】:2016-10-16 21:15:49 【问题描述】:我在 Pandas 数据框中有两列是日期。
我希望从另一列中减去一列,结果是天数的差异作为整数。
查看数据:
df_test.head(10)
Out[20]:
First_Date Second Date
0 2016-02-09 2015-11-19
1 2016-01-06 2015-11-30
2 NaT 2015-12-04
3 2016-01-06 2015-12-08
4 NaT 2015-12-09
5 2016-01-07 2015-12-11
6 NaT 2015-12-12
7 NaT 2015-12-14
8 2016-01-06 2015-12-14
9 NaT 2015-12-15
我已经成功创建了一个新列,不同之处:
df_test['Difference'] = df_test['First_Date'].sub(df_test['Second Date'], axis=0)
df_test.head()
Out[22]:
First_Date Second Date Difference
0 2016-02-09 2015-11-19 82 days
1 2016-01-06 2015-11-30 37 days
2 NaT 2015-12-04 NaT
3 2016-01-06 2015-12-08 29 days
4 NaT 2015-12-09 NaT
但是我无法获得结果的数字版本:
df_test['Difference'] = df_test[['Difference']].apply(pd.to_numeric)
df_test.head()
Out[25]:
First_Date Second Date Difference
0 2016-02-09 2015-11-19 7.084800e+15
1 2016-01-06 2015-11-30 3.196800e+15
2 NaT 2015-12-04 NaN
3 2016-01-06 2015-12-08 2.505600e+15
4 NaT 2015-12-09 NaN
【问题讨论】:
【参考方案1】:你可以将dtype
timedelta
的列除以np.timedelta64(1, 'D')
,但输出不是int
,而是float
,因为NaN
values:
df_test['Difference'] = df_test['Difference'] / np.timedelta64(1, 'D')
print (df_test)
First_Date Second Date Difference
0 2016-02-09 2015-11-19 82.0
1 2016-01-06 2015-11-30 37.0
2 NaT 2015-12-04 NaN
3 2016-01-06 2015-12-08 29.0
4 NaT 2015-12-09 NaN
5 2016-01-07 2015-12-11 27.0
6 NaT 2015-12-12 NaN
7 NaT 2015-12-14 NaN
8 2016-01-06 2015-12-14 23.0
9 NaT 2015-12-15 NaN
Frequency conversion.
【讨论】:
【参考方案2】:您可以在这里使用 datetime 模块提供帮助。另外,附带说明一下,简单的日期减法应该如下所示:
import datetime as dt
import numpy as np
import pandas as pd
#Assume we have df_test:
In [222]: df_test
Out[222]:
first_date second_date
0 2016-01-31 2015-11-19
1 2016-02-29 2015-11-20
2 2016-03-31 2015-11-21
3 2016-04-30 2015-11-22
4 2016-05-31 2015-11-23
5 2016-06-30 2015-11-24
6 NaT 2015-11-25
7 NaT 2015-11-26
8 2016-01-31 2015-11-27
9 NaT 2015-11-28
10 NaT 2015-11-29
11 NaT 2015-11-30
12 2016-04-30 2015-12-01
13 NaT 2015-12-02
14 NaT 2015-12-03
15 2016-04-30 2015-12-04
16 NaT 2015-12-05
17 NaT 2015-12-06
In [223]: df_test['Difference'] = df_test['first_date'] - df_test['second_date']
In [224]: df_test
Out[224]:
first_date second_date Difference
0 2016-01-31 2015-11-19 73 days
1 2016-02-29 2015-11-20 101 days
2 2016-03-31 2015-11-21 131 days
3 2016-04-30 2015-11-22 160 days
4 2016-05-31 2015-11-23 190 days
5 2016-06-30 2015-11-24 219 days
6 NaT 2015-11-25 NaT
7 NaT 2015-11-26 NaT
8 2016-01-31 2015-11-27 65 days
9 NaT 2015-11-28 NaT
10 NaT 2015-11-29 NaT
11 NaT 2015-11-30 NaT
12 2016-04-30 2015-12-01 151 days
13 NaT 2015-12-02 NaT
14 NaT 2015-12-03 NaT
15 2016-04-30 2015-12-04 148 days
16 NaT 2015-12-05 NaT
17 NaT 2015-12-06 NaT
现在,将类型更改为 datetime.timedelta,然后对有效的 timedelta 对象使用 .days 方法。
In [226]: df_test['Diffference'] = df_test['Difference'].astype(dt.timedelta).map(lambda x: np.nan if pd.isnull(x) else x.days)
In [227]: df_test
Out[227]:
first_date second_date Difference Diffference
0 2016-01-31 2015-11-19 73 days 73
1 2016-02-29 2015-11-20 101 days 101
2 2016-03-31 2015-11-21 131 days 131
3 2016-04-30 2015-11-22 160 days 160
4 2016-05-31 2015-11-23 190 days 190
5 2016-06-30 2015-11-24 219 days 219
6 NaT 2015-11-25 NaT NaN
7 NaT 2015-11-26 NaT NaN
8 2016-01-31 2015-11-27 65 days 65
9 NaT 2015-11-28 NaT NaN
10 NaT 2015-11-29 NaT NaN
11 NaT 2015-11-30 NaT NaN
12 2016-04-30 2015-12-01 151 days 151
13 NaT 2015-12-02 NaT NaN
14 NaT 2015-12-03 NaT NaN
15 2016-04-30 2015-12-04 148 days 148
16 NaT 2015-12-05 NaT NaN
17 NaT 2015-12-06 NaT NaN
希望对您有所帮助。
【讨论】:
是的,这是一种可能的解决方案,但我认为这是不推荐的方法,因为列Diffference
的输出是 object
并且下一个处理(加法、减法...)是不可能的。
@jesrael,还有其他方法,例如您的解决方案。但是,对于 NaN 与列中的 int 类型混合,加/减不是问题。它们将根据需要自动转换为浮动操作。【参考方案3】:
怎么样:
df_test['Difference'] = (df_test['First_Date'] - df_test['Second Date']).dt.days
如果没有缺失值(NaT
)和float
(如果有),这将返回差异为int
。
Pandas 在 Time series / date functionality 和 Time deltas 上有丰富的文档
【讨论】:
同意@AllenWang。这是最好的答案。 @至少有 3 个建议这是公认的答案 这在最近的版本中可能有所改变。现在使用.days
对我有用,而.dt.days
会引发错误
看来它取决于结果值。如果它们是日期时间序列,则需要 .dt
。你能检查表达式的结果吗?它是 DataFrame 还是 Series?我仍在试图弄清楚何时需要 dt
这似乎只能工作几天,而不是几周或几年。【参考方案4】:
我觉得如果日期“环绕”一年左右,则总体答案无法处理。这将有助于了解接近日期的日期是否准确。为了进行这些行操作,我做了以下操作。 (我在商业环境中使用它来更新客户订阅)。
def get_date_difference(row, x, y):
try:
# Calcuating the smallest date difference between the start and the close date
# There's some tricky logic in here to calculate for determining date difference
# the other way around (Dec -> Jan is 1 month rather than 11)
sub_start_date = int(row[x].strftime('%j')) # day of year (1-366)
close_date = int(row[y].strftime('%j')) # day of year (1-366)
later_date_of_year = max(sub_start_date, close_date)
earlier_date_of_year = min(sub_start_date, close_date)
days_diff = later_date_of_year - earlier_date_of_year
# Calculates the difference going across the next year (December -> Jan)
days_diff_reversed = (365 - later_date_of_year) + earlier_date_of_year
return min(days_diff, days_diff_reversed)
except ValueError:
return None
那么函数可以是:
dfAC_Renew['date_difference'] = dfAC_Renew.apply(get_date_difference, x = 'customer_since_date', y = 'renewal_date', axis = 1)
【讨论】:
【参考方案5】:创建矢量化方法
def calc_xb_minus_xa(df):
time_dict =
'<Minute>': 'm',
'<Hour>': 'h',
'<Day>': 'D',
'<Week>': 'W',
'<Month>': 'M',
'<Year>': 'Y'
time_delta = df.at[df.index[0], 'end_time'] - df.at[df.index[0], 'open_time']
offset_base_name = str(to_offset(time_delta).base)
time_term = time_dict.get(offset_base_name)
result = (df.end_time - df.open_time) / np.timedelta64(1, time_term)
return result
然后在你的 df 中做:
df['x'] = calc_xb_minus_xa(df)
这将适用于分钟、小时、天、周、月和年。 open_time 和 end_time 需要根据你的 df 改变
【讨论】:
以上是关于熊猫:减去两个日期列,结果是一个整数的主要内容,如果未能解决你的问题,请参考以下文章