在简单的线性数据集中查找并修复错误的值

时间:2011-05-25 14:43:19

标签: algorithm error-correction

这可能是一个简单的问题,但我找不到一个好方法。

我有一些有限数量的有序int值,它们之间应该有相似的距离,例如:32, 42, 52, 62, 72, 82

实际上,有些价值观是错误的。我们可能最终得到32, 51, 62, 66, 71, 83

如何找到明显错误的值(在这种情况下:66)并将其移动到正确的位置(42)?

  • 可以假设大多数数据仍然有效,因此仍然可以计算出点之间正确距离的良好猜测(此处:10)。
  • 已知并且正确的点数(即,我们只需要移动但不能添加或删除点数。)
  • 左侧和右侧的数据边界未知,边缘情况下的行为可以自由定义。

在写下我想到的问题时。一个想法可能是提取函数f(x) = a + x * b(这很容易)并迭代已知数量的点。删除与迭代点距离最大的数据,并将其插入到与原点距离最大的迭代位置。

4 个答案:

答案 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}

  1. 在点之间找到距离d。我在考虑:

    • 对元素之间的差异进行排序并取中位数 排序差异= {4,5,11,12,19} - &gt;中位数= 11
    • 或计算差异的平均值 平均值= 10.2 - &gt;圆形平均值= 10
  2. 建立m元素的平均值R 在我们的例子中(32 + 51 + 62 + 66 + 71 + 83)/ 6 = 30.2
    圆形= 30

  3. 构建比较序列S,其中第一个元素S_0具有值 m - (n / 2) * d(其中n是元素数量),任何其他元素S_i的值为S_1 + i * d
    在我们的示例中S = {30,40,50,60,70,80}

  4. 因为输入序列中的元素可能已移动到另一个位置, 构建R

  5. 的每个排列
  6. 找出异常值最小的排列(异常值是元素,元素差异大于0.3 * d

  7.                      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的正确位置。