Desvio padrão em LINQ
-
20-09-2019 - |
Pergunta
O LINQ modela a função agregada SQL STDDEV()
(desvio padrão)?
Caso contrário, qual é a maneira mais simples / de melhores práticas de calculá-lo?
Exemplo:
SELECT test_id, AVERAGE(result) avg, STDDEV(result) std
FROM tests
GROUP BY test_id
Solução
Você pode fazer sua própria extensão calculando -a
public static class Extensions
{
public static double StdDev(this IEnumerable<double> values)
{
double ret = 0;
int count = values.Count();
if (count > 1)
{
//Compute the Average
double avg = values.Average();
//Perform the Sum of (value-avg)^2
double sum = values.Sum(d => (d - avg) * (d - avg));
//Put it all together
ret = Math.Sqrt(sum / count);
}
return ret;
}
}
Se você tem um amostra da população em vez de toda a população, então você deve usar ret = Math.Sqrt(sum / (count - 1));
.
Transformado em extensão de Adicionando desvio padrão ao Linq por Chris Bennett.
Outras dicas
A resposta de Dynami funciona, mas faz vários passes através dos dados para obter um resultado. Este é um único método de passagem que calcula o Amostra de desvio padrão:
public static double StdDev(this IEnumerable<double> values)
{
// ref: http://warrenseen.com/blog/2006/03/13/how-to-calculate-standard-deviation/
double mean = 0.0;
double sum = 0.0;
double stdDev = 0.0;
int n = 0;
foreach (double val in values)
{
n++;
double delta = val - mean;
mean += delta / n;
sum += delta * (val - mean);
}
if (1 < n)
stdDev = Math.Sqrt(sum / (n - 1));
return stdDev;
}
Isto é o Amostra de desvio padrão já que se divide por n - 1
. Para o desvio padrão normal que você precisa dividir por n
em vez de.
Isso usa Método de Welford que tem maior precisão numérica em comparação com o Average(x^2)-Average(x)^2
método.
Isso converte Resposta de David Clarke em uma extensão que segue a mesma forma que as outras funções agregadas do LINQ, como a média.
O uso seria: var stdev = data.StdDev(o => o.number)
public static class Extensions
{
public static double StdDev<T>(this IEnumerable<T> list, Func<T, double> values)
{
// ref: https://stackoverflow.com/questions/2253874/linq-equivalent-for-standard-deviation
// ref: http://warrenseen.com/blog/2006/03/13/how-to-calculate-standard-deviation/
var mean = 0.0;
var sum = 0.0;
var stdDev = 0.0;
var n = 0;
foreach (var value in list.Select(values))
{
n++;
var delta = value - mean;
mean += delta / n;
sum += delta * (value - mean);
}
if (1 < n)
stdDev = Math.Sqrt(sum / (n - 1));
return stdDev;
}
}
var stddev = Math.Sqrt(data.Average(z=>z*z)-Math.Pow(data.Average(),2));
Direto para o ponto (e c#> 6.0), a resposta dinamis se torna a seguinte:
public static double StdDev(this IEnumerable<double> values)
{
var count = values?.Count() ?? 0;
if (count <= 1) return 0;
var avg = values.Average();
var sum = values.Sum(d => Math.Pow(d - avg, 2));
return Math.Sqrt(sum / count);
}
public static double StdDev(this IEnumerable<int> values, bool as_sample = false)
{
var count = values.Count();
if (count > 0) // check for divide by zero
// Get the mean.
double mean = values.Sum() / count;
// Get the sum of the squares of the differences
// between the values and the mean.
var squares_query =
from int value in values
select (value - mean) * (value - mean);
double sum_of_squares = squares_query.Sum();
return Math.Sqrt(sum_of_squares / (count - (as_sample ? 1 : 0)))
}