2017-09-15 1 views
1

각 셀에 1x35000 배열 (또는 NaN)을 가진 16x10 팬더 데이터 프레임이 있습니다. 각 열에 대해 행에 대해 요소 별 평균을 취하고 싶습니다.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 

오해를 피하려면 : 첫 번째 열의 각 배열의 첫 번째 요소를 가져 와서 평균을 취하십시오. 그런 다음 첫 번째 열에서 각 배열의 두 번째 요소를 가져 와서 다시 평균을 취하십시오. 결국에는 각 열당 1x35000 배열로 1x10 데이터 프레임을 갖기를 원합니다. 배열은 이전 배열의 요소 별 평균이어야합니다.

 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 

당신은 사전에 평등 문제

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'를 출력하면''만 보여줍니다. 그거? 둘째,'g.mean (axis = 0)'은'g.apply (np.sum, axis = 0)/g.size()'와 똑같이해야합니다. –

2

접근 # 1 : 혼합 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을 사용하여 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의 대답을 사용할 것입니다. 조금 더 짧고 이해하기 쉽습니다. –

관련 문제