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

Pandas带计数器两列嵌套循环活动统计及报错解决

问题场景
  • 基础数据结构:
    • 活动分类表df1:共两列,Type为活动大类,取值包含Sport、Studies两类;Activity为具体活动项,取值包含rowing、Surfing、Basketball、Dancing、science、Math、History等,实际业务场景下共30个活动子类别
    • 调研数据表df2:每条记录为学生活动参与的自然语言描述,格式类似Sarah does Basketball and Math
  • 计算需求:统计每条调研文本中,分属Sport、Studies大类的活动数量,最终输出包含三列的结果表:Student(原始调研文本)、Sports(运动类活动匹配计数)、Studies(学业类活动匹配计数)
  • 初始实现踩坑:最初尝试嵌套循环遍历分类表逐句匹配、手动创建分类列表/子表实现,代码冗余且效果差;后续写的测试代码运行触发类型错误,无法定位问题。
报错原因
  1. 核心映射逻辑错误:测试代码中把activity_type构造为「大类名: 对应活动列表」的字典结构,但后续匹配逻辑是拿拆分后的单个单词直接调用activity_type.get(activity),该字典的键是大类名,根本无法通过单个活动名查询到所属分类,逻辑完全不匹配。
  2. 类型兼容问题:旧版本pandas的pd.json_normalize在处理序列中存储的Counter对象时,会触发隐式类型转换失败,抛出TypeError: int() argument must be a string, a bytes-like object or a number, not 'Counter'报错。
可行实现方案

核心思路是先构造单个活动名(统一转小写做归一化)到所属大类的映射字典,再逐行拆分调研文本做匹配计数,避免多层嵌套循环,代码可维护性更高,适配30个甚至更多活动子类的扩展需求。

import pandas as pd
from collections import Counter

# 读取本地数据文件
df1 = pd.read_csv('df1.csv')
df2 = pd.read_csv('df2.csv')

# 构造正确的活动-大类映射字典,统一转小写消除大小写匹配差异
activity_type_map = dict(zip(
    df1['Activity'].str.strip().str.lower(),
    df1['Type'].str.strip().str.lower()
))

# 定义单条文本的活动分类计数函数
def count_type(text):
    words = text.strip().lower().split()
    counter = Counter()
    for word in words:
        # 命中活动映射则对应大类计数+1
        if word in activity_type_map:
            counter[activity_type_map[word]] += 1
    return counter

# 批量计算所有文本的分类计数,展开为DataFrame
count_result = pd.json_normalize(df2['Student'].apply(count_type))
# 空值填0,转为整数类型,列名对齐需求格式
count_result = count_result.fillna(0).astype(int).rename(columns={
    'sport': 'Sports',
    'studies': 'Studies'
})
# 拼接原始文本和计数结果,得到最终表
final_df = pd.concat([df2, count_result], axis=1)

注意:如果后续活动项存在多词组的情况(比如table tennis),直接按空格拆分单词会导致匹配失败,此时可将活动列表按字符串长度从长到短排序,通过正则匹配或字符串遍历的方式做计数,避免拆分漏匹配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 22:12:51