为何向Pandas DataFrame直接添加Series作为新列会丢失行?
为什么直接给空DataFrame赋值Series列会丢失部分索引?
这是个非常好的问题,很多刚接触pandas的开发者都会对这个行为感到困惑,我来帮你拆解背后的逻辑:
先重现你的场景
首先看你用到的代码和结果:
import pandas as pd s1 = pd.Series({1: 10, 2: 20, 3: 30, 4: 40}, name='s1') s2 = pd.Series({3: 35, 4: 45, 5: 55, 6: 65}, name='s2') # 直接赋值的方式 df = pd.DataFrame() df['s1'] = s1 df['s2'] = s2
得到的结果只保留了s1的索引:
s1 s2 1 10 NaN 2 20 NaN 3 30 35.0 4 40 45.0
核心原因:赋值时的索引规则
直接给DataFrame添加列的行为遵循两个关键逻辑:
- 首次赋值固定DataFrame的索引:当你给一个空DataFrame添加第一列(
df['s1'] = s1)时,pandas会自动把该Series的索引设置为DataFrame的索引,此时df的索引就固定为[1,2,3,4]了。 - 后续赋值仅做索引对齐,不扩展索引:当你添加第二列
df['s2'] = s2时,pandas会以当前DataFrame已有的索引为基准,只匹配s2中索引重合的行(也就是3、4)填充值,而s2中索引5、6不在df的现有索引里,会直接被忽略,不会自动扩展df的索引范围。
为什么pd.concat能得到预期结果?
pd.concat([s1, s2], axis=1)的逻辑和直接赋值完全不同:
它会默认收集所有输入Series的索引,取索引的并集作为结果DataFrame的索引,然后对每个Series进行索引对齐,缺失的位置自动填充NaN。这就是为什么它能保留所有索引(1-6)的原因。
用赋值方式实现预期效果的替代方案
如果你想通过赋值的方式达到和concat一样的效果,可以先手动把DataFrame的索引设置为两个Series索引的并集,再进行赋值:
# 手动设置索引为两个Series索引的并集 df = pd.DataFrame(index=s1.index.union(s2.index)) df['s1'] = s1 df['s2'] = s2
这样得到的结果就和pd.concat一致了:
s1 s2 1 10.0 NaN 2 20.0 NaN 3 30.0 35.0 4 40.0 45.0 5 NaN 55.0 6 NaN 65.0
总结一下:直接赋值是以现有DataFrame的索引为基准做对齐,而pd.concat是以所有输入的索引并集为基准,这就是两者行为差异的核心。
内容的提问来源于stack exchange,提问作者Bilou
相关产品推荐
相关产品推荐

