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

基于条件拼接实现Exchange联系人导入的数据处理求助

问题背景与需求

CSV包含虚构信息
Python on Kaggle w/ Pandas + Numpy

目标是导入/更新Exchange联系人,需要通过学生信息查找家长邮箱。

输入数据(CSV列)

  • 'Student ID'列(7位数字)
  • 'Parent ID'列(7位数字)
  • 'Student First Name'列(字符串)
  • 'Student Last Name'列(字符串)
  • 'Parent First Name'列(字符串)
  • 'Parent Last Name'列(字符串)

输入CSV

期望输出

  • 新增'Contacts'列
    *'Contacts'列需遵循以下格式:
    - 单个学生:"studentLastName, studentFirstName (parentLastName, parentFirstName)"
    - 多个学生:"studentLastName, student1FirstName, student2FirstName, & student3FirstName (parentLastName, parentFirstName)"

假设条件

  • 使用学生/家长ID判断关联关系
    • 许多学生/监护人同姓但无亲属关系
    • 许多学生有超过2位监护人
    • 许多学生与一位或多位监护人不同姓
    • 部分同姓兄弟姐妹拥有不同法定姓氏

我的尝试

1. 带if判断的嵌套for循环

for i in range(14):
    for j in range(14):
        if contacts.iloc[i]['parentID'] == contacts.iloc[j]['parentID'] and i!=j:
            hold = [contacts.iloc[i]['studentFirstName'], contacts.iloc[j]['studentFirstName']]
    print(hold)

预期结果:匹配相同Parent ID的不同行中,学生名字组成的列表(表示兄弟姐妹)
示例输出:

[[Uganda, Tiramisu], [Uganda, Tiramisu], [Ethernet, Persimmon], [Ethernet, Niagara], [Persimmon, Niagara]]

我刚接触DataFrames,习惯把数据当列表处理。

2. 结合numpy.where()的嵌套for循环

for i in range(14):
    for j in range(14):
        print(i, j)
        print(contacts.iloc[i]['parentID'], contacts.iloc[j]['parentID'])
        np.where(contacts.iloc[i]['parentID'] == contacts.iloc[j]['parentID'],
                    print(contacts.iloc[i]['studentFirstName'] + ' and ' + contacts.iloc[j]['studentFirstName']), print('1'))

预期结果:当Parent ID匹配时输出两个学生的名字,否则输出'1'
我搞不懂广播机制,感觉是print操作或者广播导致代码没效果。

考虑过的替代方案

pd.agg(), pd.groupby(), lambda functions, list comprehension

我是Pandas/Numpy/Python新手,练手时习惯先用for循环,再转列表推导式。感觉有多种方法能解决这个问题,求帮助。


解决方案

用Pandas的groupby+agg是最适合的方案,比手动循环高效得多,步骤如下:

1. 分组聚合信息

按Parent ID分组,收集该家长下的所有学生名,同时提取家长的姓名(同一个Parent ID下的家长信息应该一致,取第一条即可):

# 分组并聚合所需字段
grouped = contacts.groupby('Parent ID').agg(
    student_first_names=('Student First Name', list),
    student_last_name=('Student Last Name', 'first'),  # 若同家长下学生姓氏不同,可调整为list
    parent_first_name=('Parent First Name', 'first'),
    parent_last_name=('Parent Last Name', 'first')
).reset_index()

2. 生成符合格式的Contacts字符串

定义一个函数来处理单/多学生的格式:

def format_contact_string(row):
    first_names = row['student_first_names']
    last_name = row['student_last_name']
    parent_full = f"{row['parent_last_name']}, {row['parent_first_name']}"
    
    if len(first_names) == 1:
        return f"{last_name}, {first_names[0]} ({parent_full})"
    else:
        # 多个学生时,最后一个用&连接
        formatted_firsts = ', '.join(first_names[:-1]) + f", & {first_names[-1]}"
        return f"{last_name}, {formatted_firsts} ({parent_full})"

# 批量生成Contacts列
grouped['Contacts'] = grouped.apply(format_contact_string, axis=1)

3. 合并回原数据表(可选)

如果需要让原DataFrame的每一行都显示对应的Contacts,用merge关联:

final_result = contacts.merge(grouped[['Parent ID', 'Contacts']], on='Parent ID', how='left')

补充说明

  • 为什么不用嵌套循环:Pandas的分组操作是向量化处理,数据量大时比手动循环快几十倍,代码也更简洁
  • np.where的问题:它是用于数组的向量化判断,参数需要是能返回值的表达式,不能直接放print(因为print返回None),所以之前的写法会失效
  • 特殊情况处理:如果同家长下学生姓氏不同,把student_last_name的聚合方式改成list,再在格式化函数里调整输出逻辑即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 01:06:12