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

为何使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 22:43:19