为何使用df.loc赋值会新增行且列数据类型改变?
问题:为什么两个DataFrame赋值函数结果不同,其中一个新增了NaN行?
我原本认为以下两个函数会产生相同结果:
import pandas as pd def test_fn1(df: pd.DataFrame) -> pd.DataFrame: df['b'] = df['b'].apply(lambda x: [x] if isinstance(x, dict) else x) return df def test_fn2(df: pd.DataFrame) -> pd.DataFrame: df.loc['b'] = df['b'].apply(lambda x: [x] if isinstance(x, dict) else x) return df
测试用的DataFrame:
test_df = pd.DataFrame({'a': [1, 2, 3], 'b': [{'c': 1}, {'c': 2}, {'c': 3}]})
初始输出:
a b 0 1 {'c': 1} 1 2 {'c': 2} 2 3 {'c': 3}
调用test_fn1(test_df)后输出符合预期:
a b 0 1 [{'c': 1}] 1 2 [{'c': 2}] 2 3 [{'c': 3}]
但调用test_fn2(test_df)后出现异常,新增了一行NaN:
a b 0 1.0 [{'c': 1}] 1 2.0 [{'c': 2}] 2 3.0 [{'c': 3}] b NaN NaN
请问是什么原因导致了最后一行的出现?
回答
核心原因是**df['列名']和df.loc['行标签']的操作维度完全不同**:
1. test_fn1的正确逻辑
df['b'] = ...是直接定位到名为'b'的列,右边的df['b'].apply(...)返回一个和原列长度一致的Series,赋值操作会直接替换'b'列的原有数据,整个过程不会修改DataFrame的行结构,所以结果符合预期。
2. test_fn2的问题所在
df.loc['b']的第一个参数是行标签,你的原始DataFrame行标签是0、1、2,不存在'b'这一行,因此pandas会自动新增一行行标签为'b'的记录。- 右边的
df['b'].apply(...)返回的Series,其索引是原行标签0、1、2,而DataFrame的列名是'a'、'b'。当赋值给新行'b'时,pandas会尝试将Series的索引与DataFrame的列名对齐,但两者完全不匹配,所以新行的所有列都会被填充为NaN。 - 另外,原
'a'列原本是整数类型,新增行的'a'列是NaN(属于浮点数类型),pandas会自动将整个'a'列的类型转为float,这就是原行a列值变成1.0、2.0、3.0的原因。
简单说:要修改列用df['列名'],要修改行才用df.loc['行标签'],别搞混两者的操作对象。
内容的提问来源于stack exchange,提问作者Michael Chao
相关产品推荐
相关产品推荐

