如何在Pandas中提取两列字符串差异并生成新列?
在Pandas数据框中生成字符串差异对比列
需求与示例
你需要在Pandas数据框中新增一列colC,用来展示colA和colB两列字符串的差异。
原始数据
| colA | colB |
|---|---|
| this is test | this is a testing |
期望结果
| colA | colB | colC |
|---|---|---|
| this is test | this is a testing | this is a ____ |
现有代码
你已经实现了字符串差异对比的函数,但不清楚如何将其应用到数据框的列上:
import re import difflib def tokenize(s): return re.split('\s+', s) def untokenize(ts): return ' '.join(ts) def equalize(s1, s2): l1 = tokenize(s1) l2 = tokenize(s2) res1 = [] res2 = [] prev = difflib.Match(0,0,0) for match in difflib.SequenceMatcher(a=l1, b=l2).get_matching_blocks(): if (prev.a + prev.size != match.a): for i in range(prev.a + prev.size, match.a): res2 += ['_' * len(l1[i])] res1 += l1[prev.a + prev.size:match.a] if (prev.b + prev.size != match.b): for i in range(prev.b + prev.size, match.b): res1 += ['_' * len(l2[i])] res2 += l2[prev.b + prev.size:match.b] res1 += l1[match.a:match.a+match.size] res2 += l2[match.b:match.b+match.size] prev = match return untokenize(res1), untokenize(res2)
该函数对示例字符串的输出为:('this is a test _______', 'this is a ____ testing')。
解决方案
1. 基础应用:用apply逐行处理
通过pandas.DataFrame.apply()可以对数据框的每一行调用equalize函数,提取需要的结果生成colC。
步骤:
首先导入pandas并构造示例数据框:
import pandas as pd # 构造示例数据框 df = pd.DataFrame({ 'colA': ['this is test'], 'colB': ['this is a testing'] })
然后可以选择两种方式生成colC:
# 方式一:自定义单行处理函数,更易维护 def generate_colC(row): # 调用equalize函数获取对比结果 res_a, res_b = equalize(row['colA'], row['colB']) # 根据期望结果,移除res_b末尾的" testing"部分 return res_b.replace(" testing", "") df['colC'] = df.apply(generate_colC, axis=1)
# 方式二:用lambda简化代码,适合简单场景 df['colC'] = df.apply(lambda row: equalize(row['colA'], row['colB'])[1].replace(" testing", ""), axis=1)
运行后,数据框会生成符合期望的colC列。
2. 空值与异常处理
如果数据框中存在空值,建议在equalize函数中添加判断逻辑,避免报错:
def equalize(s1, s2): # 处理空值情况 if pd.isna(s1) or pd.isna(s2): return "", "" l1 = tokenize(s1) l2 = tokenize(s2) res1 = [] res2 = [] prev = difflib.Match(0,0,0) for match in difflib.SequenceMatcher(a=l1, b=l2).get_matching_blocks(): if (prev.a + prev.size != match.a): for i in range(prev.a + prev.size, match.a): res2 += ['_' * len(l1[i])] res1 += l1[prev.a + prev.size:match.a] if (prev.b + prev.size != match.b): for i in range(prev.b + prev.size, match.b): res1 += ['_' * len(l2[i])] res2 += l2[prev.b + prev.size:match.b] res1 += l1[match.a:match.a+match.size] res2 += l2[match.b:match.b+match.size] prev = match return untokenize(res1), untokenize(res2)
内容的提问来源于stack exchange,提问作者trombonebraveheart
相关产品推荐
相关产品推荐

