Python3中用apply调用函数匹配相似专业及过滤逻辑疑问
解决方案
1. 先标准化CIPCODE格式
你的初始预处理逻辑可能存在问题(比如zfill(7)会给带小数点的编码补前置零,导致格式混乱),先统一处理成无小数点的固定长度编码,方便后续匹配:
# 生成清洗后的CIPCODE:转字符串→去小数点→补零到6位(适配标准CIP编码长度) output_df["CIPCODE_clean"] = output_df["CIPCODE"].astype(str).str.replace('.', '', regex=False).str.zfill(6)
2. 修正相似专业查找函数
你的原函数有两个核心问题:没排除当前机构的UNITID,以及CIPCODE匹配逻辑不准确。以下是修正后的版本:
def find_similar_programs(row, df): current_cip = row['CIPCODE_clean'] current_type = row['type'] current_unitid = row['UNITID'] similar_programs = df[ # 只从其他机构筛选 (df['UNITID'] != current_unitid) & # 专业类型一致 (df['type'] == current_type) & # CIPCODE去小数点后前4位相同 (df['CIPCODE_clean'].str[:4] == current_cip[:4]) & # 剩余部分(整体编码)不同,满足"剩余位数必须不同"的要求 (df['CIPCODE_clean'] != current_cip) ] return similar_programs
逻辑说明:
- 如果你的CIPCODE有变长情况(比如超过6位),可以把
str[:4] == current_cip[:4]改成str.startswith(current_cip[:4]),适配不同长度的编码前缀匹配 - 加入
UNITID != current_unitid确保不会匹配当前机构自身的专业
3. 正确调用函数
场景1:针对单个指定UNITID查找相似专业
如果是要给某一个特定机构(比如target_unitid = 12345)找所有相似专业:
target_unitid = 12345 # 先取出目标机构的所有专业 target_programs = output_df[output_df['UNITID'] == target_unitid] # 收集所有匹配的相似专业 all_similar = pd.DataFrame() for _, row in target_programs.iterrows(): similar = find_similar_programs(row, output_df) all_similar = pd.concat([all_similar, similar], ignore_index=True) # 去重,避免同一个相似专业被多次匹配 all_similar = all_similar.drop_duplicates()
场景2:给原DataFrame每行添加相似专业信息
如果要给每个专业行添加对应的相似专业数量或详情:
# 添加相似专业数量列 output_df['similar_count'] = output_df.apply( lambda row: len(find_similar_programs(row, output_df)), axis=1 ) # 添加相似专业的详细列表(比如包含UNITID、原CIPCODE) output_df['similar_programs'] = output_df.apply( lambda row: find_similar_programs(row, output_df)[['UNITID', 'CIPCODE', 'program_name']].to_dict('records'), axis=1 )
4. 大数据量优化建议
如果你的DataFrame行数很多,逐行apply效率很低,可以用分组向量化操作替代:
# 先按"专业类型+CIP前4位"分组 output_df['CIP_PREFIX'] = output_df['CIPCODE_clean'].str[:4] groups = output_df.groupby(['type', 'CIP_PREFIX']) # 对每个分组,批量生成相似专业 def process_group(group): group['similar_programs'] = group.apply( lambda row: group[group['UNITID'] != row['UNITID']].to_dict('records'), axis=1 ) return group output_df = groups.apply(process_group).reset_index(drop=True)
这种方式比逐行处理快数倍,适合大规模数据集。
内容的提问来源于stack exchange,提问作者analyst92
相关产品推荐
相关产品推荐

