我的pandas数据框定义如下:
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
我想在df
上执行分组和聚合操作,它会为我提供以下结果数据框:
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
:Element
列中与组最大Score
值对应的值。Max_score_case
:Case
列中与组最大Score
值对应的值。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
正如您所看到的那样,基本数据已存在,但它还不是我需要的格式。这是我挣扎的最后一步。这里有没有人有一些好的想法,可以用我正在寻找的格式生成结果数据框?
答案 0 :(得分: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
答案 1 :(得分: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
虽然它提供了所需的输出,但我不确定它的效率是否低于你的方法。
答案 2 :(得分: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
答案 3 :(得分: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