使用LINQ计算百分位数

时间:2014-12-29 02:41:39

标签: c# linq percentile

所有

在回顾了StackOverflow和更广泛的互联网之后,我仍然在努力有效使用LINQ计算百分位数。

其中percentile是统计中使用的度量,表示一组观察值中观察到的给定百分比下降的值。下面的示例尝试将值列表转换为数组,其中每个(唯一)值表示为关联百分位数。 列表的min()和max()必须是返回的数组百分位数的0%和100%。

使用LINQPad,以下代码生成所需的输出VP []:

enter image description here

这可以解释为:   - 在0%时,最小值为1   - 在100%时,最大值为3   - 在最小值和最大值之间的50%处,值为2

void Main()
{
    var list = new List<double> {1,2,3};
    double denominator = list.Count - 1;   
    var answer = list.Select(x => new VP
        {
            Value = x,
            Percentile = list.Count(y => x > y) / denominator
        })
        //.GroupBy(grp => grp.Value) --> commented out until attempted duplicate solution 
        .ToArray();
    answer.Dump();
}

public struct VP
{
    public double Value;
    public double Percentile;
}

然而,当&#34; list&#34;时,这会返回错误的VP []。包含重复的条目(例如1,2,** 2,** 3):

enter image description here

我尝试按列表中的唯一值进行分组(通过包含&#34; .GroupBy(grp =&gt; grp.Value)&#34;)未能产生所需的结果(值= 2,&amp;百分位数= 0.666):

enter image description here

欢迎所有建议。包括使用&#34; list.Count(y =&gt; x&gt; y)&#34;重复迭代,这是否是一种有效的方法。

一如既往,谢谢 香农

3 个答案:

答案 0 :(得分:1)

我不确定我理解这个问题的要求。当我运行接受的答案的代码时,我得到了这个结果:

original result

但如果我将输入更改为:

var dataSet = new List<double> { 1, 1, 1, 1, 2, 3, 3, 3, 2 };

...然后我得到了这个结果:

updated result

使用行“列表的min()和max()必须是返回的数组百分位数的0%和100%。”在我看来,OP要求的值从0到1,但更新的结果超过了1。

我觉得第一个值应该是0%似乎也不对,因为我不确定这对数据的意义是什么。

在阅读链接的维基百科页面后,似乎OP实际上正在尝试进行反向计算以计算百分位数值。事实上,文章说0的百分位是未定义的。这是有道理的,因为0的百分位数将是空值集 - 并且空集的最大值是多少?

OP似乎是从价值计算百分位数。因此,从这个意义上说,并且知道0未定义,似乎最合适的计算值是等于或低于集合中每个不同值的值的百分比。

现在,如果我使用Microsoft的Reactive Framework Team的Interactive Extensions(NuGet“Ix-Main”),那么我可以运行此代码:

var dataSet = new List<double> { 1, 1, 1, 1, 2, 3, 3, 3, 2 };

var result =
    dataSet
        .GroupBy(x => x)
        .Scan(
            new VP()
            {
                Value = double.MinValue, Proportion = 0.0
            },
            (a, x) =>
                new VP()
                {
                    Value = x.Key,
                    Proportion = a.Proportion + (double)x.Count() / dataSet.Count
                });

我得到了这个结果:

result

这告诉我大约44%的值是1;大约67%的值是1或2; 100%的值为1,2或3。

在我看来,这是最符合要求的逻辑计算。

答案 1 :(得分:0)

void Main()
{
    var list = new List<double> {1,2,3};
    double denominator = list.Count - 1;   
    var answer = list.OrderBy(x => x).Select(x => new VP
        {
            Value = x,
            Proportion = list.IndexOf(x) / denominator
        })
        .ToArray();
    answer.Dump();
}

public struct VP
{
    public double Value;
    public double Proportion;
}

答案 2 :(得分:0)

这就是我做的。我更改了一些变量名以使上下文更清晰。

var dataSet = new List<double> { 1, 2, 3, 2 };
double denominator = dataSet.Count - 1;
var uniqueValues = dataSet.Distinct();
var vp = dataSet.Select(value => new VP
{
    Value = value,
    Proportion = dataSet.Count(datum => value > datum) / denominator
});

var answer = uniqueValues.Select(u => new VP{
    Value = u,
    Proportion = vp.Where(v => v.Value == u).Select(x => x.Proportion).Sum()
});