2017-09-15 97 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的答案,它有點短,很容易理解。 –