1

我有一个 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 循环的情况下优雅地到达那里?

4

2 回答 2

3

设置

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]
于 2017-09-15T22:08:59.283 回答
2

方法#1:循环

给定混合 dtype 输入数据,我们可能希望循环以提高性能。因此,使用显式循环或在引擎盖下使用 of的循环.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)
于 2017-09-15T22:40:35.253 回答