如何用Pandas按多列分组并将关联target字段加入min/max列
解决Pandas分组后关联target字段并格式化输出的问题
需求说明
按source、type列分组,计算每组similarity字段的min、max值,将对应target字段内容与min/max值拼接为「Target: [target值] ([similarity数值])」格式。
原始数据
data = [ {'source': 'Person1', 'target': 'Person2', 'type': 'bow', 'similarity': 0.636}, {'source': 'Person1', 'target': 'Person2', 'type': 'bigram', 'similarity': 0.040}, {'source': 'Person1', 'target': 'Person2', 'type': 'tfidf', 'similarity': 0.433}, {'source': 'Person1', 'target': 'Person3', 'type': 'bow', 'similarity': 0.699}, {'source': 'Person1', 'target': 'Person3', 'type': 'bigram', 'similarity': 0.171}, {'source': 'Person1', 'target': 'Person3', 'type': 'tfidf', 'similarity': 0.522} ]
当前问题
已通过df = df.groupby(['source','type']).similarity.agg(['min','max'])得到分组后的min/max值,但无法关联对应target字段并拼接成指定格式,询问是否需要用.loc定位后拼接或有其他更优方法。
解决方案
不需要单独用.loc循环定位,以下几种方法均可高效实现需求:
方法1:使用groupby.apply自定义处理每组
通过自定义函数处理每个分组,直接提取对应target并格式化输出:
import pandas as pd df = pd.DataFrame(data) def process_group(group): # 获取分组内similarity最小的行 min_row = group.loc[group['similarity'] == group['similarity'].min()] # 获取分组内similarity最大的行 max_row = group.loc[group['similarity'] == group['similarity'].max()] # 返回格式化后的结果 return pd.Series({ 'min': f"Target: {min_row['target'].iloc[0]} ({min_row['similarity'].iloc[0]})", 'max': f"Target: {max_row['target'].iloc[0]} ({max_row['similarity'].iloc[0]})" }) # 分组处理并生成结果 result = df.groupby(['source', 'type']).apply(process_group) print(result)
方法2:自定义函数配合agg实现
为agg方法传递自定义函数,直接在聚合时完成格式化:
import pandas as pd df = pd.DataFrame(data) def format_min(group): min_sim = group['similarity'].min() target = group.loc[group['similarity'] == min_sim, 'target'].iloc[0] return f"Target: {target} ({min_sim})" def format_max(group): max_sim = group['similarity'].max() target = group.loc[group['similarity'] == max_sim, 'target'].iloc[0] return f"Target: {target} ({max_sim})" # 聚合时调用自定义函数 result = df.groupby(['source', 'type']).agg( min=('similarity', format_min), max=('similarity', format_max) ) print(result)
方法3:通过transform标记极值行再合并
先标记每组的min/max行,再合并数据后格式化:
import pandas as pd df = pd.DataFrame(data) # 标记每组内similarity最小/最大的行 df['is_min'] = df['similarity'] == df.groupby(['source', 'type'])['similarity'].transform('min') df['is_max'] = df['similarity'] == df.groupby(['source', 'type'])['similarity'].transform('max') # 提取min和max对应的数据 min_data = df[df['is_min']][['source', 'type', 'target', 'similarity']].rename(columns={'target': 'min_target', 'similarity': 'min_sim'}) max_data = df[df['is_max']][['source', 'type', 'target', 'similarity']].rename(columns={'target': 'max_target', 'similarity': 'max_sim'}) # 合并数据并格式化输出 result = pd.merge(min_data, max_data, on=['source', 'type']) result['min'] = result.apply(lambda x: f"Target: {x['min_target']} ({x['min_sim']})", axis=1) result['max'] = result.apply(lambda x: f"Target: {x['max_target']} ({x['max_sim']})", axis=1) # 整理最终结果格式 result = result[['source', 'type', 'min', 'max']].set_index(['source', 'type']) print(result)
输出示例
三种方法最终输出结果一致,格式如下:
min max source type Person1 bigram Target: Person2 (0.04) Target: Person3 (0.171) bow Target: Person2 (0.636) Target: Person3 (0.699) tfidf Target: Person2 (0.433) Target: Person3 (0.522)
内容的提问来源于stack exchange,提问作者MartinCodes
相关产品推荐
相关产品推荐

