基于列值的Pandas Shift报错求解决:同产品日期重叠判定
问题描述
我有一个包含以下5列的Pandas DataFrame:
Product_ID, Start_Date, End_Date, Turnover, cumcount
其中Product_ID不唯一,cumcount用于记录同产品的出现次数(范围为0-5),数据已按Product_ID和Start_Date排序。由于同Product_ID的Start_Date可能存在重叠,我仅想保留与首个记录日期不重叠的条目。
我写的代码片段如下:
df= df.sort_values(by=[ "Product_ID", "Start_Date"]) check1 = df["Product_ID"] == df["Product_ID"].shift(1) conditions = [check1 & ( df["End_Date"].shift(df["cumcount"]) > df["Start_Date"]), check1 & ( df["End_Date"].shift(df["cumcount"]) < df["Start_Date"]), ~check1 ] choices = [0, 1, 1] df["result"] = np.select(conditions, choices)
设计思路是根据cumcount的值偏移对应行数,判断当前记录是否在首个记录的日期范围内,但执行时报错:
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
希望在不硬编码偏移量的前提下解决该问题。
样本数据
{'Product_ID': {0: 'CJ48HL', 1: 'CL23P3', 2: 'CL5WKS', 3: 'DA0AAM', 4: 'DA0AAM'}, 'Start_Date': {0: Timestamp('2022-02-11 00:00:00'), 1: Timestamp('2022-11-11 00:00:00'), 2: Timestamp('2022-10-24 00:00:00'), 3: Timestamp('2022-04-01 00:00:00'), 4: Timestamp('2022-04-06 00:00:00')}, 'Turnover': {0: 1143845.0, 1: 512476.0, 2: 178382.0, 3: 2104083.0, 4: 1300434.0}, 'count': {0: 0, 1: 0, 2: 0, 3: 0, 4: 1}, 'End_Date': {0: Timestamp('2022-02-25 00:00:00'), 1: Timestamp('2022-11-25 00:00:00'), 2: Timestamp('2022-11-07 00:00:00'), 3: Timestamp('2022-04-15 00:00:00'), 4: Timestamp('2022-04-20 00:00:00')}}
期望输出
Product_ID Start_Date Turnover count End_Date result 0 CJ48HL 2022-02-11 1143845.0 0 2022-02-25 1 1 CL23P3 2022-02-11 512476.0 0 2022-11-07 1 2 CL5WKS 2022-10-24 178382.0 0 2022-11-07 1 3 DA0AAM 2022-04-01 2104083.0 0 2022-04-15 1 4 DA0AAM 2022-04-06 1300434.0 1 2022-04-20 0 5 DA0AAM 2022-04-10 1451521.0 2 2022-04-24 0 6 DA0AAM 2022-04-20 2501520.0 3 2022-05-04 1
解决方案
错误原因
df["End_Date"].shift(df["cumcount"])写法有误:shift()方法仅接受单个整数作为偏移量,无法处理Series类型的动态偏移值,这导致后续布尔判断出现歧义,触发报错。
正确实现思路
要判断每条记录是否和同产品的首个记录日期不重叠,核心是先获取每个Product_ID对应的首个记录的End_Date,再用当前记录的Start_Date与该值直接比较:
- 按
Product_ID分组,提取每组的首个End_Date并广播到组内所有行 - 新组的首个记录直接标记为保留;同组其他记录,若
Start_Date大于组内首个End_Date则标记为保留,否则标记为不保留
代码实现
import pandas as pd import numpy as np # 确保数据按Product_ID和Start_Date排序(若未预先排序) df = df.sort_values(by=["Product_ID", "Start_Date"]) # 为每个Product_ID获取首个记录的End_Date,并广播到组内所有行 df['first_end_date'] = df.groupby('Product_ID')['End_Date'].transform('first') # 生成result列 df['result'] = np.where( df['cumcount'] == 0, # 组内首个记录直接标记为1 1, np.where(df['Start_Date'] > df['first_end_date'], 1, 0) # 非首个记录根据日期重叠判断 ) # 可选:删除辅助列 df = df.drop('first_end_date', axis=1)
验证结果
用样本数据测试后,会得到符合期望的输出:
- 每个产品的首个记录
result为1 - DA0AAM的第4、5条记录
Start_Date小于首个记录的End_Date(2022-04-15),result为0 - DA0AAM的第6条记录
Start_Date(2022-04-20)大于首个记录的End_Date,result为1
内容的提问来源于stack exchange,提问作者bcka
相关产品推荐
相关产品推荐

