Как рассчитать STD dev и Average с linq и структурой сущностей одновременно - PullRequest
1 голос
/ 01 апреля 2020

Здравствуйте, я хотел бы спросить вас, есть ли способ рассчитать среднее и стандартное отклонение одновременно с LINQ.

var players = new List<Player>
{
    new Player { Name = "Alex", Team = "A", Score = 10 },
    new Player { Name = "Anna", Team = "A", Score = 20 },
    new Player { Name = "Luke", Team = "L", Score = 60 },
    new Player { Name = "Lucy", Team = "L", Score = 40 },
};

var teamAverageScores =
    from player in players
    group player by player.Team into playerGroup
    select new
    {
        Team = playerGroup.Key,
        AverageScore = playerGroup.Average(x => x.Score),
    };

Я хотел бы рассчитать в этом примере STDev для оценки и вернуть два разных списка, один для среднего и один для стандартного отклонения.

Ожидаемый результат для AverageScore:

{ Team = "A", AverageScore = 15.0 } 
{ Team = "L", AverageScore = 50.0 } 

И для стандартного отклонения:

{ Team = "A", STDScore = 5.0 } 
{ Team = "L", STDScore = 10.0 }

Ответы [ 3 ]

2 голосов
/ 01 апреля 2020

Исходя из этого , вам необходимо использовать метод расширения, подобный следующему:

public static class ExtensionsClass
{
    public static double CalculateStdDev(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;
    }
}

Тогда вы можете сделать:

var teamAverageScores =
     from player in players
     group player by player.Team into playerGroup
     select new
     {
         Team = playerGroup.Key,
         AverageScore = playerGroup.Average(c => c.Score),
         STDev = playerGroup.Select(c => c.Score).CalculateStdDev(),
     };
1 голос
/ 01 апреля 2020

Простым решением было бы использование пакета NuGet LinqStatistics для расчета баллов стандартного отклонения и Enumerable.Average() из LINQ для расчета средних баллов. Если вам не нравится использование внешних библиотек, то решение @ Salah Akbari подойдет лучше. Я подумал, что это хорошая идея - запустить эту библиотеку, так как я использовал ее в прошлом без проблем.

using LinqStatistics;

// Other code

// Class that stores results from query
// Might be cleaner than using an anonymous class
public class Result
{
    public string Team { get; set; }
    public double Average { get; set; }
    public double StdDev { get; set; }
}

var teamAverageScores = players
    .GroupBy(player => player.Team)
    .Select(grp => new Result
    {
         Team = grp.Key,
         Average = grp.Average(player => player.Score),
         StdDev = grp.StandardDeviation(player => player.Score)
    });

Попробуйте dotnetfiddle. net

Примечание: Приведенное выше описание использует синтаксис метода LINQ полностью, вместо синтаксис запроса . Вы можете прочитать о различиях между этими различными типами синтаксиса в MSDN . Использование любого из них сводится к предпочтению.

0 голосов
/ 01 апреля 2020

Я нашел решение после нескольких попыток

var teamAverageScores =
        from player in players
        group player by player.Team into playerGroup
        select new
        {
            Team = playerGroup.Key,
            AverageScore = playerGroup.Average(c => c.Score),
            STDev =  (playerGroup.Count() == 1) ? 0 : Math.Sqrt(playerGroup.Sum(b => Math.Pow(playerGroup.Score - playerGroup.Average(c => c.Score), 2)) / (g.Count() - 1)),,
        };
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...