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

如何在Pandas DataFrame中高效查询祖先并计算团队平均战力

高效计算游戏用户团队平均战力的优化方案需求

我开发了一款拥有百万级用户的游戏,每个用户默认是自身的团队队长,也可将队长更换为其他用户,因此可能出现循环依赖。现有如下结构的Pandas DataFrame:

user_id | leader_id | power
---|---|----
1 | 1 | 10
2 | 3 | 20
3 | 2 | 30
4 | 5 | 40
5 | 5 | 50

我关注的团队定义为用户自身及其层级之下的成员,示例如下:

user_id | leader_id | power | team
---|---|----|----
1 | 1 | 10 | [1]
2 | 3 | 20 | [2, 3]
3 | 2 | 30 | [2, 3]
4 | 5 | 40 | [4]
5 | 5 | 50 | [4, 5]

我需要新增一列,计算该用户团队的平均战力。但现有两种实现方法(NetworkX方案、自定义缓存方案)在5万行数据上运行速度仍不理想(分别耗时约53秒、38秒),特此寻求更高效的实现方案。测试代码如下:

import time

import networkx as nx
import numpy as np
import pandas as pd

from tests.pandas_test_utils import assert_frame_equal


def get_team_power_using_networkx(df):
    G = nx.from_pandas_edgelist(df, source='user_id', target='leader_id', create_using=nx.DiGraph())
    ancestors = {node: nx.ancestors(G, node) for node in G.nodes()}

    user_ids = df['user_id'].values

    team_ids_list = [list(ancestors.get(user_id, set()) | {user_id}) for user_id in user_ids]

    hierarchal_scores = [df.loc[df['user_id'].isin(team_ids), "power"].dropna().values for team_ids in team_ids_list]
    avg_scores = [np.sum(scores) / len(scores) if len(scores) > 0 else np.nan for scores in hierarchal_scores]
    df["team_power"] = np.where(np.isnan(avg_scores), np.nan, np.round(avg_scores).astype(int))

    return df


def get_team_power_using_custom(df):
    G = nx.from_pandas_edgelist(df, source='user_id', target='leader_id', create_using=nx.DiGraph())

    def get_ancestors(node):
        if node in ancestors:
            return ancestors[node]
        ancestors[node] = set()
        for parent in G.predecessors(node):
            ancestors[node].add(parent)
            ancestors[node].update(get_ancestors(parent))
        return ancestors[node]

    ancestors = {}
    user_ids = df['user_id'].values

    team_ids_list = [list(get_ancestors(user_id) | {user_id}) for user_id in user_ids]

    hierarchal_scores = [df.loc[df['user_id'].isin(team_ids), "power"].dropna().values for team_ids in team_ids_list]
    avg_scores = [np.sum(scores) / len(scores) if len(scores) > 0 else np.nan for scores in hierarchal_scores]
    df["team_power"] = np.where(np.isnan(avg_scores), np.nan, np.round(avg_scores).astype(int))

    return df


## Test if it works
"""
user 1 is alone. team is [1] and average power is [10]
user 2 and 3 have each other as leaders. both have teams consisting of [2, 3] and average power is [25]
user 4 reports to user 5. team is [4] and average power is [40]
user 5 reports to themself. team is [4, 5, 6, 7] and average power is [53] -> (40 + 50 + 70) / 3
user 6 reports to user 5. team is [6, 7] and average power is [70]
user 7 reports to user 6 who reports to user 5. team is [7] and average power is [70]
user 8 reports to themself. team is [8] and average power is [np.nan]
"""
user_id = [1, 2, 3, 4, 5, 6, 7, 8]
leader_id = [1, 3, 2, 5, 5, 5, 6, 8]
power = [10, 20, 30, 40, 50, np.nan, 70, np.nan]
# Create the DataFrame
data = {'user_id': user_id, 'leader_id': leader_id, 'power': power, }
df = pd.DataFrame(data)
for func in [get_team_power_using_networkx, get_team_power_using_custom]:
    print(f"Testing: {func.__name__}")
    results = func(df)[["user_id", "team_power"]]
    expected_results = pd.DataFrame({"user_id": [1, 2, 3, 4, 5, 6, 7, 8], "team_power": [10, 25, 25, 40, 53, 70, 70, np.nan]})
    assert_frame_equal(results, expected_results)

## Test speed
num_rows = 50000
np.random.seed(42)
# Generate random values for each column
user_id = np.random.randint(1, 1000, size=num_rows)
leader_id = np.random.randint(1, 1000, size=num_rows)
power = np.random.uniform(0, 100, size=num_rows)
# Create the DataFrame
data = {'user_id': user_id, 'leader_id': leader_id, 'power': power, }
df = pd.DataFrame(data)
for func in [get_team_power_using_networkx, get_team_power_using_custom]:
    start_time = time.time()  # Record the start time
    func(df)
    end_time = time.time()  # Record the end time
    print(f"Time to run {func.__name__}:", end_time - start_time)

内容的提问来源于stack exchange,提问作者elthran

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 15:07:25