二级MultiIndex使用.loc赋值出现NaN的原因及统一赋值方法
Pandas两级MultiIndex赋值出现NaN的原因及统一解决方案
问题现象
在Pandas中对MultiIndex的Series/DataFrame赋值时,仅当MultiIndex为两级且使用标量指定最后一级索引时(如loc[:, 0]),会出现赋值后目标位置变为NaN的情况;而标准索引、三级及以上MultiIndex,或用列表形式指定索引(如loc[:, [0]])时,赋值均正常。
复现代码
import sys from importlib.metadata import version import numpy as np import pandas as pd print(f"Python version: {sys.version}") print(f"Pandas version: {version('pandas')}") print(f"Numpy version: {version('numpy')}\n") # 标准索引测试 s = pd.Series(np.random.random(5), index=pd.Index(np.arange(5))) s.loc[0] += 1 print(f"A. 标准索引: .loc[0]\n{s}\n") # 三级MultiIndex测试 s_multi_3 = pd.Series(np.random.random(5), index=pd.MultiIndex.from_product([["a"], ["b"], np.arange(5)])) # 转为两级MultiIndex s_multi_2 = s_multi_3.droplevel(0) # 两级MultiIndex:用列表指定索引 s_multi_2.loc[:, [0]] += 1 print(f"B1. 两级MultiIndex: .loc[:, [0]]\n{s_multi_2}\n") # 两级MultiIndex:用标量指定索引(出现NaN) s_multi_2.loc[:, 0] += 1 print(f"C1. 两级MultiIndex: .loc[:, 0]\n{s_multi_2}\n") # 三级MultiIndex:用列表指定索引 s_multi_3.loc[:, :, [0]] += 1 print(f"B2. 三级MultiIndex: .loc[:, :, [0]]\n{s_multi_3}\n") # 三级MultiIndex:用标量指定索引(正常) s_multi_3.loc[:, :, 0] += 1 print(f"C2. 三级MultiIndex: .loc[:, :, 0]\n{s_multi_3}\n")
输出结果
Python version: 3.12.5 (tags/v3.12.5:ff3bc82, Aug 6 2024, 20:45:27) [MSC v.1940 64 bit (AMD64)] Pandas version: 2.2.2 Numpy version: 2.0.1 A. 标准索引: .loc[0] 0 1.184514 1 0.460907 2 0.777756 3 0.983770 4 0.722276 dtype: float64 B1. 两级MultiIndex: .loc[:, [0]] b 0 1.865925 1 0.728489 2 0.948691 3 0.786609 4 0.756799 dtype: float64 C1. 两级MultiIndex: .loc[:, 0] b 0 NaN 1 0.728489 2 0.948691 3 0.786609 4 0.756799 dtype: float64 B2. 三级MultiIndex: .loc[:, :, [0]] a b 0 1.865925 1 0.728489 2 0.948691 3 0.786609 4 0.756799 dtype: float64 C2. 三级MultiIndex: .loc[:, :, 0] a b 0 2.865925 1 0.728489 2 0.948691 3 0.786609 4 0.756799 dtype: float64
原因分析
这是Pandas索引匹配逻辑的歧义性问题:
- 对于两级MultiIndex,当使用
.loc[:, 0]时,Pandas会错误地将标量0解析为一个单元素元组(即(0,)),而非第二级索引的单个值。由于原索引的第二级是整数0,而非元组(0,),导致匹配失败,Pandas会创建新的索引项并赋值,原索引项因未被匹配到,值变为NaN。 - 对于三级及以上MultiIndex,
.loc[:, :, 0]的索引层级明确,Pandas能正确识别0是最后一级的标量索引值,不会产生歧义。 - 使用列表形式(如
[0])时,无论几级MultiIndex,Pandas都会明确将其视为对应层级的索引值列表,匹配逻辑清晰,因此不会出错。
统一赋值方案
以下三种方法可确保在任意层级的MultiIndex中都能正确赋值:
1. 始终使用列表形式指定索引值
将标量索引改为列表形式,消除匹配歧义:
# 两级MultiIndex正确赋值 s_multi_2.loc[:, [0]] += 1
2. 用元组+slice明确指定索引范围
使用slice(None)代替:,结合元组精准定位目标索引区间:
# 匹配第一级所有值、第二级为0的项 s_multi_2.loc[(slice(None), 0)] += 1 # 单个元素精准定位 s_multi_2.loc[('b', 0)] += 1
3. 使用xs方法提取子Series后赋值
xs方法可直接按层级提取子数据集,逻辑直观无歧义:
# 提取第二级索引为0的子Series并赋值 s_multi_2.xs(0, level=1) += 1
内容的提问来源于stack exchange,提问作者guillaumeplc
相关产品推荐
相关产品推荐

