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