首页 > 解决方案 > 为什么带有两组括号的 .loc 分配会导致 pandas.DataFrame 中的 NaN?

问题描述

我有一个数据框:

姓名 年龄
0 保罗 25
1 约翰 27
2 账单 23

我知道如果我输入:

df[['name']] = df[['age']]

我会得到以下信息:

姓名 年龄
0 25 25
1 27 27
2 23 23

但我希望从命令中得到相同的结果:

df.loc[:, ['name']] = df.loc[:, ['age']]

但相反,我得到了这个:

姓名 年龄
0 25
1 27
2 23

出于某种原因,如果我省略[]列名周围的方括号,我会得到我所期望的。那是命令:

df.loc[:, 'name'] = df.loc[:, 'age']

给出正确的结果:

姓名 年龄
0 25 25
1 27 27
2 23 23

为什么两对括号的.loc结果是 NaN?它是某种错误还是预期的行为?我无法弄清楚这种行为的原因。

标签: pythonpandasdataframenanseries

解决方案


从文档Pandas Data Alignment(强调我的):

从.loc 和 .iloc设置 Series 和 DataFrame 时,pandas会对齐所有 AXES 。

Basics您可以在标题下找到标有警告的这段摘录。他们举了一个例子来解释。

In [9]: df[['A', 'B']]
Out[9]: 
                   A         B
2000-01-01 -0.282863  0.469112
2000-01-02 -0.173215  1.212112
2000-01-03 -2.104569 -0.861849
2000-01-04 -0.706771  0.721555
2000-01-05  0.567020 -0.424972
2000-01-06  0.113648 -0.673690
2000-01-07  0.577046  0.404705
2000-01-08 -1.157892 -0.370647

In [10]: df.loc[:, ['B', 'A']] = df[['A', 'B']]

In [11]: df[['A', 'B']]
Out[11]: 
                   A         B
2000-01-01 -0.282863  0.469112
2000-01-02 -0.173215  1.212112
2000-01-03 -2.104569 -0.861849
2000-01-04 -0.706771  0.721555
2000-01-05  0.567020 -0.424972
2000-01-06  0.113648 -0.673690
2000-01-07  0.577046  0.404705
2000-01-08 -1.157892 -0.370647

来自文档(强调我的)

不会修改 df 因为列对齐是在赋值之前。

明确避免自动对齐

当您需要在没有索引的情况下执行某些操作(例如,禁用自动对齐)时,访问数组会很有用。

当 LHS 和 RHS 是数据帧时,对齐就会起作用。为避免对齐尝试使用。

df.loc[:, ['B', 'A']] = df[['A', 'B']].to_numpy()

你手头有两个案子,

  • .locpd.DataFrame.
  • .locpd.Series在编辑中分配。

.loc分配在pd.DataFrame

Inpd.DataFrame有 2 个轴indexcolumns. 所以,当你这样做

df.loc[:, ['name']] = df.loc[:, ['age']]

LHS 的列A与 RHS 列不对齐,B因此导致NaN分配后的所有内容。

来自 Docs DataAlignment(强调我的)

DataFrame 对象之间的数据对齐会自动对齐列和索引(行标签)。同样,生成的对象将具有列和行标签的联合。

如果不是全部,您可以在大多数 pandas 的操作中找到这种行为。例如,加法、减法、乘法等。不匹配的索引和列用 填充NaN

数据对齐和算法的示例

df = pd.DataFrame(np.random.randn(10, 4), columns=["A", "B", "C", "D"])
df2 = pd.DataFrame(np.random.randn(7, 3), columns=["A", "B", "C"])

df + df2 

         A         B         C   D
0  0.045691 -0.014138  1.380871 NaN
1 -0.955398 -1.501007  0.037181 NaN
2 -0.662690  1.534833 -0.859691 NaN
3 -2.452949  1.237274 -0.133712 NaN
4  1.414490  1.951676 -2.320422 NaN
5 -0.494922 -1.649727 -1.084601 NaN
6 -1.047551 -0.748572 -0.805479 NaN
7       NaN       NaN       NaN NaN
8       NaN       NaN       NaN NaN
9       NaN       NaN       NaN NaN

回答您的评论

但是为什么列索引需要匹配呢?我可以看到为什么要匹配行索引,但为什么要匹配列索引?

让我们看一下上面的例子,如果列不对齐,你将如何添加两个 DataFrame?在列和索引上对齐它们是有意义的。


.loc分配在pd.Series

pd.Series只有一个轴,即index。这就是为什么当你这样做时它起作用的原因

df.loc[:, 'name'] = df.loc[:, 'age']

由于pd.Series只有一个轴,pandas 尝试对齐index并且成功了。当然,如果index不对齐,则会产生NaN值。

来自文档Series Alignment(强调我的)

未对齐系列之间的操作结果将包含所涉及的索引的并集。如果在一个系列或另一个系列中找不到标签,结果将被标记为缺失NaN


推荐阅读