Python:获取数据帧中多个数组的逐元素平均值

Python: get the element-wise mean of multiple arrays in a dataframe

我有一个 16x10 的熊猫数据框,每个单元格中有 1x35000 个数组(或 NaN)。我想对每一列的行进行逐元素平均。

      1       2       3       ...       10
1    1x35000 1x35000 1x35000           1x35000

2    1x35000 NaN     1x35000           1x35000

3    1x35000 NaN     1x35000           NaN

...

16   1x35000 1x35000 NaN               1x35000

为避免误解:取第一列中每个数组的第一个元素并取平均值。然后取第一列中每个数组的第二个元素,再次取平均值。最后我想要一个 1x10 数据帧,每列有一个 1x35000 数组。该数组应该是我以前的数组的逐元素平均值。

      1       2       3       ...       10
1    1x35000 1x35000 1x35000           1x35000

你有没有最好不用 for 循环优雅地到达那里的想法?

设置

np.random.seed([3,14159])
df = pd.DataFrame(
    np.random.randint(10, size=(3, 3, 5)).tolist(),
    list('XYZ'), list('ABC')
).applymap(np.array)

df.loc['X', 'B'] = np.nan
df.loc['Z', 'A'] = np.nan

df

                 A                B                C
X  [4, 8, 1, 1, 9]              NaN  [8, 2, 8, 4, 9]
Y  [4, 3, 4, 1, 5]  [1, 2, 6, 2, 7]  [7, 1, 1, 7, 8]
Z              NaN  [9, 3, 8, 7, 7]  [2, 6, 3, 1, 9]

解决方案

g = df.stack().groupby(level=1)
g.apply(np.sum, axis=0) / g.size()

A                        [4.0, 5.5, 2.5, 1.0, 7.0]
B                        [5.0, 2.5, 7.0, 4.5, 7.0]
C    [5.66666666667, 3.0, 4.0, 4.0, 8.66666666667]
dtype: object

如果你坚持你呈现的形状

g = df.stack().groupby(level=1)
(g.apply(np.sum, axis=0) / g.size()).to_frame().T

                           A                          B                                              C
0  [4.0, 5.5, 2.5, 1.0, 7.0]  [5.0, 2.5, 7.0, 4.5, 7.0]  [5.66666666667, 3.0, 4.0, 4.0, 8.66666666667]

方法 #1:Loopy

鉴于混合 dtype 输入数据,我们可能希望循环以提高性能效率。因此,可以建议使用显式循环或引擎盖下使用.apply/.applymap的解决方案。

这是循环遍历列的一种方法 -

mask = ~df.isnull().values
n = df.shape[1]
out = np.empty((1,n),dtype=object)
for i in range(n):
    out[0,i] = df.iloc[mask[:,i],i].mean()
df_out = pd.DataFrame(out)

样本输入、输出-

In [326]: df
Out[326]: 
              0             1             2
0  [4, 0, 1, 6]  [4, 2, 2, 2]  [5, 3, 5, 4]
1           NaN  [0, 5, 6, 8]           NaN
2           NaN           NaN           NaN
3           NaN           NaN           NaN

In [327]: df_out
Out[327]: 
                      0                     1                     2
0  [4.0, 0.0, 1.0, 6.0]  [2.0, 3.5, 4.0, 5.0]  [5.0, 3.0, 5.0, 4.0]

方法 #2:向量化

如果您必须矢量化,这里有一种使用 matrix-multiplication 替换 mean-reductions 的方法,这可能会改进大数据 -

mask = ~df.isnull().values
v = np.vstack(df.values[mask])
r,c = np.where(mask)
n = df.shape[1]
pos_mask = c == np.arange(n)[:,None]
out = pos_mask.dot(v)/np.bincount(c).astype(float)[:,None]
df_out1 = pd.DataFrame(out)

示例输出 -

In [328]: df_out1
Out[328]: 
     0    1    2    3
0  4.0  0.0  1.0  6.0
1  2.0  3.5  4.0  5.0
2  5.0  3.0  5.0  4.0

方法 #3:再向量化一个

利用np.add.reduceat得到那些mean-reductions-

mask = ~df.T.isnull().values
v = np.vstack(df.values.T[mask])
count = mask.sum(1)
out0 = np.add.reduceat(v, np.r_[0,count.cumsum()[:-1]])
out = out0/count[:,None].astype(float)
df_out2 = pd.DataFrame(out)