Система Левенштейна возвращает неожидаемый результат
Есть такие данные:
const levenshtein = require('fast-levenshtein');
let arr = [
'баги',
'bots',
'чат',
'ботыад',
'информация'
]
Использую такой код:
let str = 'бот'
arr.sort((a, b) => levenshtein.get(str , a) - levenshtein.get(str, b))[0]
Возвращает:
'чат'
А должно быть:
'ботыад'
Что я делаю не так?
Ответы (1 шт):
Автор решения: nörbörnën
→ Ссылка
Этот вопрос является продолжением вопроса Как найти самый похожий String в Array по этому и ответ на него является продолжением ответа.
В прошлом ответе я показал как применить Расстояние Левенштейна (не подошло автору) и Сходство Джаро — Винклера.
В этом ответе покажу как использовать
- cтемминг, чтобы упростить поиск совпадений (стеммер - это такая штука, которая превратит ("боту", "бота", "ботом") в "бот". ну, если это слово есть в его словаре или если угадает правила по которым искать "основу" слова)
- Коэффициент Сёренсена
Плюс, по сравнению с предыдущим ответом, поиск максимального совпадения теперь в один проход, без сортировки.
const natural = require('natural');
natural.PorterStemmerRu.attach();
const userMessage = 'пешу в ппаддержку11! бот-заебот! надоели баги вашего ббота!';
const arr = userMessage.tokenizeAndStem(); // ["пеш","паддержку11","бот","заебот","надоел","баг","ваш","ббот"]
['поддержка', 'бот', 'ытот'].forEach((str) => {
console.log('[d]', str, '->', compareDiceCoefficient(str, arr, 0.5));
console.log('[j]', str, '->', compareJaroWinkler(str, arr, 0.7));
});
function compareDiceCoefficient(str, arr, lowerLimit = 0.05) {
// arr.forEach((x) => console.log('[d]', x, natural.DiceCoefficient(str, x)));
const reduced = arr.reduce((acc, x) => {
const dt = natural.DiceCoefficient(str, x);
if (acc.dt < dt && dt > lowerLimit) {
acc.dt = dt;
acc.w = x;
}
return acc;
}, {dt: -Infinity, w: null});
return reduced.w;
}
function compareJaroWinkler(str, arr, lowerLimit = 0.05) {
// arr.forEach((x) => console.log('[j]', x, natural.JaroWinklerDistance(str, x, undefined, true)));
const reduced = arr.reduce((acc, x) => {
const dt = natural.JaroWinklerDistance(str, x, undefined, true);
if (acc.dt < dt && dt > lowerLimit) {
acc.dt = dt;
acc.w = x;
}
return acc;
}, {dt: -Infinity, w: null});
return reduced.w;
}
[d] поддержка -> ппаддержку11
[j] поддержка -> ппаддержку11
[d] бот -> бот
[j] бот -> бот
[d] ытот -> null
[j] ытот -> null