查找一系列数字中的异常情况

时间:2016-10-20 06:56:44

标签: c#

我有数字列表

1

假设列表中的项目正常分发;在这个系列中,我想过滤掉异常(可以是3和{{1}},因为它们似乎是最偏离的值)。我必须使用动态系列,它们的值可能会发生变化,因此无法对条件检查中的任何值进行硬编码。

2 个答案:

答案 0 :(得分:0)

对您的请求的一般回答:您需要定义异常是什么。这是你的谓词。然后根据谓词过滤列表。

var nums = new List<double> {1,2,2.4,2.6,1.5,3,1.9};
Predicate<double> anomalyPredicate = IsNoAnomaly; // Definition of a predicate
List<double> listWithoutAnomalies= nums.FindAll(anomalyPredicate); // Find every item that is not an anomaly

让我们假设异常是数字是3或更大。然后你有:

private static bool IsNoAnomaly(double d)
{
    return d < 3;
}

但当然,IsNoAnomaly可能是任何bool返回功能。

编辑:另一个例子:如果在运行时确定的阈值_currentThreshold可能未达到或超过,则该函数将为:

private static bool IsNoAnomaly(double d)
{
    return d < _currentThreshold;
}

答案 1 :(得分:0)

如果假设nums项的分布为 normal ,我们可以将值视为异常,如果它超出[mean - k * sigma..mean + k * sigma]范围(sigma站立对于标准偏差),其中k通常为2(95%),3(99.76%),有时甚至为5。 如果是你的情况,你可以实施

public static IEnumerable<T> Anomaly<T>(IEnumerable<T> source, 
                                        Func<T, double> map, 
                                        double maxSigma = 3.0) {
  if (null == source)
    throw new ArgumentNullException("source");
  else if (null == map)
    throw new ArgumentNullException("map");

  T[] data = source.ToArray();

  if (data.Length <= 1)
    yield break;

  double s = 0.0;
  double s2 = 0.0;

  foreach (var item in data) {
    double x = map(item);

    s += x;
    s2 += x * x;
  }

  double mean = s / data.Length;
  double sigma = Math.Sqrt(s2 / data.Length - (s / data.Length) * (s / data.Length));
  double leftMargin = mean - maxSigma * sigma;
  double rightMargin = mean + maxSigma * sigma;

  foreach (var item in data) {
    double x = map(item);

    if (x < leftMargin || x > rightMargin)
      yield return item;
  }
}

因此您可以找到不同k的异常:

var nums = new List<double> { 1, 2, 2.4, 2.6, 1.5, 3, 1.9 };

// k = 3 (typical criterium of 3 sigma deviation - 99.76%) -  empty output
Console.Write(string.Join(", ", Anomaly(nums, x => x, 3)));

// k = 1 (unusual criterium of just 1 sigma deviation - 67%) the output is "1, 3"
Console.Write(string.Join(", ", Anomaly(nums, x => x, 1)));