ws4j возвращает бесконечность для мер сходства, которые должны возвращать 1
У меня есть очень простой код, взятый из этого примера, где я использую меры сходства Lin, Path и Wu-Palmer, чтобы вычислить сходство между двумя словами. Мой код выглядит следующим образом:
import edu.cmu.lti.lexical_db.ILexicalDatabase;
import edu.cmu.lti.lexical_db.NictWordNet;
import edu.cmu.lti.ws4j.RelatednessCalculator;
import edu.cmu.lti.ws4j.impl.Lin;
import edu.cmu.lti.ws4j.impl.Path;
import edu.cmu.lti.ws4j.impl.WuPalmer;
public class Test {
private static ILexicalDatabase db = new NictWordNet();
private static RelatednessCalculator lin = new Lin(db);
private static RelatednessCalculator wup = new WuPalmer(db);
private static RelatednessCalculator path = new Path(db);
public static void main(String[] args) {
String w1 = "walk";
String w2 = "trot";
System.out.println(lin.calcRelatednessOfWords(w1, w2));
System.out.println(wup.calcRelatednessOfWords(w1, w2));
System.out.println(path.calcRelatednessOfWords(w1, w2));
}
}
И оценки ожидаемые, за исключением того, что оба слова идентичны. Если оба слова совпадают (например, w1 = "walk"; w2 = "walk";
), три меры, которые у меня есть, должны возвращать 1,0. Но вместо этого они возвращаются 1.7976931348623157E308.
Я использовал ws4j раньше (на самом деле, ту же версию), но я никогда не видел такого поведения. Поиск в Интернете не дал никаких подсказок. Что здесь может пойти не так?
PS Тот факт, что меры Lin, Wu-Palmer и Path должны возвращаться 1, также может быть подтвержден онлайн-демонстрацией, предоставленной ws4j.
4 ответа
Я поднял эту проблему на сайте googlecode для ws4j, и оказалось, что это действительно была ошибка. Ответ, который я получил, выглядит следующим образом:
Похоже, что это происходит из-за попытки переопределить защищенное статическое поле (это не может быть сделано в Java). Прикрепленный патч устраняет проблему, перемещая определение полей min и max в нестатические конечные элементы в RelatednessCalculator и добавляя геттеры. Реализации затем предоставляют свои минимальные / максимальные значения через вызовы супер-конструктора.
Патч можно применить с патчем -p1 < 0001-Cannot-override-static-members-replacecing-fields-with.patch
И вот (теперь решена) проблема на их сайте.
У меня была похожая проблема, и вот что здесь происходит. Я надеюсь, что другие люди, которые столкнутся с этой проблемой, найдут ответной реакцией полезной.
Если вы заметили, онлайн-демонстрация позволяет вам выбрать смысл слова, указав слово в следующем формате: word # pos_tag # word_sense. Например, род существительного с первым значением слова будет равен пол # n # 1.
Ваш фрагмент кода по умолчанию использует первый смысл слова. Когда я вычисляю сходство WuPalmer между "полом" и "полом", оно возвращает 0.26. Если я использую онлайн демо, он вернется 1.0. Но если мы будем использовать "пол #n#1" и "секс #n#1", то онлайн-демонстрация вернет 0.26, поэтому расхождений нет. Демо-версия онлайн рассчитывает максимальное значение всех пар pos-тегов / словосочетаний. Вот соответствующий фрагмент кода, который должен добиться цели:
ILexicalDatabase db = new NictWordNet();
WS4JConfiguration.getInstance().setMFS(true);
RelatednessCalculator rc = new Lin(db);
String word1 = "gender";
String word2 = "sex";
List<POS[]> posPairs = rc.getPOSPairs();
double maxScore = -1D;
for(POS[] posPair: posPairs) {
List<Concept> synsets1 = (List<Concept>)db.getAllConcepts(word1, posPair[0].toString());
List<Concept> synsets2 = (List<Concept>)db.getAllConcepts(word2, posPair[1].toString());
for(Concept synset1: synsets1) {
for (Concept synset2: synsets2) {
Relatedness relatedness = rc.calcRelatednessOfSynset(synset1, synset2);
double score = relatedness.getScore();
if (score > maxScore) {
maxScore = score;
}
}
}
}
if (maxScore == -1D) {
maxScore = 0.0;
}
System.out.println("sim('" + word1 + "', '" + word2 + "') = " + maxScore);
Кроме того, это даст вам 0,0 сходства в неосновных формах слов, например, "пол" и "пол". Вы можете использовать портер-стеммер, включенный в ws4j, чтобы убедиться, что вы заранее запишете слова в случае необходимости.
Надеюсь это поможет!
Вот почему -
В JCN у нас есть...
sim (c1, c2) = 1 / расстояние (c1, c2)
расстояние (c1, c2) = ic (c1) + ic (c2) - (2 * ic (lcs (c1, c2)))
где c1, c2 - два понятия, ic - информационное содержание понятия. lcs (c1, c2) - наименее распространенный подсумер из c1 и c2.
Теперь мы не хотим, чтобы расстояние было равно 0 (=> сходство станет неопределенным).
расстояние может быть 0 в 2 случаях...
(1) ic(c1) = ic(c2) = ic(lcs(c1, c2)) = 0
ic (lcs (c1, c2)) может быть 0, если lcs оказывается корневым узлом (информационное содержимое корневого узла равно нулю). Но поскольку c1 и c2 никогда не могут быть корневым узлом, ic (c1) и ic (c2) будут равны 0 только в том случае, если у двух понятий имеется счетчик частоты 0, и в этом случае при отсутствии данных мы возвращаем связность 0 (аналогично случаю лин).
Обратите внимание, что корневой узел на самом деле имеет информационное содержание ноль. Технически, ни одно из других понятий не может иметь значение информационного содержания, равное нулю. Мы присваиваем понятиям нулевые значения, когда в действительности их информационное содержание не определено (из-за нулевого количества частот). Чтобы понять, зачем искать формулу для информационного содержания: ic(c) = -log(freq(c)/freq(ROOT)) {log(0)? войти (1)?}
(2) Второй случай, когда расстояние оказывается равным нулю, это когда...
ic (c1) + ic (c2) = 2 * ic (lcs (c1, c2))
(который может иметь более вероятный частный случай ic(c1) = ic(c2) = ic(lcs(c1, c2)), если все три окажутся одинаковыми.)
Как с этим справиться?
Интуитивно это случай максимальной связанности (нулевое расстояние). Для jcn это родство было бы бесконечностью... Но мы не можем вернуть бесконечность. И просто возвращение 0 не сработает... так как здесь мы нашли пару концепций с максимальной связанностью, а возвращение 0 было бы равносильно тому, чтобы сказать, что они вообще не связаны.
1.7976931348623157E308 - это значение Double.MAX_VALUE, но максимальное значение некоторого алгоритма сходства / родства (Lin, WuPalmer и Path) находится в диапазоне от 0 до 1. Затем для идентичного синтаксиса максимальное значение может быть возвращено равным 1. В версию моего репо ( https://github.com/DonatoMeoli/WS4J) я исправил эту и другие ошибки.
Теперь для двух одинаковых слов возвращаются следующие значения:
HirstStOnge 16.0
LeacockChodorow 1.7976931348623157E308
Lesk 1.7976931348623157E308
WuPalmer 1.0
Resnik 1.7976931348623157E308
JiangConrath 1.7976931348623157E308
Lin 1.0
Path 1.0
Done in 67 msec.
Process finished with exit code 0