You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何仅用DataFrame操作生成多玩家唯一组合的得分DataFrame?

问题

现有数据记录了两名玩家对战后,对应不同胜负结果的共享得分(数值仅为示例,与实际游戏逻辑无关)。需求如下:

  • 基于给定的DataFrame,生成包含4名玩家所有唯一对战组合的新DataFrame
  • 计算每个组合的总得分:比如P1&P2全胜得30分、P3&P4全胜得42分,二者相加就是这4人全胜组合的总得分72分

目前已能通过生成组合的方式实现,但数据量较大时代码冗余,询问是否仅通过merge、groupby、join、agg等DataFrame原生操作完成该需求。

附示例代码及数据:

import pandas as pd

data = {
    "Player_1": ["P1", "P1", "P1", "P1", "P2", "P2", "P2", "P2", "P1", "P1", "P1", "P1", "P3", "P3", "P3", "P3"],
    "Player_2": ["P2", "P2", "P2", "P2", "P3", "P3", "P3", "P3", "P4", "P4", "P4", "P4", "P4", "P4", "P4", "P4"],
    "Outcome_1": ["win", "win", "lose", "lose", "win", "win", "lose", "lose", "win", "win", "lose", "lose", "win", "win", "lose", "lose"],
    "Outcome_2": ["win", "lose", "win", "lose", "win", "lose", "win", "lose", "win", "lose", "win", "lose", "win", "lose", "win", "lose"],
    "Score": [30, 45, 12, 78, 56, 21, 67, 90, 15, 32, 68, 88, 42, 74, 8, 93]
}

df = pd.DataFrame(data)

print(df)

示例输出:

Player_1 Player_2 Outcome_1 Outcome_2  Score
0        P1       P2       win       win     30
1        P1       P2       win      lose     45
2        P1       P2      lose       win     12
3        P1       P2      lose      lose     78
4        P2       P3       win       win     56
5        P2       P3       win      lose     21
6        P2       P3      lose       win     67
7        P2       P3      lose      lose     90
8        P1       P4       win       win     15
9        P1       P4       win      lose     32
10       P1       P4      lose       win     68
11       P1       P4      lose      lose     88
12       P3       P4       win       win     42
13       P3       P4       win      lose     74
14       P3       P4      lose       win      8
15       P3       P4      lose      lose     93
解决方案

完全可以通过DataFrame原生操作实现,核心思路是先标准化对战组合、提取唯一胜负-得分映射,再生成所有无重叠的4人对战分组,最后关联得分并求和。步骤如下:

1. 标准化对战组合并提取唯一得分映射

先把无序的对战组合(比如(P1,P2)和(P2,P1))统一格式,同时保留每一组对战对应胜负结果的得分:

# 标准化对战组合:将玩家按字母排序,避免同一对战的正反序被视为不同组合
df['standard_pair'] = df.apply(lambda row: tuple(sorted([row['Player_1'], row['Player_2']])), axis=1)
# 提取唯一的「对战组合-胜负结果-得分」映射
match_score_map = df.groupby(['standard_pair', 'Outcome_1', 'Outcome_2'])['Score'].first().reset_index()

2. 生成所有无重叠的4人对战分组

通过组合工具生成所有合法的4人分组(即两组无重叠的两两对战):

from itertools import combinations

# 获取所有唯一玩家
all_players = df[['Player_1', 'Player_2']].stack().unique()
# 生成所有两两对战的基础组合
all_pairs = list(combinations(all_players, 2))
# 筛选出无重叠的4人分组(两组对战没有共同玩家)
valid_4player_groups = []
for idx, pair1 in enumerate(all_pairs):
    used_players = set(pair1)
    # 只遍历后续组合,避免重复分组(比如(P1,P2)+(P3,P4)和(P3,P4)+(P1,P2)视为同一组)
    for pair2 in all_pairs[idx+1:]:
        if not used_players.intersection(pair2):
            valid_4player_groups.append({'Pair1': pair1, 'Pair2': pair2})
# 转换为DataFrame
group_df = pd.DataFrame(valid_4player_groups)

3. 关联得分并计算组合总得分

通过笛卡尔积关联所有胜负结果,再分别匹配两组对战的得分,最后求和得到总得分:

# 提取所有唯一的胜负结果组合
all_outcomes = df[['Outcome_1', 'Outcome_2']].drop_duplicates()
# 生成「分组-胜负结果」的笛卡尔积,覆盖所有可能的胜负场景
full_result_df = group_df.merge(all_outcomes, how='cross')

# 关联第一组对战的得分
full_result_df = full_result_df.merge(
    match_score_map,
    left_on=['Pair1', 'Outcome_1', 'Outcome_2'],
    right_on=['standard_pair', 'Outcome_1', 'Outcome_2'],
    how='left'
).rename(columns={'Score': 'Score_Pair1'}).drop(columns='standard_pair')

# 关联第二组对战的得分
full_result_df = full_result_df.merge(
    match_score_map,
    left_on=['Pair2', 'Outcome_1', 'Outcome_2'],
    right_on=['standard_pair', 'Outcome_1', 'Outcome_2'],
    how='left'
).rename(columns={'Score': 'Score_Pair2'}).drop(columns='standard_pair')

# 计算该分组在当前胜负场景下的总得分
full_result_df['Total_Score'] = full_result_df['Score_Pair1'] + full_result_df['Score_Pair2']

最终的full_result_df就包含了所有4人对战组合在各种胜负情况下的总得分,全程使用merge、groupby等DataFrame原生操作,代码简洁且适合大数据量场景。


内容的提问来源于stack exchange,提问作者Cem Koçak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 14:58:12