我正在尝试计算一组数据的平均差异平均值。我有两个(假设是等价的)公式计算这个,其中一个比另一个(O ^ n2)更有效(O ^ n)。
问题在于,虽然低效的公式提供了正确的输出,但有效的公式却没有。只要看看这两个公式,我就预感到它们并不等同,但是把它写下来是因为推导是由科学杂志中的一个静态的。所以我假设问题是我的翻译。任何人都可以帮我正确翻译有效的功能吗?
效率低下的公式:
低效的公式转换(Java):
public static double calculateMeanDifference(ArrayList<Integer> valuesArrayList)
{
int valuesArrayListSize = valuesArrayList.size();
int sum = 0;
for(int i = 0; i < valuesArrayListSize; i++)
{
for(int j = 0; j < valuesArrayListSize; j++)
sum += (i != j ? Math.abs(valuesArrayList.get(i) - valuesArrayList.get(j)) : 0);
}
return new Double( (sum * 1.0)/ (valuesArrayListSize * (valuesArrayListSize - 1)));
}
高效的派生公式:
其中(抱歉,不知道如何在这里使用MathML):
x(下标i)=数据集的第i order statistic
x(bar)=数据集的平均值
高效的派生公式翻译(Java):
public static double calculateMean(ArrayList<Integer> valuesArrayList)
{
double sum = 0;
int valuesArrayListSize = valuesArrayList.size();
for(int i = 0; i < valuesArrayListSize; i++)
sum += valuesArrayList.get(i);
return sum / (valuesArrayListSize * 1.0);
}
public static double calculateMeanDifference(ArrayList<Integer> valuesArrayList)
{
double sum = 0;
double mean = calculateMean(valuesArrayList);
int size = valuesArrayList.size();
double rightHandTerm = mean * size * (size + 1);
double denominator = (size * (size - 1)) / 2.0;
Collections.sort(valuesArrayList);
for(int i = 0; i < size; i++)
sum += (i * valuesArrayList.get(i) - rightHandTerm);
double meanDifference = (2 * sum) / denominator;
return meanDifference;
}
我的数据集由一组整数组成,每个整数都有一个由集合[0,5]限定的值。
随机生成这样的集合并在它们上使用这两个函数会得到不同的结果。低效的似乎是产生与测量结果一致的结果:集合中任何两个值之间的绝对平均差异。
有人能告诉我翻译有什么问题吗?
编辑:我创建了一个更简单的实现O(N),只要你的所有数据的值都限制在一个相对较小的集合中。公式坚持第一种方法的方法,因此,给出相同的结果(与派生的公式不同)。如果它适合你的用例,我建议人们使用它来代替派生的有效公式,特别是因为当N很小时后者似乎给出负值。)
高效的非衍生翻译(Java):
public static double calculateMeanDifference3(ArrayList<Integer> valuesArrayList)
{
HashMap<Integer, Double> valueCountsHashMap = new HashMap<Integer, Double>();
double size = valuesArrayList.size();
for(int i = 0; i < size; i++)
{
int currentValue = valuesArrayList.get(i);
if(!valueCountsHashMap.containsKey(currentValue))
valueCountsHashMap.put(currentValue, new Double(1));
else
valueCountsHashMap.put(currentValue, valueCountsHashMap.get(currentValue)+ 1);
}
double sum = 0;
for(Map.Entry<Integer, Double> valueCountKeyValuePair : valueCountsHashMap.entrySet())
{
int currentValue = valueCountKeyValuePair.getKey();
Double currentCount = valueCountKeyValuePair.getValue();
for(Map.Entry<Integer, Double> valueCountKeyValuePair1 : valueCountsHashMap.entrySet())
{
int loopValue = valueCountKeyValuePair1.getKey();
Double loopCount = valueCountKeyValuePair1.getValue();
sum += (currentValue != loopValue ? Math.abs(currentValue - loopValue) * loopCount * currentCount : 0);
}
}
return new Double( sum/ (size * (size - 1)));
}
答案 0 :(得分:3)
您对sum += (i * valuesArrayList.get(i) - rightHandTerm);
的解释是错误的,应该是sum += i * valuesArrayList.get(i);
,然后是for
,double meanDifference = ((2 * sum) - rightHandTerm) / denominator;
两个方程都产生大约相同的值,但它们不相等。不过,这应该对你有所帮助。
答案 1 :(得分:1)
你在每次迭代时减去rightHandTerm
,所以它得到[over]乘以N.
提名者中的大西格玛只接触(i x_i),而不是右手术语。
还有一点说明:mean * size == sum
。你不必将N除以N,然后再将它重新乘以。