pandas拆分Binance BTCUSDT时间序列数据出现重复轴错误如何解决
问题解决方法
1. 解决ValueError: cannot reindex from a duplicate axis报错
该错误核心原因是price['BTCUSDT']的行索引存在重复值:
- 你当前用
len(price['BTCUSDT'])作为行索引写入新数据,而Binance Websocket的回调是异步多线程触发的,极端情况会出现多个回调同时执行,用相同的长度值作为索引写入,导致索引重复。 - 部分场景下时间戳重复也会触发该问题,尤其是你后续把时间列设为索引的情况。
对应的修复方案:
修改回调函数里的新增数据逻辑,改用pd.concat配合ignore_index=True自动生成无重复的递增索引,替换原有的手动指定索引写法:
def btc_pairs_trade(msg): if msg['e'] != 'error': # 构造单行数据再拼接,自动生成无重复索引 new_row = pd.DataFrame([[pd.Timestamp.now(), float(msg['c'])]], columns=['date','price']) price['BTCUSDT'] = pd.concat([price['BTCUSDT'], new_row], ignore_index=True) bn=price['BTCUSDT'] return bn else: price['error'] = True
如果需要更高的筛选效率,也可以直接把时间列设为索引,微秒级时间戳基本不会重复:
# 初始化price['BTCUSDT']时就设置时间为索引 price['BTCUSDT'] = pd.DataFrame(columns=['price'], index=pd.DatetimeIndex([])) # 回调写入逻辑 def btc_pairs_trade(msg): if msg['e'] != 'error': price['BTCUSDT'].loc[pd.Timestamp.now()] = float(msg['c']) return price['BTCUSDT'] else: price['error'] = True # 筛选逻辑可以直接用索引切片,速度更快 start_time = price['BTCUSDT'].index[-1] - pd.Timedelta(minutes=5) df2 = price['BTCUSDT'].loc[start_time:]
2. 解决A value is trying to be set on a copy of a slice from a DataFrame警告
该警告是因为df.loc[df.date >= start_time]筛选出来的结果是原DataFrame的视图而非独立副本,如果你后续对该结果做修改操作,pandas无法判断你要修改原数据还是修改筛选结果,就会弹出警告。
修复方案:筛选时主动调用.copy()生成独立副本即可:
df = price['BTCUSDT'] start_time = df.date.iloc[-1] - pd.Timedelta(minutes=5) # 加.copy()生成独立副本 df2 = df.loc[df.date >= start_time].copy()
额外优化建议
- 流式数据会不断占用内存,你可以每次筛选完之后只保留最近5分钟的历史数据,避免内存溢出:
price['BTCUSDT'] = df2.copy() - 多线程读写DataFrame不是线程安全的,建议加锁避免并发读写冲突:
# 初始化锁 import threading data_lock = threading.Lock() # 回调写入加锁 def btc_pairs_trade(msg): if msg['e'] != 'error': with data_lock: new_row = pd.DataFrame([[pd.Timestamp.now(), float(msg['c'])]], columns=['date','price']) price['BTCUSDT'] = pd.concat([price['BTCUSDT'], new_row], ignore_index=True) return price['BTCUSDT'] else: price['error'] = True # 主逻辑读取也加锁 with data_lock: df = price['BTCUSDT'] start_time = df.date.iloc[-1] - pd.Timedelta(minutes=5) df2 = df.loc[df.date >= start_time].copy()
内容的提问来源于stack exchange,提问作者vincent charagu
相关产品推荐
相关产品推荐

