所以我正在使用罗盘角度(以度为单位)进行应用。我已经设法通过使用以下(在http://en.wikipedia.org/wiki/Directional_statistics#The_fundamental_difference_between_linear_and_circular_statistics找到)来确定角度平均值的计算:
double calcMean(ArrayList<Double> angles){
double sin = 0;
double cos = 0;
for(int i = 0; i < angles.size(); i++){
sin += Math.sin(angles.get(i) * (Math.PI/180.0));
cos += Math.cos(angles.get(i) * (Math.PI/180.0));
}
sin /= angles.size();
cos /= angles.size();
double result =Math.atan2(sin,cos)*(180/Math.PI);
if(cos > 0 && sin < 0) result += 360;
else if(cos < 0) result += 180;
return result;
}
所以我正确地得到了我的平均值/平均值,但是我无法获得正确的方差/ stddev值。我很确定我正在计算我的方差不正确,但想不出正确的方法。
以下是我计算方差的方法:
double calcVariance(ArrayList<Double> angles){
//THIS IS WHERE I DON'T KNOW WHAT TO PUT
ArrayList<Double> normalizedList = new ArrayList<Double>();
for(int i = 0; i < angles.size(); i++){
double sin = Math.sin(angles.get(i) * (Math.PI/180));
double cos = Math.cos(angles.get(i) * (Math.PI/180));
normalizedList.add(Math.atan2(sin,cos)*(180/Math.PI));
}
double mean = calcMean(angles);
ArrayList<Double> squaredDifference = new ArrayList<Double>();
for(int i = 0; i < normalizedList.size(); i++){
squaredDifference.add(Math.pow(normalizedList.get(i) - mean,2));
}
double result = 0;
for(int i = 0; i < squaredDifference.size(); i++){
result+=squaredDifference.get(i);
}
return result/squaredDifference.size();
}
虽然这是计算方差的正确方法,但我不是我应该使用的。我认为我应该使用arctangent,但标准偏差/方差值似乎是关闭的。帮助
修改 示例:输入值0,350,1,0,0,0,1,358,9,1结果,平均角度为0.0014(因为角度非常接近于零),但如果您只是进行非角度平均,则会得到72 ......这是离开的。由于我不知道如何操纵个别值应该是什么,计算的方差是25074,导致标准偏差为158度,这是疯了! (它应该只有几度)我认为我需要做的是正确地将各个值标准化,这样我就能得到正确的方差/ stddev值。
答案 0 :(得分:12)
如果您将单位圆圈上的样本视为复数,则通过维基百科页面链接到圆形标准差为sqrt(-log R²)
,其中R = |样本|的平均值。因此,标准偏差的计算与平均角度的计算非常相似:
double calcStddev(ArrayList<Double> angles){
double sin = 0;
double cos = 0;
for(int i = 0; i < angles.size(); i++){
sin += Math.sin(angles.get(i) * (Math.PI/180.0));
cos += Math.cos(angles.get(i) * (Math.PI/180.0));
}
sin /= angles.size();
cos /= angles.size();
double stddev = Math.sqrt(-Math.log(sin*sin+cos*cos));
return stddev;
}
如果你想一下它就会有意义:当你在单位圆上平均一堆彼此接近的点时,结果离圆圈不太远,所以R将接近1并且stddev接近0.如果点沿圆圈均匀分布,则它们的平均值将接近0,因此R将接近0并且stddev非常大。
答案 1 :(得分:1)
使用 Math.atan(sin / cosine)时,会得到-90到90度之间的角度。如果你有120度角,你会得到 cos = - 0.5和 sin = 0.866,然后你得到 atan(-1.7) = - 60度。因此,您将错误的角度放在规范化列表中。
假设variance是线性偏差,我建议您通过 -calcMean(角度)旋转角度数组并添加/减去360度/高于/低于180 / -180的角度(该死的我的写作!))同时找到最大和最小角度。它会给你想要的偏差。像这样:
Double meanAngle = calcMean(angles)
Double positiveDeviation = new Double(0);
Double negativeDeviation = new Double(0);
Iterator<Double> it = angles.iterator();
while (it.hasNext())
{
Double deviation = it.next() - meanAngle;
if (deviation > 180) deviation -= 180;
if (deviation <= -180) deviation += 180;
if (deviation > positiveDeviation) positiveDeviation = deviation;
if (deviation > negativeDeviation) negativeDeviation = deviation;
}
return positiveDeviation - negativeDeviation;
对于平均偏差,你应该使用你的方法(角度,而不是“标准化”的),并继续寻找(-180,180)范围!
答案 2 :(得分:0)
数学库函数余数对于处理角度非常方便。
一个简单的改变就是替换
normalizedList.get(i) - mean
与
remainder( normalizedList.get(i) - mean, 360.0)
然而,你的第一个循环是多余的,因为对余数的调用将处理所有的规范化。而且,只是总结平方差异而不是存储它们更简单。我个人喜欢在算术运算时避免使用pow()。所以你的功能可能是:
double calcVariance(ArrayList<Double> angles){
double mean = calcMean(angles);
double result = 0;
for(int i = 0; i < angles.size(); i++){
double diff = remainder( angles.get(i) - mean, 360.0);
result += diff*diff;
}
return result/angles.size();
}
答案 3 :(得分:0)
目前处理这个问题的好方法是现在已经在 scipy 中实现的两个功能:
包括一些很棒的东西:
答案 4 :(得分:-1)
The accepted answer by Joni在回答这个问题方面表现非常出色,但是Brian Hawkins noted:
介意单位。写入的函数以度为单位的角度作为输入,并以弧度为单位返回标准偏差。
这是一个通过对其参数及其返回值使用度数来修复该问题的版本。它还具有更大的灵活性,因为它允许variable number of arguments。
public static double calcStdDevDegrees(double... angles) {
double sin = 0;
double cos = 0;
for (int i = 0; i < angles.length; i++) {
sin += Math.sin(angles[i] * (Math.PI/180.0));
cos += Math.cos(angles[i] * (Math.PI/180.0));
}
sin /= angles.length;
cos /= angles.length;
double stddev = Math.sqrt(-Math.log(sin*sin+cos*cos));
return Math.toDegrees(stddev);
}