You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

pandas使用.loc遇不匹配索引内存爆增及赋值重复轴错误问题

问题:pandas按条件拼接列时第三种方案内存占用异常问题

这是来自问题「按条件拼接pandas单元格的最Pythonic实现方式」的观测结果,我无法理解为什么第三种方案比第一种占用更多内存。

  • 如果不做采样操作,第三种方案不会报运行时错误,显然存在异常问题
  • 为了模拟大数据帧场景我尝试重采样,但完全没料到会遇到这类错误

背景

逻辑很容易理解,单行代码,写法很pythonic

df['city'] + (df['city'] == 'paris')*('_' + df['arr'].astype(str))

测试数据集构造代码:

s = """city,arr,final_target
paris,11,paris_11
paris,12,paris_12
dallas,22,dallas
miami,15,miami
paris,16,paris_16"""
import pandas as pd
import io
df = pd.read_csv(io.StringIO(s)).sample(1000000, replace=True)
df

运行速度测试:

%%timeit
df['city'] + (df['city'] == 'paris')*('_' + df['arr'].astype(str))
# 877 ms ± 19.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%%timeit
df['final_target'] = np.where(df['city'].eq('paris'), 
                              df['city'] + '_' + df['arr'].astype(str), 
                              df['city'])
# 874 ms ± 19.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
如果不做采样,没有报错且输出完全匹配

错误(已更新):仅在对数据帧采样时出现

第三种方案代码:

%%timeit
df['final_target'] = df['city']
df.loc[df['city'] == 'paris', 'final_target'] +=  '_' + df['arr'].astype(str)

大采样量报错:

MemoryError: Unable to allocate 892. GiB for an array with shape (119671145392,) and data type int64

小采样量(采样大小100)报错:

ValueError: cannot reindex from a duplicate axis
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-5-57c5b10090b2> in <module>
      1 df['final_target'] = df['city']
----> 2 df.loc[df['city'] == 'paris', 'final_target'] +=  '_' + df['arr'].astype(str)

~/anaconda3/lib/python3.8/site-packages/pandas/core/ops/methods.py in f(self, other)
     99             # we are updating inplace so we want to ignore is_copy
    100             self._update_inplace(
--> 101                 result.reindex_like(self, copy=False), verify_is_copy=False
    102             )
    103 

每次测试我都会从头重新运行代码。

更新

我目前已经发现部分原因:
小采样量输出示例:

s = """city,arr,final_target
paris,11,paris_11
paris,12,paris_12
dallas,22,dallas
miami,15,miami
paris,16,paris_16"""
import pandas as pd
import io
df = pd.read_csv(io.StringIO(s)).sample(10, replace=True)
df

输出:

city    arr final_target
1   paris   12  paris_12
0   paris   11  paris_11
2   dallas  22  dallas
2   dallas  22  dallas
3   miami   15  miami
3   miami   15  miami
2   dallas  22  dallas
1   paris   12  paris_12
0   paris   11  paris_11
3   miami   15  miami
  • 有放回采样会导致索引重复
  • 因此重置索引可以解决问题,或者替换为df.loc[df['city'] == 'paris', 'arr'].astype(str)也可以解决,即便df.arr和df.loc的尺寸本质上存在差异。
  • 仍希望有人解释.loc的运行逻辑,以及索引存在重复且不匹配时内存暴增的原因?

解答

这个问题的核心是pandas的索引对齐机制和重复索引的笛卡尔积匹配逻辑:

  1. .loc赋值时的默认行为:对左右两个Series做运算时,pandas会优先按索引标签匹配对应值,而不是按位置匹配。
  2. 重复索引的笛卡尔积问题:你使用有放回采样后,索引存在大量重复值,比如索引1在df里出现了1万次。你+=右边的是完整的df['arr'].astype(str),索引和整个df完全一致,同样有大量重复索引。此时左边.loc筛选出来的是所有city为paris的行,当pandas尝试对齐左右两边的索引时,会把左边每个索引标签和右边所有相同标签的行做笛卡尔积匹配,比如左边有k个标签为1的行,右边有m个标签为1的行,就会生成k*m个匹配结果。当采样量到1e6时,重复索引的笛卡尔积会直接把结果数组的长度拉到百亿级别,也就是你看到的需要分配892GiB内存的情况。
  3. 小样本报错的原因:小样本时笛卡尔积后的结果长度和左边.loc筛选出来的子集长度不匹配,pandas无法直接赋值,就会抛出cannot reindex from a duplicate axis的错误。

两种解决方法的原理:

  • 重置索引:df.reset_index(drop=True)后所有索引都是唯一的,对齐时只会一一匹配,不会生成笛卡尔积。
  • 右边改为筛选后的arr列:df.loc[df['city'] == 'paris', 'arr'].astype(str)的索引和左边.loc筛选出来的子集索引完全一致,不需要额外对齐,自然不会有问题。

内容的提问来源于stack exchange,提问作者eroot163pi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 23:00:00