Melhor maneira de usar funções estatísticas do Math.NET nas propriedades de objetos em uma lista
-
21-12-2019 - |
Pergunta
Estou tentando descobrir a melhor maneira de realizar um cálculo rápido e queria descobrir que tipo de abordagem as pessoas normalmente adotariam em uma situação como essa.
Eu tenho uma lista de objetos que possuem propriedades das quais desejo calcular a média e o desvio padrão.pensei em usar esse A biblioteca Math.NET provavelmente seria mais fácil/otimizada para desempenho.
Infelizmente, os argumentos de entrada para estas funções são arrays.Minha única solução é escrever minha própria função para calcular meios e DSTs?Posso escrever algum tipo de método de extensão para listas que usem funções lambda como aqui?Ou é melhor escrever funções que retornem matrizes das propriedades do meu objeto e usá-las com o Math.NET.
Presumivelmente, a resposta depende de algumas coisas como o tamanho da lista?Digamos, para fins de argumentação, que a lista tenha 50 elementos.Minha preocupação é puramente desempenho.
Solução
ArrayStatistics
na verdade, espera arrays, pois é otimizado para este caso especial (é por isso que é chamado de ArrayStatistics).De forma similar, StreamingStatistics
é otimizado para streaming de sequência IEnumerable sem manter dados na memória.A classe geral que funciona com todos os tipos de entrada é a Statistics
aula.
Você verificou que simplesmente usar LINQ e StreamingStatistics não é rápido o suficiente no seu caso de uso?Calcular essas estatísticas para uma lista de apenas 50 entradas quase não é mensurável, a menos que você faça isso um milhão de vezes seguidas.
Exemplo com Math.NET Numerics v3.0.0-alpha7, usando tuplas em uma lista para emular seus tipos personalizados:
using MathNet.Numerics.Statistics;
var data = new List<Tuple<string, double>>
{
Tuple.Create("A", 1.0),
Tuple.Create("B", 2.0),
Tuple.Create("C", 1.5)
};
// using the normal extension methods within `Statistics`
var stdDev1 = data.Select(x => x.Item2).StandardDeviation();
var mean1 = data.Select(x => x.Item2).Mean();
// single pass variant (unfortunately there's no single pass MeanStdDev yet):
var meanVar2 = data.Select(x => x.Item2).MeanVariance();
var mean2 = meanVar2.Item1;
var stdDev2 = Math.Sqrt(meanVar2.Item2);
// directly using the `StreamingStatistics` class:
StreamingStatistics.MeanVariance(data.Select(x => x.Item2));
Outras dicas
A solução mais fácil que você pode usar é colocar Linq então isso transforma List
para variedade
List<SomeClass> list = ...
GetMeanAndStdError(list.ToArray()); // <- Not that good performance
No entanto, se o desempenho é sua preocupação, você prefere calcular a Média e a Variância explicitamente (escreva sua própria função):
List<SomeClass> list = ...
Double sumX = 0.0;
Double sumXX = 0.0;
foreach (var item in list) {
Double x = item.SomeProperty;
sumX += x;
sumXX += x * x;
}
Double mean = sumX / list.Count;
Double variance = (sumXX / list.Count - mean);