pandas报InvalidIndexError:仅唯一值索引可重索引问题排查
Pandas 宽表转换报InvalidIndexError解决方案
报错原因
报错和原始DataFrame列名无关,核心原因是按date分组后,部分日期对应的time列表中存在重复的时间值,手动拼接生成列名时会出现重复的1 {时间} {字段名}格式列名,pandas做concat拼接操作时要求索引、列名必须唯一,因此抛出异常。
同代码在5分钟粒度数据上可正常运行,是因为5分钟间隔的时间序列天然不会在单日出现重复时间点,生成的列名全唯一,不会触发校验。
你可以先运行以下代码定位存在重复时间点的日期,验证问题:
# 校验每个日期下是否存在重复时间 df['time'] = pd.to_datetime(df['time']).dt.time has_dup_time = df.groupby('date')['time'].apply(lambda x: len(x) != len(set(x))) print("存在重复时间点的日期:", has_dup_time[has_dup_time].index.tolist())
解决方法
方法1:去重后保留原有逻辑
如果重复时间点属于脏数据,先按date+time维度去重再执行原有转换逻辑即可:
df['time'] = pd.to_datetime(df['time']).dt.time # 同日期同时间点仅保留第一条记录 df = df.drop_duplicates(subset=['date', 'time'], keep='first') df = df.groupby('date').agg(list) one_min_df = pd.concat([ pd.concat([pd.DataFrame([row[col]], index=[index], columns=[f'1 {h} {col}' for h in row['time']]) for col in row.index[1:]], axis=1) for index, row in df.iterrows() ])
方法2:用pandas原生透视表实现(更推荐)
逐行遍历的写法性能差、容易出边界问题,直接用pivot_table实现长宽表转换更稳定,性能也更高,不需要手动拼接列名:
df['time'] = pd.to_datetime(df['time']).dt.time # 构造列名前缀 df['time_label'] = '1 ' + df['time'].astype(str) # 透视生成宽表,重复时间点自动取第一条记录 one_min_df = df.pivot_table( index='date', columns='time_label', values=['open', 'high', 'low', 'close'], aggfunc='first' ) # 调整列名格式为目标结构 one_min_df.columns = [f'{time_col} {val_col}' for val_col, time_col in one_min_df.columns] one_min_df = one_min_df.reset_index()
如果需要列按时间点顺序排列(即同一时间点的open/high/low/close排在一起),可以在生成列后对列名做自定义排序即可。
内容的提问来源于stack exchange,提问作者boioboi
相关产品推荐
相关产品推荐

