2017-07-16 117 views
4

現狀

我有一個熊貓數據幀定義如下:熊貓:分組和聚合具有多種功能

import pandas as pd 

headers = ['Group', 'Element', 'Case', 'Score', 'Evaluation'] 
data = [ 
    ['A', 1, 'x', 1.40, 0.59], 
    ['A', 1, 'y', 9.19, 0.52], 
    ['A', 2, 'x', 8.82, 0.80], 
    ['A', 2, 'y', 7.18, 0.41], 
    ['B', 1, 'x', 1.38, 0.22], 
    ['B', 1, 'y', 7.14, 0.10], 
    ['B', 2, 'x', 9.12, 0.28], 
    ['B', 2, 'y', 4.11, 0.97], 
] 
df = pd.DataFrame(data, columns=headers) 

它看起來像這樣在控制檯輸出:

Group Element Case Score Evaluation 
0  A  1 x 1.40  0.59 
1  A  1 y 9.19  0.52 
2  A  2 x 8.82  0.80 
3  A  2 y 7.18  0.41 
4  B  1 x 1.38  0.22 
5  B  1 y 7.14  0.10 
6  B  2 x 9.12  0.28 
7  B  2 y 4.11  0.97 

問題

我想對執行分組和彙總操作會給我下面的結果數據框:

Group Max_score_value Max_score_element Max_score_case Min_evaluation 
0  A    9.19     1    y   0.41 
1  B    9.12     2    x   0.10 

要澄清的詳細信息:我想組由Group列,然後應用聚合,得到以下結果列:

  • Max_score_value:來自Score列的組最大值。
  • Max_score_element:從對應於所述基團的最大ScoreElement列的值。
  • Max_score_case:從對應於所述基團的最大ScoreCase列的值。
  • Min_evaluation:從Evaluation列中的基團的最小值。因此

嘗試遠

我來爲分組和聚集下面的代碼:

result = (
    df.set_index(['Element', 'Case']) 
    .groupby('Group') 
    .agg({'Score': ['max', 'idxmax'], 'Evaluation': 'min'}) 
    .reset_index() 
) 
print(result) 

這給作爲輸出:

Group Score   Evaluation 
      max idxmax  min 
0  A 9.19 (1, y)  0.41 
1  B 9.12 (2, x)  0.10 

由於你可以看到基本數據在那裏,但它還不是我需要的格式。這是我努力的最後一步。有沒有人有這樣的想法來生成我想要的格式的結果數據框?

回答

4

result數據幀開始,可以在兩個步驟中的變換如下,以所需的格式:

# collapse multi index column to single level column 
result.columns = [y + '_' + x if y != '' else x for x, y in result.columns] 
​ 
# split the idxmax column into two columns 
result = result.assign(
    max_score_element = result.idxmax_Score.str[0], 
    max_score_case = result.idxmax_Score.str[1] 
).drop('idxmax_Score', 1) 

result 

#Group max_Score min_Evaluation max_score_case max_score_element 
#0 A  9.19    0.41    y     1 
#1 B  9.12    0.10    x     2 

另一種從原始df使用join開始,這可能不那麼有效但更簡練類似@ tarashypka的想法:

(df.groupby('Group') 
    .agg({'Score': 'idxmax', 'Evaluation': 'min'}) 
    .set_index('Score') 
    .join(df.drop('Evaluation',1)) 
    .reset_index(drop=True)) 

#Evaluation Group Element Case Score 
#0  0.41  A  1  y 9.19 
#1  0.10  B  2  x 9.12 

與示例數據集天真時間:

%%timeit 
(df.groupby('Group') 
.agg({'Score': 'idxmax', 'Evaluation': 'min'}) 
.set_index('Score') 
.join(df.drop('Evaluation',1)) 
.reset_index(drop=True)) 
# 100 loops, best of 3: 3.47 ms per loop 

%%timeit 
result = (
    df.set_index(['Element', 'Case']) 
    .groupby('Group') 
    .agg({'Score': ['max', 'idxmax'], 'Evaluation': 'min'}) 
    .reset_index() 
) 
​ 
result.columns = [y + '_' + x if y != '' else x for x, y in result.columns] 
​ 
result = result.assign(
    max_score_element = result.idxmax_Score.str[0], 
    max_score_case = result.idxmax_Score.str[1] 
).drop('idxmax_Score', 1) 
# 100 loops, best of 3: 7.61 ms per loop 
+2

哦,明確設定指標和加入後這是一個不錯的改進。 – tarashypka

+0

我很高興從這裏所有海報的優秀答案。我認爲現在我會用Psidom的答案中的'join'來解決這個問題,因爲我喜歡低冗長度。沒關係,這是慢一點,因爲我當前程序中的性能瓶頸在其他地方。 – Xukrao

2

這裏是pd.merge

>> r = df.groupby('Group') \ 
>>  .agg({'Score': 'idxmax', 'Evaluation': 'min'}) \ 
>>  .rename(columns={'Score': 'idx'}) 
>> for c in ['Score', 'Element', 'Case']: 
>> r = pd.merge(r, df[[c]], how='left', left_on='idx', right_index=True) 
>> r.drop('Score_idx', axis=1).rename(columns={'Score': 'Max_score_value', 
>>            'Element': 'Max_score_element', 
>>            'Case': 'Max_score_case'}) 
     Evaluation Max_score_value Max_score_element Max_score_case 
Group                
A   0.41    9.19     1    y 
B   0.10    9.12     2    x 

可能的解決方案雖然它提供了所需的輸出,我不知道,如果它不是有效的小於你接近。

1

您可以使用apply而不是agg來一次構建所有列。

result = (
    df.groupby('Group').apply(lambda x: [np.max(x.Score), 
           df.loc[x.Score.idxmax(),'Element'], 
           df.loc[x.Score.idxmax(),'Case'], 
           np.min(x.Evaluation)]) 
     .apply(pd.Series) 
     .rename(columns={0:'Max_score_value', 
         1:'Max_score_element', 
         2:'Max_score_case', 
         3:'Min_evaluation'}) 
     .reset_index() 
) 



result 
Out[9]: 
    Group Max_score_value Max_score_element Max_score_case Min_evaluation 
0  A    9.19     1    y   0.41 
1  B    9.12     2    x   0.10 
1

我就拿

g = df.set_index('Group').groupby(level='Group', group_keys=False) 

result = g.apply(
    pd.DataFrame.nlargest, n=1, columns='Score' 
) 

def f(x): 
    x = 'value' if x == 'Score' else x 
    return 'Max_score_' + x.lower() 

result.drop('Evaluation', 1).rename(columns=f).assign(
    Min_evaluation=g.Evaluation.min().values).reset_index() 

    Group Max_score_element Max_score_case Max_score_value Min_evaluation 
0  A     1    y    9.19   0.41 
1  B     2    x    9.12   0.10