我有一个非常简单的问题。我有一个包含多种产品的数据集,以及它们的价格随时间的变化情况。现在我需要确定价格在连续几天内不变的时期(不包括周末 - >因此周五和周一是连续的)。
数据集:
身份证 | 日期 | 价格 |
---|---|---|
1 | 2024-02-01 | 1,00 |
1 | 2024-02-04 | 1,00 |
1 | 2024-02-05 | 1,20 |
1 | 2024-02-06 | 1,30 |
1 | 2024-02-07 | 1,30 |
2 | 2024-02-01 | 1,30 |
2 | 2024-02-04 | 0,90 |
2 | 2024-02-05 | 0,90 |
2 | 2024-02-06 | 0,90 |
2 | 2024-02-07 | 1,30 |
我的输出应该看起来像这样:
身份证 | 开始日期 | 结束日期 | 价格 | 重复天数 |
---|---|---|---|---|
1 | 2024-02-01 | 2024-02-04 | 1,00 | 2 |
1 | 2024-02-06 | 2024-02-07 | 1,30 | 2 |
2 | 2024-02-04 | 2024-02-06 | 0,90 | 3 |
如你所见,我需要避免以下问题:
shift().cumsum()
因此在此不起作用。有什么想法吗?也许是
shift().cumsum()
但仅限于每个 ID 内?
到目前为止,我尝试了第一个
shift().cumsum()
的一些变体
然后groupby().agg({"date": ["min", "max"], "price": "size"}
但没有一个能同时解决上述问题。
你可以尝试:
def get_next_day(d):
d += pd.Timedelta("1 day")
if d.dayofweek == 4:
d += pd.Timedelta("2 days")
elif d.dayofweek == 5:
d += pd.Timedelta("1 day")
return d
def yield_group(g):
if len(g) > 1:
yield {
"ID": g[0][0],
"start_date": g[0][1],
"end_date": g[-1][1],
"price": g[0][2],
"repeated_days_count": len(g),
}
def generate_groups(ids, dates, prices):
current_group = []
prev_id = None
prev_price = None
expected_next_day = None
for i, d, p in zip(ids, dates, prices):
if prev_id is None:
current_group.append((i, d, p))
elif expected_next_day != d or prev_id != i or prev_price != p:
yield from yield_group(current_group)
current_group = [(i, d, p)]
else:
current_group.append((i, d, p))
prev_id = i
prev_price = p
expected_next_day = get_next_day(d)
yield from yield_group(current_group)
df["Date"] = pd.to_datetime(df["Date"])
out = pd.DataFrame(generate_groups(df["ID"], df["Date"], df["Price"]))
print(out)
打印:
ID start_date end_date price repeated_days_count
0 1 2024-02-01 2024-02-04 1,00 2
1 1 2024-02-06 2024-02-07 1,30 2
2 2 2024-02-04 2024-02-06 0,90 3