【问题标题】:How to calculate population standard deviation foreach double in a list of Double[]?如何计算 Double [] 列表中每个 double 的总体标准差?
【发布时间】:2021-07-26 15:49:11
【问题描述】:

我有一个这样的双数组列表: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

【问题讨论】:

  • 您能举个例子吗?例如,{[1, 2, 3], [15, 20, 40]} 的期望输出是什么?
  • 您的示例输出将是 [7, 9, 18.5]
  • @Fildor 7 是样本 1、15 的标准差。9 是 2,15 的标准差。 18.5 是 3,40 的标准差
  • @Fildor 可能是因为您使用的是样本标准差。如果您使用总体标准差,这些就是您得到的数字。将数字插入您选择的标准偏差计算器:) 我正在使用这个:calculator.net/standard-deviation-calculator.html
  • 噢噢噢,你用了德米特里的例子吗??是的,对不起,忘记了。我的错。想念你实际上是 OP 并回答 Dmitry ...哈哈

标签: c# linq standard-deviation


【解决方案1】:

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

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 https://stackoverflow.com/questions/3141692/standard-deviation-of-generic-list
    // 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

【讨论】:

    【解决方案2】:

    尝试以下:

            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);
             }
    

    【讨论】:

    • 我相信你已经取了每个数组的标准差。不完全是我需要的。因为我需要每个数组中每个元素的标准偏差。请在原始帖子中查看我的示例。我已经修改了示例以更好地反映我的问题
    • 我在您发表评论之前更新了代码。
    • 我稍微更新了代码以使其更简单。
    【解决方案3】:

    我将首先定义一个可以旋转数据的扩展方法

    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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-31
      • 2014-06-16
      相关资源
      最近更新 更多