这可能是一个简单的问题,但我找不到一个好方法。
我有一些有限数量的有序int值,它们之间应该有相似的距离,例如:32, 42, 52, 62, 72, 82
。
实际上,有些价值观是错误的。我们可能最终得到32, 51, 62, 66, 71, 83
。
如何找到明显错误的值(在这种情况下:66)并将其移动到正确的位置(42)?
在写下我想到的问题时。一个想法可能是提取函数f(x) = a + x * b
(这很容易)并迭代已知数量的点。删除与迭代点距离最大的数据,并将其插入到与原点距离最大的迭代位置。
答案 0 :(得分:1)
你可以使用robust regression,这只不过是一个花哨的术语,用于“以一种方式将一条直线拟合到一堆点,使得不适合的点被优雅地移除”。
如果您不想编写非线性优化代码,可以使用iteratively reweighted least squares来利用您所处的任何现有加权线性回归代码。
这个想法是你weighted least squares做直线符合你的观点。然后,您可以为每个点指定一个权重,用于衡量您是否认为它是outlier,过多地偏离回归线(例如,通过Huber loss function)。然后,您使用权重重做回归。您将获得一个新行,因此可以计算一组新的权重。重复直到收敛(或最大迭代次数)。你将留下权重,告诉你哪些点是坏的,以及一条很好地适合其余点的线,可用于替换异常值。
我认为实施的时间并不比上面的文字说明长得多。
答案 1 :(得分:0)
如果只有一个数据错误,并且假设值增加(如示例所示): 数据在DATA和DATA_SIZE中,THRESHOLD是允许的偏差
#include <stdio.h>
#define THRESHOLD 3
#define DATA 32, 51, 62, 66, 71, 83
#define DATA_SIZE 6
void main()
{
int data[]={DATA}; int size = DATA_SIZE;
int skip = 0, diffs, curDif, maxDif, lastItem, item, dif, maxPos;
int maxDiffs = 10000, location, newPosition, newValue;
for(skip = 0; skip < size; skip++)
{
diffs = 0;
curDif = 0;
maxDif = 0;
maxPos = -1;
lastItem = (skip == 0);
for(item = lastItem+1; item < size; item++)
{
if(item == skip)continue;
dif = data[item]-data[lastItem];
if(abs(dif - curDif) > THRESHOLD)
{
curDif = dif;
diffs++;
if(curDif > maxDif)
{
maxDif = curDif;
maxPos = item;
}
}
lastItem = item;
}
if(diffs < maxDiffs)
{
maxDiffs = diffs;
location = skip;
newPosition = maxPos;
newValue = data[maxPos-1]+(maxDif>>1);
}
}
printf("Found... \nindex %d\nValue: %d\nGoes in:%d\nNew value:%d\n", location, data[location], newPosition, newValue);
}
答案 2 :(得分:0)
我尝试了很多不同的方法,这就是我最终的结果。基本思想是为期望值数组分配良好有效的值。无法分配的值将通过使用缺少的预期值来修复。
给出的是实际数据列表peaks
。
构建预期数据列表
var expected = Enumerable
// 19 is the known number of values
.Range (0, 19)
// simply interpolate over the actual data
.Select (x => peaks.First () + x * (peaks.Last () - peaks.First ()) / 18)
.ToList ();
建立所有点距离的矩阵
var distances = expected.SelectMany (dst => peaks.Select (src => new {
Expected = dst,
Original = src,
Distance = Math.Abs (dst - src)
}));
重复
for (;;)
{
选择最佳距离
var best = distances
// ignore really bad values
.Where (x => x.Distance < dAvgAll * 0.3)
.OrderBy (x => x.Distance).FirstOrDefault ();
如果未找到好的分配,请退出
if (best == null) {
break;
}
否则,存储比赛
expected.Remove (best.Expected);
peaks.Remove (best.Original);
}
我们的来源中的所有有效条目都已被识别并删除。我们只是使用预期集中的剩余值,并忽略剩余的原始值来完成我们的最终数据集。
其他尝试过的方法,包括改编自gusbro's的版本,效果不佳,经常表现出不良行为。
答案 3 :(得分:0)
我将尝试概述一个算法(我不知道它是否会为每个输入序列提供正确的结果,因此将其视为一个想法):
算法的输入是有序序列R
。例如{32,51,62,66,71,83}
在点之间找到距离d
。我在考虑:
建立m
元素的平均值R
在我们的例子中(32 + 51 + 62 + 66 + 71 + 83)/ 6 = 30.2
圆形= 30
构建比较序列S
,其中第一个元素S_0
具有值
m - (n / 2) * d
(其中n
是元素数量),任何其他元素S_i
的值为S_1 + i * d
。
在我们的示例中S
= {30,40,50,60,70,80}
因为输入序列中的元素可能已移动到另一个位置,
构建R
找出异常值最小的排列(异常值是元素,元素差异大于0.3 * d
S = { 30, 40, 50, 60, 70, 80 }
permutation x of R = { 32, 51, 62, 66, 71, 83 } three outliers
permutation y of R = { 32, 66, 51, 62, 71, 83 } one outlier
permutation z of R = ...
此示例中的算法结果将是排列y,并且随之找到元素66的正确位置。