为什么当我应用 DataFrame.sub() 时我得到了具有更多列的新 DF?

Why when I apply DataFrame.sub() I get the new DF with a higher number of columns?

当我在这种特定情况下应用 .sub() 方法时,我无法理解 Pandas 的行为,我的目标是将 DataFrame 中的行居中。

基本上我想为每一行计算平均值,然后从每一行中减去该值以使 DataFrame 居中。

我认为这个问题可能与元素操作有关,但在阅读文档后仍然很模糊,原因也很模糊 here

import pandas as pd
val = {1: [1,2,3,4],
       2: [4,5,6,7],
       3: [8,9,10,11],
       4: [12,13,14,15]}

df = pd.DataFrame(val)
# Computing for each row the mean value
avg = df.mean(axis=1)
#Removing the mean value from each element in each row
df_centered = df.sub(avg,axis=1)

print(df)
print(avg)
print(df_centered)


   1  2   3   4
0  1  4   8  12
1  2  5   9  13
2  3  6  10  14
3  4  7  11  15
0    6.25
1    7.25
2    8.25
3    9.25
dtype: float64
    0     1     2     3   4
0 NaN -6.25 -4.25 -1.25 NaN
1 NaN -5.25 -3.25 -0.25 NaN
2 NaN -4.25 -2.25  0.75 NaN
3 NaN -3.25 -1.25  1.75 NaN
  1. 我不明白为什么我得到这个输出
  2. 我希望我的输出是 4X4 而不是 4X5,为什么我有第 5 列?
  3. 为什么我从操作中得到 NaN

编辑

预期输出:

 df_centered
         1      2      3      4
    0 -5.25  -2.25    1.75   5.75
    1 -5.25  -2.25    1.75   5.75
    2 -5.25  -2.25    1.75   5.75
    3 -5.25  -2.25    1.75   5.75

我认为所有行都相等这一事实仅适用于此示例。

现在,如果您从 df_centered 计算每一行的平均值,它将是 0,正如“居中”过程所预期的那样。

DataFrame.sub中使用axis=0来减去前行,这意味着6.25被DataFrame的第一行减去:

df_centered = df.sub(avg,axis=0)
print(df_centered)
      1     2     3     4
0 -5.25 -2.25  1.75  5.75
1 -5.25 -2.25  1.75  5.75
2 -5.25 -2.25  1.75  5.75
3 -5.25 -2.25  1.75  5.75

Why I get NaN from the operation?

因为列 0,5 的索引与 Series avg 的索引不同,这里是 1,2,3,4,所以 pandas 不匹配并且缺少列已创建。

您所有问题的答案都在这部分文档中:

For Series input, axis to match Series index on.

在您的情况下,您的列是 print(df.columns):

Int64Index([1, 2, 3, 4], dtype='int64')

同时 print(avg):

0    6.25
1    7.25
2    8.25
3    9.25
dtype: float64

所以这里的索引是 0, 1, 2, 3.

根据上面的文档,您需要向 df 添加一个额外的列 0,同样地 avg 中没有索引 4所以你用 NaN 做减法,结果是 NaN。

克服这个问题的一种方法是将 avg 中的索引重命名为

avg.index = df.columns

但是,据我所知,使用 level=0level=1 会产生相同的结果。

估计是广播操作的方式有问题。所以我建议您采用以下解决方案。

数据

import numpy as np
import pandas as pd

import pandas as pd

val = {1: [1,2,3,4],
       2: [4,5,6,7],
       3: [8,9,10,11],
       4: [12,13,14,15]}

df = pd.DataFrame(val)

生成要减去的矩阵

我们首先要求结果是一个numpy数组

avg = df.mean(axis=1).values

然后我们重复 df

中的行数
rep = np.repeat(avg, len(df))

最后我们根据df

重塑它
mat = rep.reshape(df.shape)
[[6.25 6.25 6.25 6.25]
 [7.25 7.25 7.25 7.25]
 [8.25 8.25 8.25 8.25]
 [9.25 9.25 9.25 9.25]]

现在 df.sub 按预期工作

df_centered = df.sub(mat)

您要查找的数据框是哪个

      1     2     3     4
0 -5.25 -2.25  1.75  5.75
1 -5.25 -2.25  1.75  5.75
2 -5.25 -2.25  1.75  5.75
3 -5.25 -2.25  1.75  5.75