3

我有一个取自这个示例的非常简单的代码,其中我使用 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

4 回答 4

8

我有一个类似的问题,这就是这里发生的事情。我希望其他遇到此问题的人会通过回复找到帮助。

如果您注意到,在线演示允许您通过指定以下格式的单词来选择词义:word#pos_tag#word_sense。例如,具有第一个词义的名词gender将是gender#n#1

您的代码片段默认使用第一个词义。当我计算“性别”和“性别”之间的 WuPalmer 相似度时,它将返回 0.26。如果我使用在线演示,它将返回 1.0。但如果我们使用“gender#n#1”和“sex#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 中包含的搬运工词干分析器来确保您事先词干词干。

希望这可以帮助!

于 2013-10-24T10:52:32.730 回答
1

我在 ws4j 的 googlecode 网站上提出了这个问题,结果证明这确实是一个错误。我收到的回复如下:

这看起来是由于试图覆盖受保护的静态字段(这不能在 Java 中完成)。附加的补丁通过将最小和最大字段的定义移动到相关性计算器中的非静态最终成员并添加 getter 来解决此问题。然后实现通过超级构造函数调用提供它们的最小值/最大值。

可以使用补丁 -p1 < 0001-Cannot-override-static-members-replacing-fields-with.patch 应用补丁

是他们网站上的(现已解决的)问题

于 2014-08-12T00:21:20.553 回答
-1

这就是为什么 -

在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(=> 相似度将变为未定义)。

在 2 种情况下距离可以为 0...

(1) ic(c1) = ic(c2) = ic(lcs(c1, c2)) = 0

如果 lcs 是根节点(根节点的信息内容为零),则 ic(lcs(c1, c2)) 可以为 0。但是由于 c1 和 c2 永远不可能是根节点,因此 ic(c1) 和 ic(c2) 只有当 2 个概念的频率计数为 0 时才会为 0,在这种情况下,由于缺乏数据,我们返回相关性 0 (类似于 lin 案例)。

请注意,根节点的信息内容实际上为零。从技术上讲,没有其他概念的信息内容值可以为零。我们为概念分配零值,而实际上它们的信息内容是未定义的(由于零频率计数)。要了解为什么要查看信息内容的公式: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 就像说它们根本不相关。

于 2014-07-19T20:55:05.017 回答
-1

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
于 2018-08-18T13:39:08.460 回答