将具有相似(但略有不同)子字符串的字符串重新映射为相同结果

时间:2018-12-20 08:47:06

标签: python regex string pandas replace

我有一个如下数据框:

df = pd.DataFrame({
"group_code": ['111', '111', '111', '111', '111', '111', '111', '222', '222','222', '222', '222', '222'],
"ind_code": ['K M trading', 'K.M trad', 'KM trading LL', 'bill payment', 'pays', 'PayMent', 'Payer', 'Rev12','Rev11','13 rev','Rev13','Rev .!','REV 17']
})

我想对列中的所有值进行分组: 'K M trading', 'K.M trad', 'KM trading LL'"KM Trading"。 谁能帮助我?

我尝试了以下代码,但不起作用

 def replace_(row):
if 'pay' in row.lower():
    return 'Payment'
if 'rev' in row.lower():
    return 'Rev'
if 'km' in row.lower():
    return 'KM Trade'
else:
return row
df.ind_code = df.ind_code.apply(lambda row : replace_(row))
print(df)

4 个答案:

答案 0 :(得分:1)

您可以构建正则表达式的映射并使用字典调用Series.replace

mapping = {'pay' : 'Payment', 'rev' : 'Rev', 'km': 'KM Trading'}
for k, v in mapping.items():
    mapping['(?i).*' + r"\.?\s?".join(k) + '.*$'] = mapping.pop(k)

df.ind_code.replace(mapping, regex=True)

0     KM Trading
1     KM Trading
2     KM Trading
3        Payment
4        Payment
5        Payment
6        Payment
7            Rev
8            Rev
9            Rev
10           Rev
11           Rev
12           Rev
Name: ind_code, dtype: object

哪里

print(mapping)

{'(?i).*k\\.?\\s?m.*$': 'KM Trading',
 '(?i).*p\\.?\\s?a\\.?\\s?y.*$': 'Payment',
 '(?i).*r\\.?\\s?e\\.?\\s?v.*$': 'Rev'}

表示不区分大小写的替换,带有可选的句点和要替换的字符之间的空格。

答案 1 :(得分:0)

您可以尝试使用levenshtein距离来计算2个单词之间的距离。 基本上,此距离计算从字符串a到字符串b的单字符编辑(插入,删除或替换)的最小数量

例如,您可以将基本字符串“ km trading”与所有其他字符串进行比较,如果距离低于阈值,例如4,则可以确定该字符串是“ km trading”的变体。

def minimumEditDistance(s1,s2):
    if len(s1) > len(s2):
        s1,s2 = s2,s1
    distances = range(len(s1) + 1)
    for index2,char2 in enumerate(s2):
        newDistances = [index2+1]
        for index1,char1 in enumerate(s1):
            if char1 == char2:
                newDistances.append(distances[index1])
            else:
                newDistances.append(1 + min((distances[index1],
                                             distances[index1+1],
                                             newDistances[-1])))
        distances = newDistances
    return distances[-1]

dist = minimumEditDistance('km trading', 'K.M trad'.lower())
print(dist)

此代码摘自Rosetta Code,从纯粹的直觉上很难理解该算法,因此,我建议查看一些深入解释该算法的教程。

答案 2 :(得分:0)

Oren Revenge的回答很棒,这是针对您特定情况的更骇人的解决方案(尽管很容易扩展):

for pair in [('km','KM Trading'), ('pay', 'Payment'), ('rev', 'Rev')]:
    df1.ind_code = df1.ind_code.apply(lambda x: pair[1] if pair[0] in re.sub('\.', '', x.lower()).strip() else x)

答案 3 :(得分:0)

使用此代码,可能会对您有所帮助。 此代码使用“ difflib”中的序列匹配器技术。 有关更多详细信息,请参阅python软件包文档中的“ diffllib”。

import pandas as pd
import difflib

df = pd.DataFrame({
"group_code": ['111', '111', '111', '111', '111', '111', '111', '222', '222','222', '222', '222', '222'],
"ind_code": ['K M trading', 'K.M trad', 'KM trading LL', 'bill payment', 'pays', 'PayMent', 'Payer', 'Rev12','Rev11','13 rev','Rev13','Rev .!','REV 17']
})

a = "KM Trading"
ans = []
for val in df['ind_code']:
i = 0
seq=difflib.SequenceMatcher(None, a,val)
d = seq.ratio()*100
if d > 60:
ans.append(a)
else:
ans.append(val)

print (ans)