Pandas中cannot reindex from a duplicate axis错误解决及分组滚动统计
搞定Pandas分组滚动最大/最小值的ValueError问题
嘿,我刚碰到过一模一样的问题,来给你捋捋怎么解决!
为啥会报错?
你遇到的ValueError: cannot reindex from a duplicate axis,说白了就是循环里赋值的时候出了问题:你用df.loc[df['Type'].eq(v)]筛出来的子集,带着原DataFrame的索引,当原数据有重复索引,或者Pandas在对齐索引时遇到重复匹配的情况,就会直接炸锅——它不知道该怎么把子集的结果对应到原表的每一行。
靠谱的解决办法
方法1:用groupby+transform(强烈推荐,不用写循环!)
这是最简洁高效的方式,直接按Type分组后,用transform把滚动计算的结果自动对齐到原表的对应行:
# 计算分组后的15分钟滚动最大值 df['Prev15minMax'] = df.groupby('Type')['Last'].transform( lambda x: x.rolling('15min', min_periods=16).max() ) # 计算分组后的15分钟滚动最小值 df['Prev15minMin'] = df.groupby('Type')['Last'].transform( lambda x: x.rolling('15min', min_periods=16).min() )
要是你想给每个Type单独生成一列(比如Prev15minMax_Ada、Prev15minMax_Btc),可以这么搞:
# 先按Type分组计算滚动最大/最小值,再把结果拆成多列 roll_max = df.groupby('Type')['Last'].rolling('15min', min_periods=16).max().unstack('Type') roll_min = df.groupby('Type')['Last'].rolling('15min', min_periods=16).min().unstack('Type') # 给列名加上前缀,再合并回原表 roll_max.columns = [f'Prev15minMax_{col}' for col in roll_max.columns] roll_min.columns = [f'Prev15minMin_{col}' for col in roll_min.columns] df = df.join(roll_max).join(roll_min)
方法2:修复你的循环代码
要是你非得用循环,那得处理好索引对齐的问题,用reindex把结果扩展到原表的所有行,空的地方填NaN:
for v in df['Type'].unique(): # 计算当前Type的滚动最大值,重新索引到原表的索引 max_series = df.loc[df['Type'].eq(v), 'Last'].rolling('15min', min_periods=16).max() df[f'Prev15minMax_{v}'] = max_series.reindex(df.index) # 同理处理最小值 min_series = df.loc[df['Type'].eq(v), 'Last'].rolling('15min', min_periods=16).min() df[f'Prev15minMin_{v}'] = min_series.reindex(df.index)
这样Pandas就不会因为索引对齐出问题了,因为reindex确保了新生成的Series和原表索引完全一致。
几个要注意的点
- 一定要确保你的
Timestamp列是DataFrame的索引,或者在rolling里加上on='Timestamp'参数,不然Pandas认不出时间窗口:# 如果Timestamp不是索引,必须加on参数 df.groupby('Type')['Last'].transform( lambda x: x.rolling('15min', min_periods=16, on='Timestamp').max() ) min_periods要跟你的数据频率匹配,比如每分钟一条数据的话,15分钟窗口设min_periods=16就是要至少16条数据才计算,否则返回NaN;要是你的数据是其他频率,得对应调整这个数值。
内容的提问来源于stack exchange,提问作者KSp
相关产品推荐
相关产品推荐

