标准差是不是可传递的?

时间:2014-11-12 05:17:20

标签: java comparator

我正在尝试实现Comparator,考虑到要比较的对象(Word)有两个属性定义为int

我希望得到这两个值的标准偏差(可能更多,但现在是2),并对列表中的对象具有最低值进行排序。但显然,它是说我的方法不是基于this question的传递(我认为,因为我有相同的例外)。但我不知道如何,这里只会比较标准偏差的结果。

我是否对数学感到困惑,并没有考虑一个特殊情况,指出这种方法不是传递性的,或者我做错了什么?

对列表进行排序:

for(Map.Entry<String,List<Word>> entry: list.entrySet()){
 Collections.sort(entry.getValue(), Collections.reverseOrder(new SimpleComparator()));
 ...
}

比较类:

import java.util.Comparator;

public class SimpleComparator implements Comparator<Word> {
    @Override
    public int compare(Word word1, Word word2) {
        int b1,b2,f1,f2;
        double average1,average2, result1,result2;
        b1 = word1.getAttr1();
        b2 = word2.getAttr1();
        f1 = word1.getAttr2();
        f2 = word2.getAttr2();
        average1 = (b1-f1)/2;
        average2 = (b2-f2)/2;
        result1 = Math.sqrt((Math.pow(b1-average1,2)+Math.pow(f1-average1,2))/2);
        result2 = Math.sqrt((Math.pow(b2-average2,2)+Math.pow(f2-average2,2))/2);
        return (int)(result1 - result2);
    }
}

2 个答案:

答案 0 :(得分:3)

你应该使用Math.signum(result1 - result2),如果结果为负则产生-1,如果结果为零则产生0,如果结果为正则产生1。确保将结果保持为double - 将double转换为int时发生的截断会产生不准确的结果。

相反,请将您的return语句替换为:

return (int) Math.signum( result1 - result2 );

在这种情况下,0.9 - 0.3的结果为0.6,其结果为1。但是,如果我们将双0.6转换为int,则结果为0,而不是1,表示它们相等。但是,我们知道这不是真的。这样做的原因是,当将数值数据类型转换为较低精度之一时,该值不会舍入 - 它只会丢失精度,这意味着小数点后的值会下降。

请参阅JavaDocs Comparator.comare(T, T)

  

实现者必须确保所有x和y的sgn(compare(x,y))== -sgn(compare(y,x))。

答案 1 :(得分:0)

您的compare(x1,x2)方法违反了条件:

  

实现者必须确保compare(x,y)== 0暗示   所有z的sgn(compare(x,z))== sgn(compare(y,z))。

以下是compare(w1,w2)=0

的方法的反例
public static void main(String[] args) {

 Word w1=new Word(2,5);
 Word w2=new Word(1,5);
 Word w3=new Word(2,4);

    System.out.println(Math.signum(getStandardDeviation(w1, w3))==Math.signum(getStandardDeviation(w2, w3)));
}

public static double getStandardDeviation(Word word1,Word word2)
{
    int b1,b2,f1,f2;
    double average1,average2, result1,result2;
    b1 = word1.getAttr1();
    b2 = word2.getAttr1();
    f1 = word1.getAttr2();
    f2 = word2.getAttr2();
    average1 = (b1-f1)/2;
    average2 = (b2-f2)/2;
    result1 = Math.sqrt((Math.pow(b1-average1,2)+Math.pow(f1-average1,2))/2);
    result2 = Math.sqrt((Math.pow(b2-average2,2)+Math.pow(f2-average2,2))/2);
    return (int)(result1 - result2);
}

}