【问题标题】:Remapping strings with similar (but slightly differing) substrings to the same result将具有相似(但略有不同)子字符串的字符串重新映射到相同的结果
【发布时间】:2019-05-20 18:25:34
【问题描述】:

我有一个如下的数据框:

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)

【问题讨论】:

  • 涉及的“分组”在哪里?
  • 是 'K M trading'、'K.M trad'、'KM trading LL' 唯一的可能性还是有其他类似的字符串?
  • df.ind_code = df.ind_code.str.replace(r'k\.?\s?m\.? .*', 'KM Trading', case=False) 工作吗?
  • 'Rev12','Rev11','13 rev','Rev13','Rev .!','REV 17' 所有这些也属于类似的分组
  • @coldspeed 我总是对具有良好正则表达式技能的人印象深刻 :) 不确定 OP 是否正是在问这个问题,或者他/她是否想要更通用的东西:如何应用一般规则 @987654327 @到一个系列

标签: python regex string pandas replace


【解决方案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'}

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

【讨论】:

    【解决方案2】:

    您可以尝试使用 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,该算法很难凭直觉理解,因此我建议查看一些深入解释该算法的教程。

    【讨论】:

      【解决方案3】:

      Oren revenge 的回答太棒了,这里是针对您的特定情况的 hackier 解决方案(虽然很容易扩展):

      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)
      

      【讨论】:

        【解决方案4】:

        使用此代码,这可能会对您有所帮助。 此代码使用“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)
        

        【讨论】:

          猜你喜欢
          • 2023-03-10
          • 2021-02-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-11-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多