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

按学生分组统计不同进度等级活动次数的Pandas实现问题

问题:按STUDENT_ID分组统计不同prog_level的活动次数

现有数据

STUDENT_ID STUDENT_ACTIVITY_SESSION_ID NODE_NAME   ACTIVITY_NAME   prog_level
FredID  gobbledeegook1  Node1   MyActivity1 pass
FredID  gobbledeegook2  Node1   MyActivity1 pass
FredID  gobbledeegook3  Node2   MyActivity2 pass
JaniceID    gobbledeegook4  Node3   MyActivity3 stay
JaniceID    gobbledeegook5  Node3   MyActivity3 stay
JaniceID    gobbledeegook5  Node3   MyActivity3 fail

期望结果

STUDENT_ID attempts_pass   attempts_fail   attempts_stay
FredID  3       0       0
JaniceID    0       1       2

尝试过的方案及问题

方案1:循环分组生成列名

代码如下:

def std_attempts_by_prog_level(df):
    dict_fields = {}
    df_by_prog_level = df.groupby('prog_level')['STUDENT_ACTIVITY_SESSION_ID']
    for name, group in df_by_prog_level:
        x = group.count() 
        dict_fields["attempts_" + name] = x

    return pd.Series(dict_fields)   
  
df.groupby('STUDENT_ID').apply(std_attempts_by_prog_level).reset_index()

问题:运行结果需要二次透视处理,不符合预期格式。

方案2:透视表手动命名字段

代码如下:

df_temp=df.groupby(['STUDENT_ID', 'prog_level'],as_index=False)['STUDENT_ACTIVITY_SESSION_ID'].count().pivot(index='STUDENT_ID', columns='prog_level').rename({'cancel':'attempts_cancel', 'fail':'attempts_fail', 'in_progress':'attempts_in_progress', 'pass':'attempts_pass'}, axis=1)

print(df_temp.columns)

问题:生成了MultiIndex列,难以和其他学生统计指标合并:

MultiIndex([('STUDENT_ACTIVITY_SESSION_ID',      'attempts_cancel'),
            ('STUDENT_ACTIVITY_SESSION_ID',        'attempts_fail'),
            ('STUDENT_ACTIVITY_SESSION_ID', 'attempts_in_progress'),
            ('STUDENT_ACTIVITY_SESSION_ID',        'attempts_pass')],
           names=[None, 'prog_level'])

解决方案

方法1:用pivot_table一步到位

直接使用pivot_table聚合并设置列名,无需处理MultiIndex:

import pandas as pd

# 读取数据(示例)
data = [
    ["FredID", "gobbledeegook1", "Node1", "MyActivity1", "pass"],
    ["FredID", "gobbledeegook2", "Node1", "MyActivity1", "pass"],
    ["FredID", "gobbledeegook3", "Node2", "MyActivity2", "pass"],
    ["JaniceID", "gobbledeegook4", "Node3", "MyActivity3", "stay"],
    ["JaniceID", "gobbledeegook5", "Node3", "MyActivity3", "stay"],
    ["JaniceID", "gobbledeegook5", "Node3", "MyActivity3", "fail"]
]
df = pd.DataFrame(data, columns=["STUDENT_ID", "STUDENT_ACTIVITY_SESSION_ID", "NODE_NAME", "ACTIVITY_NAME", "prog_level"])

# 生成统计结果
result = pd.pivot_table(
    df,
    index="STUDENT_ID",
    columns="prog_level",
    values="STUDENT_ACTIVITY_SESSION_ID",
    aggfunc="count",
    fill_value=0  # 空值填充为0
)

# 重命名列,添加attempts_前缀
result.columns = [f"attempts_{col}" for col in result.columns]

# 重置索引,让STUDENT_ID成为普通列
result = result.reset_index()

print(result)

运行结果:

STUDENT_ID  attempts_fail  attempts_pass  attempts_stay
0     FredID              0              3              0
1   JaniceID              1              0              2

方法2:修正方案2的MultiIndex问题

如果坚持用原分组+透视的方式,可以合并MultiIndex层级,把列名改成单层:

# 先分组统计
df_grouped = df.groupby(["STUDENT_ID", "prog_level"])["STUDENT_ACTIVITY_SESSION_ID"].count().unstack(fill_value=0)

# 重命名列
df_grouped.columns = [f"attempts_{col}" for col in df_grouped.columns]

# 重置索引
df_grouped = df_grouped.reset_index()

print(df_grouped)

此方法同样能得到和方法1一致的结果,且列名是单层结构,方便和其他数据合并。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 18:23:08