Python按课程分组并将字符串主题转为二进制列的问题
问题描述
我有一个大型CSV文件,每行对应一门学校课程,每门课程带有一个或多个以分号分隔的字符串主题标签。需要实现两个需求:
- 将每个主题转为独立列,用1表示课程包含该主题,0表示不包含;
- 对重复的课程进行分组合并,同一课程的所有关联主题均标记为1。
我尝试了一段Pandas代码,但所有二进制列结果都为0,现寻求正确实现方法。
示例输入表格:
| school name | department | course name | topics |
|---|---|---|---|
| A | A1 | X | fruit; vegetable |
| A | A1 | Y | fruit; grains |
| B | B1 | Z | fruit; vegetable; sweets |
| C | C1 | XX | fruit; poultry |
期望输出表格:
| school name | department | course name | fruit | vegetable | grains | sweets | poultry |
|---|---|---|---|---|---|---|---|
| A | A1 | X | 1 | 1 | 0 | 0 | 0 |
| A | A1 | Y | 1 | 0 | 1 | 0 | 0 |
| B | B1 | Z | 1 | 1 | 0 | 1 | 0 |
| C | C1 | XX | 1 | 0 | 0 | 0 | 1 |
现有代码:
import pandas as pd import io df = pd.read_csv(io.BytesIO(uploaded['topics.csv'])) x = df.pop("Final Topic").str.split(r"\s*;\s*").explode() x = pd.crosstab(x.index, x).add_prefix("topic ") df = pd.concat([df, x], axis=1)
解决方案
问题原因
代码出现全0结果的核心问题是列名不匹配:CSV中的主题列是topics,但代码里用了df.pop("Final Topic"),取出的是不存在的列,后续交叉表自然全为0。同时原代码也未处理重复课程的合并需求。
正确实现步骤
- 拆分
topics列,将分号分隔的主题转为每行一个主题的格式; - 基于课程的唯一标识(学校、院系、课程名)分组,生成主题的二进制标记,确保重复课程的所有主题都标记为1;
- 合并处理后的主题列与原数据集,得到最终结果。
完整代码
import pandas as pd import io # 读取CSV文件 df = pd.read_csv(io.BytesIO(uploaded['topics.csv'])) # 拆分主题列并展开为每行一个主题 split_topics = df['topics'].str.split(r'\s*;\s*', expand=True).stack().reset_index(level=1, drop=True).rename('topic') # 合并原数据与拆分后的主题,生成二进制主题列并合并重复课程 df_with_topics = df.drop('topics', axis=1).join(split_topics) result = df_with_topics.pivot_table( index=['school name', 'department', 'course name'], columns='topic', aggfunc='max', # 用max确保同一课程的主题只要出现过就标记为1 fill_value=0 ).reset_index() print(result)
代码说明
- 修正了列名错误,使用CSV实际存在的
topics列进行拆分; stack()和reset_index将拆分后的多列主题转换为每行一个主题的格式,便于后续处理;pivot_table通过指定课程的唯一标识作为索引,自动合并重复课程,aggfunc='max'保证同一课程的关联主题全部标记为1,fill_value=0填充未出现的主题;reset_index()将索引列转回普通列,输出格式与示例完全匹配。
内容的提问来源于stack exchange,提问作者bvecc
相关产品推荐
相关产品推荐

