Получить процент сходства для нескольких строк - PullRequest
0 голосов
/ 16 декабря 2018

Есть ли внутри Python какая-либо функция, которая может принимать несколько строк строк и возвращать процент их сходства?что-то вроде SequenceMatcher, но для нескольких строк.

Например, у нас есть следующие предложения

Hello how are you?
Hi how are you?
hi how are you doing?
Hey how is your day?

Я хочу получить процент, основанный на том, насколько похожи предложения для каждогопрочее

Допустим, у нас есть эти три предложения

Hello how are you?
Hello how are you?
Hello how are you?

Тогда мы должны получить 100% похожих

, но если у нас есть

Hello how are you?
Hello how are you?
hola como estats?

, тогдамы должны получить число примерно до 67% сходства.

Ответы [ 3 ]

0 голосов
/ 16 декабря 2018

Вы можете использовать pandas для работы с фреймом данных, itertools.combinations для вычисления комбинаций из 2 строк из вашего списка и difflib.SequenceMatcher для вычисления подобия:

import pandas as pd
import itertools
from difflib import SequenceMatcher

def similarity(a,b):
    seq = SequenceMatcher(a=a, b=b)
    return seq.ratio()    

strings = ['Hello how are you?', 'Hi how are you?', 'hi how are you doing?', 'Hey how is your day?']
combinations = itertools.combinations(strings,2)

df = pd.DataFrame(list(combinations))
df['similarity'] = df.apply(lambda x: similarity(x[0],x[1]), axis=1)

df.similarity.mean()
0.68
0 голосов
/ 17 декабря 2018

Вы можете использовать numpy для создания матрицы попарного сходства из itertools.product.Затем вы можете извлечь желаемую меру сходства из этой матрицы.В любом случае вам нужно найти метрику (то есть попарно квантификатор), которая подходит для вашей проблемы.

import itertools as it
import numpy as np


def similarity_check(sentences, metric):
    pairwise = np.fromiter(map(
        metric,
        it.product(sentences, sentences)),
    dtype=float).reshape(len(sentences), -1)
    # return pairwise[np.triu_indices(len(sentences), 1)].mean()  # Option 1.
    return pairwise.mean(axis=0).max()  # Option 2.


print(similarity_check([
    'Hello how are you?',
    'Hello how are you?',
    'Hello how are you?'
], lambda x: float(x[0] == x[1])))  # Plug in your own metric here.

print(similarity_check([
    'Hello how are you?',
    'Hello how are you?',
    'hola como estats?'
], lambda x: float(x[0] == x[1])))  # Plug in your own metric here.
0 голосов
/ 16 декабря 2018

Наивно, вы можете сделать что-то вроде этого:

from collections import Counter 
from itertools import zip_longest

cases=[('Hello how are you?','Hello how are you?','Hello how are you?'),
       ('Hello how are you?','Hello how are you?','hola como estats?')]

for t in cases:    
    sums=[]
    for st in zip_longest(*t,fillvalue='|'):
        sums.append((st,(len(Counter(st))-1)/len(st)))
    print(t)
    print('\n'.join(map(str, sums)))   

Отпечатки:

('Hello how are you?', 'Hello how are you?', 'Hello how are you?')
(('H', 'H', 'H'), 0.0)
(('e', 'e', 'e'), 0.0)
(('l', 'l', 'l'), 0.0)
(('l', 'l', 'l'), 0.0)
(('o', 'o', 'o'), 0.0)
((' ', ' ', ' '), 0.0)
(('h', 'h', 'h'), 0.0)
(('o', 'o', 'o'), 0.0)
(('w', 'w', 'w'), 0.0)
((' ', ' ', ' '), 0.0)
(('a', 'a', 'a'), 0.0)
(('r', 'r', 'r'), 0.0)
(('e', 'e', 'e'), 0.0)
((' ', ' ', ' '), 0.0)
(('y', 'y', 'y'), 0.0)
(('o', 'o', 'o'), 0.0)
(('u', 'u', 'u'), 0.0)
(('?', '?', '?'), 0.0)
('Hello how are you?', 'Hello how are you?', 'hola como estats?')
(('H', 'H', 'h'), 0.3333333333333333)
(('e', 'e', 'o'), 0.3333333333333333)
(('l', 'l', 'l'), 0.0)
(('l', 'l', 'a'), 0.3333333333333333)
(('o', 'o', ' '), 0.3333333333333333)
((' ', ' ', 'c'), 0.3333333333333333)
(('h', 'h', 'o'), 0.3333333333333333)
(('o', 'o', 'm'), 0.3333333333333333)
(('w', 'w', 'o'), 0.3333333333333333)
((' ', ' ', ' '), 0.0)
(('a', 'a', 'e'), 0.3333333333333333)
(('r', 'r', 's'), 0.3333333333333333)
(('e', 'e', 't'), 0.3333333333333333)
((' ', ' ', 'a'), 0.3333333333333333)
(('y', 'y', 't'), 0.3333333333333333)
(('o', 'o', 's'), 0.3333333333333333)
(('u', 'u', '?'), 0.3333333333333333)
(('?', '?', '|'), 0.3333333333333333)

Таким образом, разница во втором случае будет чуть меньше 1/3, посколькудва символа, которые совпадают в последнем испанском предложении.

Затем уменьшите эту последовательность до общей разницы.

...