【问题标题】:Finding the First and Third Quartiles找到第一和第三四分位数
【发布时间】:2019-07-26 20:39:38
【问题描述】:

我想要做的是得到我数字的每一半的中间。 所以我已经创建的是一种在此处获取数字中间值(数学中的中位数)的方法;

    public static String Find_Median()
    {
        double Size = list.Count;
        double Final_Number = 0;
        if (Size % 2 == 0)
        {
            int HalfWay = list.Count / 2;
            double Value1 = Convert.ToDouble(list[HalfWay - 1].ToString());
            double Value2 = Convert.ToDouble(list[HalfWay - 1 + 1].ToString());
            double Number = Value1 + Value2;
            Final_Number = Number / 2;
        }
        else
        {
            int HalfWay = list.Count / 2;
            double Value1 = Convert.ToDouble(list[HalfWay].ToString());
            Final_Number = Value1;
        }
        return Convert.ToString(Final_Number);
    }

这会得到列表中所有数字的确切中间数字,即使它到达中间它也会进行数学运算。 我想在双方都这样做;这是一个例子;

3 2 1 4 5 6

该列表的中间值(中位数)是 3.5。 我想用数学来找到 2,它位于等式的开始和中间。在 IQR 中也称为 Q1。我也想知道如何找到中位数(中间)和结尾之间的中间数,即 5。

I.E.所以我可以找到 70,80 和 90 的代码。

【问题讨论】:

  • 4 3 2 1列表的答案应该是什么?
  • list[list.Count/2], list[list.Count/4], list[3*list.Count/4],这就是你想要的吗?
  • @SWeko 不知道如何从这么小的数字池中获得第一个和第三个,但在数学中,数字列表总是大于 4。
  • 为什么不把这个列表分成另外两个列表并使用相同的方法呢? list1 = list.Where(x => x < Final_Number), list2 = list.Where(x => x > Final_Number)
  • 我不确定如何正确地做到这一点,因此我需要一些帮助:3

标签: c# math


【解决方案1】:

我刚刚遇到了同样的问题,并检查了wikipedia entry for Quartile,它比最初出现的要复杂一些。

我的方法如下:(这似乎适用于所有情况,N=1 以上)...

 /// <summary>
/// Return the quartile values of an ordered set of doubles
///   assume the sorting has already been done.
///   
/// This actually turns out to be a bit of a PITA, because there is no universal agreement 
///   on choosing the quartile values. In the case of odd values, some count the median value
///   in finding the 1st and 3rd quartile and some discard the median value. 
///   the two different methods result in two different answers.
///   The below method produces the arithmatic mean of the two methods, and insures the median
///   is given it's correct weight so that the median changes as smoothly as possible as 
///   more data ppints are added.
///    
/// This method uses the following logic:
/// 
/// ===If there are an even number of data points:
///    Use the median to divide the ordered data set into two halves. 
///    The lower quartile value is the median of the lower half of the data. 
///    The upper quartile value is the median of the upper half of the data.
///    
/// ===If there are (4n+1) data points:
///    The lower quartile is 25% of the nth data value plus 75% of the (n+1)th data value.
///    The upper quartile is 75% of the (3n+1)th data point plus 25% of the (3n+2)th data point.
///    
///===If there are (4n+3) data points:
///   The lower quartile is 75% of the (n+1)th data value plus 25% of the (n+2)th data value.
///   The upper quartile is 25% of the (3n+2)th data point plus 75% of the (3n+3)th data point.
/// 
/// </summary>
internal Tuple<double, double, double> Quartiles(double[] afVal)
{
    int iSize = afVal.Length;
    int iMid = iSize / 2; //this is the mid from a zero based index, eg mid of 7 = 3;

    double fQ1 = 0;
    double fQ2 = 0;
    double fQ3 = 0;

    if (iSize % 2 == 0)
    {
        //================ EVEN NUMBER OF POINTS: =====================
        //even between low and high point
        fQ2 = (afVal[iMid - 1] + afVal[iMid]) / 2;

        int iMidMid = iMid / 2;

        //easy split 
        if (iMid % 2 == 0)
        {
            fQ1 = (afVal[iMidMid - 1] + afVal[iMidMid]) / 2;
            fQ3 = (afVal[iMid + iMidMid - 1] + afVal[iMid + iMidMid]) / 2;
        }
        else
        {
            fQ1 = afVal[iMidMid];
            fQ3 = afVal[iMidMid + iMid];
        }
    }
    else if (iSize == 1)
    {
        //================= special case, sorry ================
        fQ1 = afVal[0];
        fQ2 = afVal[0];
        fQ3 = afVal[0];
    }
    else
    {
        //odd number so the median is just the midpoint in the array.
        fQ2 = afVal[iMid];

        if ((iSize - 1) % 4 == 0)
        {
            //======================(4n-1) POINTS =========================
            int n = (iSize - 1) / 4;
            fQ1 = (afVal[n - 1] * .25) + (afVal[n] * .75);
            fQ3 = (afVal[3 * n] * .75) + (afVal[3 * n + 1] * .25);
        }
        else if ((iSize - 3) % 4 == 0)
        {
            //======================(4n-3) POINTS =========================
            int n = (iSize - 3) / 4;

            fQ1 = (afVal[n] * .75) + (afVal[n + 1] * .25);
            fQ3 = (afVal[3 * n + 1] * .25) + (afVal[3 * n + 2] * .75);
        }
    }

    return new Tuple<double, double, double>(fQ1, fQ2, fQ3);
}

有很多方法可以计算四分位数:

我在这里尽了最大努力来实现 R 文档中描述为 type = 8 Quartile(array, type=8) 的四分位数版本:https://www.rdocumentation.org/packages/stats/versions/3.5.1/topics/quantile。 R 函数described here 的作者更喜欢这种方法,因为它可以在值之间产生更平滑的过渡。但是,R 默认使用方法 7,这与 S 和 Excel 使用的函数相同。

如果您只是在谷歌上搜索答案,而不考虑输出的含义或您想要达到的结果,这可能会给您带来惊喜。

【讨论】:

  • 它在我的机器学习异常值查找器中就像一个魅力。谢谢。
【解决方案2】:

我知道这是一个老问题,所以我争论了一会儿是否应该添加下面的答案,由于投票最多的答案与 Excel 四分位数的数字不匹配,我决定在下面发布答案。

我还需要找到第一和第三四分位数,因为我正在尝试绘制直方图并创建 bin 宽度和范围,我使用的是 Freedman–Diaconis 规则,该规则需要知道第一和第三四分位数。我从Mike's answer开始。

但在数据验证过程中,我注意到结果与 Excel 中计算四分位数的方式和使用 Ploltly 创建的直方图不匹配,因此我进一步挖掘并偶然发现了以下两个链接:

第二个链接中的幻灯片 12 指出“第 P 个百分位数的位置由 (n + 1)P/100 给出,其中 n 是集合中的观察数。”

所以来自C# Descriptive Statistic Class 的等效 C# 代码是:

    /// <summary>
    /// Calculate percentile of a sorted data set
    /// </summary>
    /// <param name="sortedData"></param>
    /// <param name="p"></param>
    /// <returns></returns>
    internal static double Percentile(double[] sortedData, double p)
    {
        // algo derived from Aczel pg 15 bottom
        if (p >= 100.0d) return sortedData[sortedData.Length - 1];

        double position = (sortedData.Length + 1) * p / 100.0;
        double leftNumber = 0.0d, rightNumber = 0.0d;

        double n = p / 100.0d * (sortedData.Length - 1) + 1.0d;

        if (position >= 1)
        {
            leftNumber = sortedData[(int)Math.Floor(n) - 1];
            rightNumber = sortedData[(int)Math.Floor(n)];
        }
        else
        {
            leftNumber = sortedData[0]; // first data
            rightNumber = sortedData[1]; // first data
        }

        //if (leftNumber == rightNumber)
        if (Equals(leftNumber, rightNumber))
            return leftNumber;
        double part = n - Math.Floor(n);
        return leftNumber + part * (rightNumber - leftNumber);
    } // end of internal function percentile

测试用例(用 Visual Studio 2017 编写):

    static void Main()
    {
        double[] x = { 18, 18, 18, 18, 19, 20, 20, 20, 21, 22, 22, 23, 24, 26, 27, 32, 33, 49, 52, 56 };
        var q1 = Percentile(x, 25);
        var q2 = Percentile(x, 50);
        var q3 = Percentile(x, 75);
        var iqr = q3 - q1;

        var (q1_mike, q2_mike, q3_mike) = Quartiles(x); //Uses named tuples instead of regular Tuple
        var iqr_mike = q3_mike - q1_mike;
    }

结果对比:

您会注意到结果与幻灯片 12 中提到的 Statistics 理论相匹配。

  • 来自代码:

  • 来自 excel(匹配 q1、q2 和 q3 值)

【讨论】:

    【解决方案3】:

    在以下列表上运行相同的方法:

    list1 = list.Where(x => x < Median)
    list2 = list.Where(x => x > Median) 
    

    Find_Median(list1) 将返回第一个四分位数, Find_Median(list2) 将返回第三个四分位数

    【讨论】:

    【解决方案4】:

    一种可以调整的快捷方式

    var q3 = table.Skip(table.Length * 3 / 4).Take(1);
    var q1 = table.Skip(table.Length * 1 / 4).Take(1);
    

    【讨论】:

      猜你喜欢
      • 2021-08-25
      • 2017-07-11
      • 2018-02-06
      • 2016-08-30
      • 2021-12-12
      • 1970-01-01
      • 2017-05-21
      • 2017-11-23
      相关资源
      最近更新 更多