如何计算 Double[] 列表中每个 double 的总体标准差?

How to calculate population standard deviation foreach double in a list of Double[]?

我有一个双数组列表:List<Double[]> ys

它们都包含来自 xy 图的 y 值。我想计算 x 的所有点的总体标准偏差,这实际上是针对每个数组中的每个元素。示例:

取每个数组的第一个元素,计算总体标准差,将值放入新数组。移动到列表中所有数组中的下一个元素并计算总体标准偏差并放入新创建的数组中。等等,直到我们到达所有数组的末尾。

我是否可以使用 linq 或类似工具在不使用嵌套 for 循环的情况下快速实现这一目标?

示例输入 ys = {[1, 2, 3, 4, 5], [10, 20, 30, 40, 50], [100, 200, 300, 400, 500]}

输出:double[] = [44.69899328, 89.39798655, 134.0969798, 178.7959731, 223.4949664]

44.69899328 来自:1, 10, 100

89.39798655 来自:2, 20, 200

134.0969798 来自:3, 30, 300

178.7959731 来自:4, 40, 400

223.4949664 来自:5, 50, 500

尝试以下操作:

        static void Main(string[] args)
        {
            List<Double[]> ys = new List<double[]>() { new double[] { 1, 2, 3, 4, 5 }, new double[] { 10, 20, 30, 40, 50 }, new double[] { 100, 200, 300, 400, 500 } };

            double[] results = ys.SelectMany(x => x.Select((y,i) => new {y = y, i = i})).GroupBy(x => x.i).Select(x => StandardDeviation(x.Select(y => y.y).ToArray())).ToArray(); 

            
        }
         static double StandardDeviation(double[] input)
         {
             double average = input.Average();
             double sumOfSquares = input.Select(x => (average - x) * (average - x)).Sum();

             return Math.Sqrt(sumOfSquares / input.Length);
         }

我会首先定义一个扩展方法,它可以旋转你的数据

public static class Extensions
{
    public static IEnumerable<T[]> Pivot<T>(this List<T[]> items)
    {
        return items.SelectMany( arr => arr.Select( (x,i) => new{Value=x,Index = i}) )
                    .GroupBy(x => x.Index)
                    .Select(g => g.Select(x => x.Value).ToArray());
    }
}

然后代码以及 StDev 的简单实现变得如此简单:

var res = ys.Pivot().Select(StDev);

StDev函数:

public static double StDev(double[] input)
{
    double avg = input.Average();
    double sum = input.Select(x => (avg - x) * (avg - x)).Sum();

    return Math.Sqrt(sum / input.Length);
}

实例:https://dotnetfiddle.net/g3HqRF

对于所有子数组长度相同的数据,这可能是:

var stdDevs = Enumerable.Range(0, ys[0].Length)
    .Select(i => ys.Select(y => y[i]))
    .Select(StdDev); 

如果您需要输入值,最后一部分可以是 .Select(Z => new { Z, V = StdDev(Z) });

测试:

var ys = new[] { new[] { 1, 2, 3, 4, 5 }, new[] { 10, 20, 30, 40, 50 }, new[] { 100, 200, 300, 400, 500 } };

var stdDevs = Enumerable.Range(0, ys[0].Length)
    .Select(i => ys.Select(y => y[i]))
    .Select(Z => new { Z, V = StdDev(Z) });

foreach(var d in stdDevs)
{
    Console.WriteLine($"Std dev for {string.Join(",", d.Z)} is {d.V}");
}

static double StdDev(IEnumerable<int> values)
{
    // From 
    // by Jonathan DeMarks   
    double avg = values.Average();
    return Math.Sqrt(values.Average(v=>Math.Pow(v-avg,2)));
}

输出:

Std dev for 1,10,100 is 44.69899327725402
Std dev for 2,20,200 is 89.39798655450804
Std dev for 3,30,300 is 134.09697983176207
Std dev for 4,40,400 is 178.79597310901607
Std dev for 5,50,500 is 223.4949663862701

不同长度

如果子数组的长度不同,则版本不那么漂亮但仍然可读

var stdDevs = Enumerable.Range(0, ys.Max( y => y.Length))
    .Select(i => ys.Where( y => i < y.Length).Select(y => y[i]))
    .Select(Z => new { Z, V = StdDev(Z) }); 

如果这是删除了 5 和 500 的 运行,则结果为:

Std dev for 1,10,100 is 44.69899327725402
Std dev for 2,20,200 is 89.39798655450804
Std dev for 3,30,300 is 134.09697983176207
Std dev for 4,40,400 is 178.79597310901607
Std dev for 50 is 0