我在Dataframe
中有一个Pandas
,其中包含一个字母和两个日期作为列。我想使用shift()
计算上一行的两个日期列之间的营业日,前提是Letter
值相同(使用.groupby()
)。我是用.apply()
做的。这一直有效,直到我传递了一些缺少其中一个日期的数据。我将所有内容移动到一个函数来使用try/except
子句处理缺失的值,但现在我的函数返回NaN
的所有内容。看来日期的None
值会影响函数的每次调用,而我认为只有当Letter
的{{1}}为.groupby()
时才会这样做。< / p>
A
实际输出:
import pandas as pd
from datetime import datetime
import numpy as np
def business_days(x):
try:
return pd.DataFrame(np.busday_count(x['First Date'].tolist(), x['Last Date'].tolist())).shift().reset_index(drop=True)
except ValueError:
return None
df = pd.DataFrame(data=[['A', datetime(2016, 1, 7), None],
['A', datetime(2016, 3, 1), datetime(2016, 3, 8)],
['B', datetime(2016, 5, 1), datetime(2016, 5, 10)],
['B', datetime(2016, 6, 5), datetime(2016, 6, 7)]],
columns=['Letter', 'First Date', 'Last Date'])
df['First Date'] = df['First Date'].apply(lambda x: x.to_datetime().date())
df['Last Date'] = df['Last Date'].apply(lambda x: x.to_datetime().date())
df['Gap'] = df.groupby('Letter').apply(business_days)
print df
期望的输出:
Letter First Date Last Date Gap
0 A 2016-01-07 NaT NaN
1 A 2016-03-01 2016-03-08 NaN
2 B 2016-05-01 2016-05-10 NaN
3 B 2016-06-05 2016-06-07 NaN
答案 0 :(得分:4)
暂时忽略NaT
,请注意np.busday_count
计算
在应用df
之前,可以在groupby
的整列上完成。这将
节省时间,因为这取代了许多对np.busday_count
的呼叫(每个呼叫一个)
只需拨打一次np.busday_count
即可。一个函数调用应用于a
大数组通常比小数组上的许多函数调用快。
要处理NaT
,您可以使用pd.notnull
来识别哪些行
拥有NaT
并屏蔽First Date
和Last Date
s,以便只有效
日期将发送至np.busday_count
。然后,您可以填写NaN
s
日期为NaT
s的行。
在我们计算了所有营业日计数后,我们需要做的就是分组
Letter
和将值向下移动。这可以做到
groupby/transform('shift')
。
import datetime as DT
import numpy as np
import pandas as pd
def business_days(start, end):
mask = pd.notnull(start) & pd.notnull(end)
start = start.values.astype('datetime64[D]')[mask]
end = end.values.astype('datetime64[D]')[mask]
result = np.empty(len(mask), dtype=float)
result[mask] = np.busday_count(start, end)
result[~mask] = np.nan
return result
df = pd.DataFrame(data=[['A', DT.datetime(2016, 1, 7), None],
['A', DT.datetime(2016, 3, 1), DT.datetime(2016, 3, 8)],
['B', DT.datetime(2016, 5, 1), DT.datetime(2016, 5, 10)],
['B', DT.datetime(2016, 6, 5), DT.datetime(2016, 6, 7)]],
columns=['Letter', 'First Date', 'Last Date'])
df['Gap'] = business_days(df['First Date'], df['Last Date'])
print(df)
# Letter First Date Last Date Gap
# 0 A 2016-01-07 NaT NaN
# 1 A 2016-03-01 2016-03-08 5.0
# 2 B 2016-05-01 2016-05-10 6.0
# 3 B 2016-06-05 2016-06-07 1.0
df['Gap'] = df.groupby('Letter')['Gap'].transform('shift')
print(df)
打印
Letter First Date Last Date Gap
0 A 2016-01-07 NaT NaN
1 A 2016-03-01 2016-03-08 NaN
2 B 2016-05-01 2016-05-10 NaN
3 B 2016-06-05 2016-06-07 6.0