Pandas合并DataFrame报错:ValueError: cannot reindex from a duplicate axis
我拥有两个以时间戳datetime为索引的Pandas DataFrame,分别包含浮点类型列metric1和metric2。尝试合并这两个DataFrame时,出现如下错误:
ValueError: cannot reindex from a duplicate axis
查阅资料后仍未找到解决方案。尝试复现问题,但仅能通过特定数据触发,数据量过大无法完整上传。最终发现部分数据子集存在兼容性问题,部分则可正常合并。
期望合并后的结果索引包含所有时间戳,同时保留metric1和metric2列,无对应数据的位置填充NaN。通常pd.concat可实现此需求,但本次合并tt1与tt2时报错,合并tt1与tt4则正常。
复现文件与代码
CSV文件
test1.csv
timestamp,metric1 2018-03-21 15:46:36,3.5555559999999997 2018-03-21 15:47:36,5.345001 2018-03-21 15:48:36,5.719998
test2.csv
timestamp,metric2 2018-03-28 05:49:59,3.28 2018-03-28 05:50:59,3.45 2018-03-28 05:51:59,3.258332 2018-03-28 05:52:59,3.068333 2018-03-28 05:53:59,2.9733330000000002 2018-03-28 05:54:59,3.0650009999999996 2018-03-28 05:55:59,3.109999 2018-03-28 05:56:59,3.3683330000000002 2018-03-28 05:57:59,3.1516669999999998 2018-03-28 05:58:59,3.051666 2018-03-28 05:59:59,3.3083339999999994 2018-03-28 06:01:01,3.328333 2018-03-28 06:01:01,3.1 2018-03-28 06:02:00,3.305 2018-03-28 06:03:00,3.29 2018-03-28 06:04:00,3.2183330000000003 2018-03-28 06:05:00,3.176666 2018-03-28 06:06:00,3.353333 2018-03-28 06:07:00,3.3233330000000003 2018-03-28 06:08:00,3.393332 2018-03-28 06:09:00,3.053334 2018-03-28 06:10:00,3.268333 2018-03-28 06:11:00,3.239999 2018-03-28 06:12:00,3.223332 2018-03-28 06:13:00,3.119999
test4.csv
timestamp,metric2 2018-03-21 00:00:00,10.665 2018-03-21 00:01:00,10.285 2018-03-21 00:02:00,10.12834
说明:test2.csv与test4.csv源自同一数据集
加载CSV的代码
import pandas as pd tt1 = pd.read_csv('test1.csv', index_col=0) tt1.index = pd.to_datetime(tt1.index) tt2 = pd.read_csv('test2.csv', index_col=0) tt2.index = pd.to_datetime(tt2.index) tt4 = pd.read_csv('test4.csv', index_col=0) tt4.index = pd.to_datetime(tt4.index)
合并测试
- 无报错测试:
tt3 = pd.concat([tt1, tt4], axis = 1) - 报错测试:
tt3 = pd.concat([tt1, tt2], axis = 1) # 报错:ValueError: cannot reindex from a duplicate axis
问题根源
一眼就能看出问题:test2.csv里存在重复的时间戳——2018-03-28 06:01:01对应两条不同的metric2记录。当使用pd.concat(axis=1)合并时,Pandas要求参与合并的DataFrame索引必须唯一,否则无法完成索引对齐的重索引操作,直接抛出错误。而test4.csv的索引没有重复,所以合并tt1和tt4完全正常。
你可以用以下代码验证索引重复情况:
# 检查tt2是否有重复索引 print("tt2索引是否有重复:", tt2.index.duplicated().any()) # 查看重复的索引值 print("重复的索引:", tt2.index[tt2.index.duplicated()])
针对需求的解决办法
你的需求是保留所有时间戳、无数据填充NaN,下面提供两种适配不同场景的方案:
方案1:保留重复索引的所有数据
如果这些重复时间戳的记录是合法的(比如同一时间点有多个观测值),可以用DataFrame.join()替代pd.concat,join默认支持重复索引的合并:
tt3 = tt1.join(tt2, how='outer')
合并后,重复的时间戳会保留所有行,metric1对应位置自动填充NaN(因为tt1没有该时间戳的数据)。
方案2:清理重复索引(保留唯一时间戳)
如果重复的时间戳是数据错误,先清理tt2的重复索引再合并:
- 方式A:保留每个重复时间戳的第一条记录
tt2_clean = tt2[~tt2.index.duplicated()] tt3 = pd.concat([tt1, tt2_clean], axis=1) - 方式B:保留每个重复时间戳的最后一条记录
tt2_clean = tt2[~tt2.index.duplicated(keep='last')] tt3 = pd.concat([tt1, tt2_clean], axis=1) - 方式C:对重复时间戳的
metric2值做聚合(比如取均值)tt2_clean = tt2.groupby(tt2.index).mean() tt3 = pd.concat([tt1, tt2_clean], axis=1)
验证结果
无论使用哪种方案,最终的tt3都会包含tt1和tt2的所有时间戳,无对应数据的位置自动填充NaN,完全符合你的预期需求。
内容的提问来源于stack exchange,提问作者ojunk

