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

基于Course/Section列合并CSV多行数据的Pandas实现问题

解决CSV多行课程信息合并问题

问题分析

你的核心需求是将Course/Section列为空的补充行内容合并到上方的主课程行,最终保留每行对应一条完整课程记录。原代码逻辑方向正确,但可能因数据类型不统一或空值判断不准确导致未达预期。

修正后的逐行遍历方案(适合小数据集)

针对原代码的潜在问题,我们先统一数据类型并修正空值处理逻辑:

import pandas as pd

# 读取CSV文件(替换为你的文件路径)
df = pd.read_csv('your_course_data.csv')

# 1. 处理空值:将空字符串转为pd.NA,确保空行判断准确
df['Course/Section'] = df['Course/Section'].replace('', pd.NA)

# 2. 将所有列转为字符串类型,避免拼接时的类型错误
df = df.astype(str).replace('nan', pd.NA)

# 3. 从下往上遍历,合并补充行内容到主行
for i in range(len(df)-1, 0, -1):
    if pd.isna(df.loc[i, 'Course/Section']):
        for col in df.columns:
            if pd.notna(df.loc[i, col]):
                # 若主行该列已有值则拼接,否则直接赋值
                if pd.notna(df.loc[i-1, col]):
                    df.loc[i-1, col] = f"{df.loc[i-1, col]} {df.loc[i, col]}"
                else:
                    df.loc[i-1, col] = df.loc[i, col]

# 4. 删除补充行并重置索引
df = df.dropna(subset=['Course/Section']).reset_index(drop=True)

# 输出或保存结果
print(df)
# df.to_csv('merged_course_data.csv', index=False)

高效分组合并方案(适合大型CSV)

逐行遍历在数据量较大时效率极低,推荐使用分组聚合的方式,速度提升明显:

import pandas as pd

df = pd.read_csv('your_course_data.csv')

# 处理空值
df['Course/Section'] = df['Course/Section'].replace('', pd.NA)

# 创建分组键:用向前填充的课程编号将同一课程的行归为一组
df['group_id'] = df['Course/Section'].ffill()

# 定义合并函数:过滤空值后拼接所有非空内容
def merge_non_null(s):
    non_null_vals = s.dropna().astype(str)
    return ' '.join(non_null_vals)

# 按分组聚合,合并所有补充内容
merged_df = df.groupby('group_id', as_index=False).agg(merge_non_null)

# 删除临时分组列
merged_df = merged_df.drop(columns=['group_id'])

# 输出结果
print(merged_df)
# merged_df.to_csv('merged_course_data.csv', index=False)

关键说明

  • 两种方案都会将补充行的非空值追加到主行对应列,如果需要自定义分隔符(如换行、分号),只需修改拼接时的字符串(比如把' '换成'; ')。
  • 若你的CSV中存在'NaN'字符串而非真正的缺失值,需提前用replace替换为pd.NA。

内容的提问来源于stack exchange,提问作者Khalil Al Hooti

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 09:34:59