【问题标题】:Merge Similar Strings Python合并相似的字符串 Python
【发布时间】:2019-02-21 10:14:03
【问题描述】:

我有两个字符串

string1 = "apple banna kiwi mango"
string2 = "aple banana mango lemon"

我想要这两个字符串相加的结果(不是串联),即结果应该是这样的

result = "apple banana kiwi mango lemon"

我目前的方法相当简单。

  1. 标记多行字符串(以上字符串是标记后的),去除任何噪音(特殊/换行符/空字符串)
  2. 下一步是识别字符串的余弦相似度,如果大于0.9,那么我将其中一个字符串添加到最终结果中

现在,问题来了。它不包括一个字符串包含一个单词的一半而另一个包含单词的另一半(或在某些情况下是正确的单词)的部分。我还在我的脚本中添加了this 函数。但问题仍然存在。任何有关如何推进这一点的帮助表示赞赏。

def text_to_vector(text):
     words = WORD.findall(text)
     return Counter(words)

def get_cosine(vec1, vec2):
     intersection = set(vec1.keys()) & set(vec2.keys())
     numerator = sum([vec1[x] * vec2[x] for x in intersection])

     sum1 = sum([vec1[x]**2 for x in vec1.keys()])
     sum2 = sum([vec2[x]**2 for x in vec2.keys()])
     denominator = math.sqrt(sum1) * math.sqrt(sum2)

     if not denominator:
        return 0.0
     else:
        return float(numerator) / denominator


def merge_string(string1, string2):
    i = 0
    while not string2.startswith(string1[i:]):
        i += 1

    sFinal = string1[:i] + string2
    return sFinal

for item in c:
for j in d:
    vec1 = text_to_vector(item)
    vec2 = text_to_vector(j)
    r = get_cosine(vec1, vec2)
    if r > 0.5:
        if r > 0.85:
            final.append(item)
            break
        else:
            sFinal = merge_string(item, j)
            #print("1.", len(sFinal), len(item), len(j))
            if len(sFinal) >= len(item) + len(j) -8:
                sFinal = merge_string(j, item)
                final.append(sFinal)
                #print("2.", len(sFinal), len(item), len(j))
                temp.append([item, j])
                break

【问题讨论】:

  • 好主意!你试过什么?
  • 我已经提到了我的方法。你也需要代码吗?
  • @JackDaniels 是的,您需要向我们展示您已经尝试过的内容。
  • 好的,让我更新一下。
  • 我认为没有正确拼写单词的字典或两个以上列表的情况下没有正确的方法可以做到这一点,因此您可以应用某种“多数票”可供选择的变体。

标签: python regex string text nlp


【解决方案1】:

困难的部分是检查单词是否是有效的英文单词。

为此,您必须使用字典来检查单词,或者使用 nltk。

     pip install nltk  

     from nltk.corpus import wordnet  

     set([w for w in (string1 + string2).split() if  wordnet.synsets(w)]) 

     Out[41]: {'apple', 'banana', 'kiwi', 'lemon', 'mango'}

要捕获数字,如果存在,请添加 isdigit()。

st1 = 'Includes Og Added Sugars'

st2 = 'Includes 09 Added Sugars 09'


set([w for w in (st1 + st2).split() if  (wordnet.synsets(w) or w.isdigit())])

Out[30]: {'09', 'Added', 'Includes', 'Sugars'}

要捕获 g、mg 之类的缩写,请添加 re.match()。

set([w for w in (st1 + st2).split() if  (wordnet.synsets(w) or w.isdigit() or re.match(r'\d+g|mg',w))])

Out[40]: {'09', '0g', 'Added', 'Includes', 'Sugars'}

【讨论】:

  • 这似乎是(接近)正确的方法,但结果很奇怪。你永远不会“修复”w,那么结果中怎么会有两个“香蕉”,第二个正确拼写的“芒果”在哪里?
  • @tobias_k。感谢您的评论。我错过了重复的单词..更改为设置,是吗...
  • 我会试试这个。我已经尝试过 symspell 但这并没有太大帮助。但会试一试,并会在这里更新。
  • @LetzerWille 它似乎不起作用。就像在这种情况下 ['Includes Og added Sugars/', 'Includes 09 added Sugars 09'],这种组合似乎不起作用。我也需要按原样排列结果。我希望更多的是动态解决方案,而不是静态解决方案。我已经尝试symspell 进行更正,但效果不佳。无论如何,不​​寻找这样的更正,只需要上面有问题的示例中的最终输出。
  • @JackDaniels,它对我有用。 st1 = '包括 Og 添加糖' st2 = '包括 09 添加糖 09' set([w for w in (st1 + st2).split() if wordnet.synsets(w)]) Out[22]: {'Added ', '包括', '糖'}
【解决方案2】:

你听说过 Levenshtein 的距离吗?我建议以下算法:

  1. 将列表拆分为元素(string1.split(" "))

  2. 循环通过list(string1)。在它内部循环通过list(string2),如果 Levenshtein 的两个元素的距离小于 3,则将元素推送到结果数组。

  3. 返回result

for i in list(string1): for k in list(string2): if levenshtein(i,k) < 3: res.append(i)

【讨论】:

  • 我试过这个以及 soundex。但问题是我应该推动哪个词,推动两个更大的词在这里并不总是答案。
猜你喜欢
  • 2017-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-15
  • 1970-01-01
  • 1970-01-01
  • 2019-03-03
  • 1970-01-01
相关资源
最近更新 更多