我有一个带有日期的数据框,我想选择每周中除周末之外的最高日期(因此,星期五,如果有的话),除非没有周一至周五的数据,而只有周六/周日
可以像这样设置样本数据:
dates = pd.Series(data=['2018-11-05', '2018-11-06', '2018-11-07', '2018-11-08', '2018-11-09',
'2018-11-12', '2018-11-13', '2018-11-14', '2018-11-15', '2018-11-17',
'2018-11-19',
'2018-12-01',
])
nums = np.random.randint(50, 100, 12)
# nums
# array([95, 80, 81, 51, 98, 62, 50, 55, 59, 77, 69])
df = pd.DataFrame(data={'dates': dates, 'nums': nums})
df['dates'] = pd.to_datetime(df['dates'])
我想要的记录:
我当前的解决方案在answer below中,但我认为它不是理想的解决方案,并且存在一些我必须解决的问题。简而言之,它是:
df.groupby(df['dates'].dt.week).apply(some_function)
理想情况下,我想要一种书写方式:
[latest Mon-Fri record] if [has Mon-Fri record] else [latest Sat-Sun record]
答案 0 :(得分:1)
创建一个新的工作日层次结构,其中周六和周日的优先级最低。然后在这个新排名上sort_values
+ groupby
+ .tail(1)
。
import numpy as np
wd_map = dict(zip(np.arange(0,7,1), np.roll(np.arange(0,7,1),-2)))
# {0: 2, 1: 3, 2: 4, 3: 5, 4: 6, 5: 0, 6: 1}
df = df.assign(day_mapped = df.dates.dt.weekday.map(wd_map)).sort_values('day_mapped')
df.groupby(df.dates.dt.week).tail(1).sort_index()
dates nums day_mapped
4 2018-11-09 57 6
8 2018-11-15 83 5
10 2018-11-19 96 2
11 2018-12-01 66 0
如果数据跨越多年,则需要将Year
+ week
归为一组。
答案 1 :(得分:0)
我编写了一个函数来选择本周的有效最高记录,这需要在每周分组依据上使用:
def last_valid_report(recs):
if len(recs) == 1:
return recs
recs = recs.copy()
# recs = recs[recs['dates'].dt.weekday <= 4].nlargest(1, recs['dates'].dt.weekday) # doesn't work
recs['weekday'] = recs['dates'].dt.weekday # because nlargest() needs a column name
recs = recs[recs['weekday'] <= 4].nlargest(1, 'weekday')
del recs['weekday']
return recs
# could have also done:
# return recs[recs['weekday'] <= 4].nlargest(1, 'weekday').drop('weekday', axis=1)
用正确的组调用它,我得到:
In [155]: df2 = df.groupby(df['dates'].dt.week).apply(last_valid_report)
In [156]: df2
Out[156]:
dates nums
dates
45 4 2018-11-09 63
46 8 2018-11-15 90
47 10 2018-11-19 80
48 11 2018-12-01 94
与此相关的问题:
如果我不放recs.copy()
,我会得到ValueError: Shape of passed values is (3, 12), indices imply (3, 4)
pandas' nlargest
仅使用列名,而不使用表达式。
.apply()
之后。 我从groupby+apply获得了一个额外的索引列“日期”,,需要为explicitly dropped :
In [157]: df2.index = df2.index.droplevel(); df2
Out[157]:
dates nums
4 2018-11-09 63
8 2018-11-15 90
10 2018-11-19 80
11 2018-12-01 94
如果我获得了包含星期六和星期日数据(两天)的记录,则需要添加检查recs[recs['weekday'] <= 4]
是否为空,然后仅使用.nlargest(1, 'weekday')
而不会过滤掉{{1 }};但这不是问题的重点。