基于条件拼接实现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'列(字符串)

期望输出
- 新增'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
相关产品推荐
相关产品推荐

