2017-09-15 41 views
1

我在每个单元格中都有一个16x10的熊猫数据框,每个数组中有1x35000个数组(或NaN)。我想为每一列采用元素明显的意思。Python:获取数据框中多个数组的元素平均数

 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-loops?

+1

考虑到混合的dtype数据(使用NaN),我认为每个单元格迭代执行的意思可能是这里的方法。 – Divakar

+0

我希望避免for-loops:p –

+0

然后检查[this post]中的两个矢量化解决方案(https://stackoverflow.com/a/46248304/3293881)。 – Divakar

回答

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 

如果你坚持你的形状预sented

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] 
+0

非常感谢!非常聪明的想法!如果可能,我有两个后续问题?首先,我真的不明白'groupby(level = 1)'在做什么 - 如果在这一步之后我输出'g',它只会显示'',你可以用elloborate在那?其次,'g.mean(axis = 0)'应该和'g.apply(np.sum,axis = 0)/ g.size()'一样,对吗? –

2

方法一:糊涂的

鉴于混合D型输入数据,我们可以通过对性能效率要循环。因此,使用.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取代th的方法Ë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) 
+0

非常感谢您的努力Divakar!似乎有很多解决这个问题的方法。我想我会用piRSquared的答案,它有点短,很容易理解。 –