【问题标题】:How to calculate 1st and 3rd quartiles?如何计算第一和第三四分位数?
【发布时间】:2018-02-06 03:36:21
【问题描述】:

我有数据框:

    time_diff   avg_trips
0   0.450000    1.0
1   0.483333    1.0
2   0.500000    1.0
3   0.516667    1.0
4   0.533333    2.0

我想获得time_diff 列的第一个四分位数、第三个四分位数和中位数。为了获得中位数,我使用np.median(df["time_diff"].values)

如何计算四分位数?

【问题讨论】:

标签: python python-2.7 pandas numpy


【解决方案1】:

通过使用pandas:

df.time_diff.quantile([0.25,0.5,0.75])


Out[793]: 
0.25    0.483333
0.50    0.500000
0.75    0.516667
Name: time_diff, dtype: float64

【讨论】:

  • 请记住,有 15 种不同的方法来计算四分位数。所以请仔细看看,因为不同的函数可能会给出略有不同的结果(pandas vs numpy vs scipy..)jse.amstat.org/v14n3/langford.html
  • 是的,我曾经使用df.quantile(q=[0.25, 0.75], axis=0, numeric_only=True, interpolation='midpoint') -- 这会计算数据帧的 Q1 和 Q3(每个系列分别)
【解决方案2】:

您可以使用np.percentile计算四分位数(包括中位数):

>>> np.percentile(df.time_diff, 25)  # Q1
0.48333300000000001

>>> np.percentile(df.time_diff, 50)  # median
0.5

>>> np.percentile(df.time_diff, 75)  # Q3
0.51666699999999999

或一次性:

>>> np.percentile(df.time_diff, [25, 50, 75])
array([ 0.483333,  0.5     ,  0.516667])

【讨论】:

    【解决方案3】:

    巧合的是,这些信息是使用describe 方法捕获的:

    df.time_diff.describe()
    
    count    5.000000
    mean     0.496667
    std      0.032059
    min      0.450000
    25%      0.483333
    50%      0.500000
    75%      0.516667
    max      0.533333
    Name: time_diff, dtype: float64
    

    【讨论】:

    • 如何将 25% 和平均值称为 vars my_meanmy_firstquartile
    • my_mean = df.time_diff.describe()[1] my_firstquartile = df.time_diff.describe()[4]
    【解决方案4】:

    np.percentile 计算 Q1、中位数和 Q3 的值。考虑下面的排序列表:

    samples = [1, 1, 8, 12, 13, 13, 14, 16, 19, 22, 27, 28, 31]
    

    运行 np.percentile(samples, [25, 50, 75]) 从列表中返回实际值:

    Out[1]: array([12., 14., 22.])
    

    但是,四分位数是Q1=10.0, Median=14, Q3=24.5(您也可以使用此link 在线查找四分位数和中位数)。 可以使用下面的代码来计算排序列表的四分位数和中位数(因为排序这种方法需要O(nlogn) 计算,其中n 是项目数)。 此外,可以使用Median of medians 选择算法 (order statistics) 在O(n) 计算中找到四分位数和中位数。

    samples = sorted([28, 12, 8, 27, 16, 31, 14, 13, 19, 1, 1, 22, 13])
    
    def find_median(sorted_list):
        indices = []
    
        list_size = len(sorted_list)
        median = 0
    
        if list_size % 2 == 0:
            indices.append(int(list_size / 2) - 1)  # -1 because index starts from 0
            indices.append(int(list_size / 2))
    
            median = (sorted_list[indices[0]] + sorted_list[indices[1]]) / 2
            pass
        else:
            indices.append(int(list_size / 2))
    
            median = sorted_list[indices[0]]
            pass
    
        return median, indices
        pass
    
    median, median_indices = find_median(samples)
    Q1, Q1_indices = find_median(samples[:median_indices[0]])
    Q2, Q2_indices = find_median(samples[median_indices[-1] + 1:])
    
    quartiles = [Q1, median, Q2]
    
    print("(Q1, median, Q3): {}".format(quartiles))
    

    【讨论】:

    • 这是正确答案。我花了至少一个小时试图理解为什么describe 没有输出精确的四分位数,直到我认为第 25 个百分位数不完全等于 Q1。干得好!
    • @Wladston 如果样本中有重复值,则会产生不同的结果
    • 百分位数没有单一的定义,所以在这种情况下,几乎每个人都能得到正确答案。
    【解决方案5】:

    在 Babak 所说的基础上建立或者更正一点……

    np.percentile 确实很多计算 Q1、中位数和 Q3 的值。考虑下面的排序列表:

    s1=[18,45,66,70,76,83,88,90,90,95,95,98]
    

    运行 np.percentile(s1, [25, 50, 75]) 从列表中返回实际值:

    [69.  85.5  91.25]
    

    但是,四分位数是 Q1=68.0,Median=85.5,Q3=92.5,这是正确的说法

    我们这里缺少的是np.percentileinterpolation 参数和相关函数。默认情况下,此参数的值为 linear。此可选参数指定在所需分位数位于两个数据点 i 之间时使用的插值方法 线性:i + (j - i) * 分数,其中分数是由 i 和 j 包围的索引的小数部分。
    较低:i.
    更高:j.
    最近:i 或 j,以最近者为准。
    中点:(i + j) / 2.

    因此运行 np.percentile(s1, [25, 50, 75], interpolation='midpoint') 返回列表的实际结果:

    [68. 85.5 92.5]
    

    【讨论】:

    • NOT 对赛勒斯使用的相同值列表起作用,“中点”是他列表的“线性”结果。您的解决方案有效,因为您有偶数个值。 Cyrus 有奇数个值,如果你添加一个额外的值,这仍然会给你预期的结果吗?
    【解决方案6】:

    使用np.percentile

    q75, q25 = np.percentile(DataFrame, [75,25])
    iqr = q75 - q25
    

    How do you find the IQR in Numpy?的回答

    【讨论】:

    • q25 和 q75 分别是上半年和下半年的中位数,如果我想要上半年的平均值和下半年的平均值?
    【解决方案7】:

    你可以使用

    df.describe()
    

    显示信息

    【讨论】:

      【解决方案8】:

      如果你想使用 raw python 而不是 numpy 或 panda,你可以使用 python stats 模块来查找列表的上半部分和下半部分的中位数:

          >>> import statistics as stat
          >>> def quartile(data):
                  data.sort()               
                  half_list = int(len(data)//2)
                  upper_quartile = stat.median(data[-half_list]
                  lower_quartile = stat.median(data[:half_list])
                  print("Lower Quartile: "+str(lower_quartile))
                  print("Upper Quartile: "+str(upper_quartile))
                  print("Interquartile Range: "+str(upper_quartile-lower_quartile)
      
          >>> quartile(df.time_diff)
      

      第一行:导入别名“stat”下的统计模块

      第2行:定义四分位函数

      第 3 行:对数据进行升序排序

      第4行:获取列表一半的长度

      第5行:获取列表下半部分的中位数

      第6行:获取列表上半部分的中位数

      第 7 行:打印下四分位数

      第 8 行:打印上四分位数

      第 9 行:打印四分位距

      第 10 行:运行 DataFrame 的 time_diff 列的四分位函数

      【讨论】:

        【解决方案9】:

        在我努力学习面向对象编程和学习统计的过程中,我做了这个,也许你会发现它很有用:

        samplesCourse = [9, 10, 10, 11, 13, 15, 16, 19, 19, 21, 23, 28, 30, 33, 34, 36, 44, 45, 47, 60]
        
        class sampleSet:
            def __init__(self, sampleList):
                self.sampleList = sampleList
                self.interList = list(sampleList) # interList is sampleList alias; alias used to maintain integrity of original sampleList
        
            def find_median(self):
                self.median = 0
        
                if len(self.sampleList) % 2 == 0:
                    # find median for even-numbered sample list length
                    self.medL = self.interList[int(len(self.interList)/2)-1]
                    self.medU = self.interList[int(len(self.interList)/2)]
                    self.median = (self.medL + self.medU)/2
        
                else:
                    # find median for odd-numbered sample list length
                    self.median = self.interList[int((len(self.interList)-1)/2)]
                return self.median
        
            def find_1stQuartile(self, median):
                self.lower50List = []
                self.Q1 = 0
        
                # break out lower 50 percentile from sampleList
                if len(self.interList) % 2 == 0:
                    self.lower50List = self.interList[:int(len(self.interList)/2)]
                else:
                    # drop median to make list ready to divide into 50 percentiles
                    self.interList.pop(interList.index(self.median))
                    self.lower50List = self.interList[:int(len(self.interList)/2)]
        
                # find 1st quartile (median of lower 50 percentiles)
                if len(self.lower50List) % 2 == 0:
                    self.Q1L = self.lower50List[int(len(self.lower50List)/2)-1]
                    self.Q1U = self.lower50List[int(len(self.lower50List)/2)]
                    self.Q1 = (self.Q1L + self.Q1U)/2
        
                else:
                    self.Q1 = self.lower50List[int((len(self.lower50List)-1)/2)]
        
                return self.Q1
        
            def find_3rdQuartile(self, median):
                self.upper50List = []
                self.Q3 = 0
        
                # break out upper 50 percentile from sampleList
                if len(self.sampleList) % 2 == 0:
                    self.upper50List = self.interList[int(len(self.interList)/2):]
                else:
                    self.interList.pop(interList.index(self.median))
                    self.upper50List = self.interList[int(len(self.interList)/2):]
        
                # find 3rd quartile (median of upper 50 percentiles)
                if len(self.upper50List) % 2 == 0:
                    self.Q3L = self.upper50List[int(len(self.upper50List)/2)-1]
                    self.Q3U = self.upper50List[int(len(self.upper50List)/2)]
                    self.Q3 = (self.Q3L + self.Q3U)/2
        
                else:
                    self.Q3 = self.upper50List[int((len(self.upper50List)-1)/2)]
        
                return self.Q3
        
            def find_InterQuartileRange(self, Q1, Q3):
                self.IQR = self.Q3 - self.Q1
                return self.IQR
        
            def find_UpperFence(self, Q3, IQR):
                self.fence = self.Q3 + 1.5 * self.IQR
                return self.fence
        
        samples = sampleSet(samplesCourse)
        median = samples.find_median()
        firstQ = samples.find_1stQuartile(median)
        thirdQ = samples.find_3rdQuartile(median)
        iqr = samples.find_InterQuartileRange(firstQ, thirdQ)
        fence = samples.find_UpperFence(thirdQ, iqr)
        
        print("Median is: ", median)
        print("1st quartile is: ", firstQ)
        print("3rd quartile is: ", thirdQ)
        print("IQR is: ", iqr)
        print("Upper fence is: ", fence)
        

        【讨论】:

          【解决方案10】:

          当我试图找到一个找到四分位数的包时,我也遇到了类似的问题。这并不是说其他​​人错了,而是说这就是我个人对四分位数的定义。它类似于 Shikar 使用中点的结果,但也适用于奇数长度的列表。如果四分位位置在长度之间,它将使用相邻值的平均值。 (即位置始终被视为确切位置或位置的 0.5)

          import math
          
          def find_quartile_postions(size):
              if size == 1:
                  # All quartiles are the first (only) element
                  return 0, 0, 0
              elif size == 2:
                  # Lower quartile is first element, Upper quartile is second element, Median is average
                  # Set to 0.5, 0.5, 0.5 if you prefer all quartiles to be the mean value
                  return 0, 0.5, 1
              else:
                  # Lower quartile is element at 1/4th position, median at 1/2th, upper at 3/4
                  # Quartiles can be between positions if size + 1 is not divisible by 4
                  return (size + 1) / 4 - 1, (size + 1) / 2 - 1, 3 * (size + 1) / 4 - 1
          
          def find_quartiles(num_array):
              size = len(num_array)
              
              if size == 0:
                  quartiles = [0,0,0]
              else:
                  sorted_array = sorted(num_array)
                  lower_pos, median_pos, upper_pos = find_quartile_postions(size)
          
                  # Floor so can work in arrays
                  floored_lower_pos = math.floor(lower_pos)
                  floored_median_pos = math.floor(median_pos)
                  floored_upper_pos = math.floor(upper_pos)
          
                  # If position is an integer, the quartile is the elem at position
                  # else the quartile is the mean of the elem & the elem one position above
                  lower_quartile = (sorted_array[floored_lower_pos]
                                    if (lower_pos % 1 == 0)
                                    else (sorted_array[floored_lower_pos] + sorted_array[floored_lower_pos + 1]) / 2
                                   )
          
                  median = (sorted_array[floored_median_pos]
                                    if (median_pos % 1 == 0)
                                    else (sorted_array[floored_median_pos] + sorted_array[floored_median_pos + 1]) / 2
                                   )
          
                  upper_quartile = (sorted_array[floored_upper_pos]
                                    if (upper_pos % 1 == 0)
                                    else (sorted_array[floored_upper_pos] + sorted_array[floored_upper_pos + 1]) / 2
                                   )
          
                  quartiles = [lower_quartile, median, upper_quartile]
          
              return quartiles
          

          【讨论】:

            【解决方案11】:

            试试这个方法:

            dfo = sorted(df.time_diff)
            
            n=len(dfo)
            
            Q1=int((n+3)/4)  
            Q3=int((3*n+1)/4)  
            
            
            print("Q1 position: ", Q1, "Q1 position: " ,Q3)
            
            print("Q1 value: ", dfo[Q1], "Q1 value: ", dfo[Q3])
            

            【讨论】:

              【解决方案12】:

              如果你对使用 JS 感兴趣,我已经开发了一个解决方案:

              var
              withThis = (obj, cb) => cb(obj),
              sort = array => array.sort((a, b) => a - b),
              
              fractile = (array, parts, nth) => withThis(
                (nth * (array.length + 1) / parts),
                decimal => withThis(Math.floor(decimal),
                  even => withThis(sort(array),
                    sorted => sorted[even - 1] + (
                      (decimal - even) * (
                        sorted[even] - sorted[even - 1]
                      )
                    )
                  )
                )
              ),
              
              data = [
                78, 72, 74, 79, 74, 71, 75, 74, 72, 68,
                72, 73, 72, 74, 75, 74, 73, 74, 65, 72,
                66, 75, 80, 69, 82, 73, 74, 72, 79, 71,
                70, 75, 71, 70, 70, 70, 75, 76, 77, 67
              ]
              
              fractile(data, 4, 1) // 1st Quartile is 71
              fractile(data, 10, 3) // 3rd Decile is 71.3
              fractile(data, 100, 82) // 82nd Percentile is 75.62
              

              您只需将代码复制粘贴到浏览器中即可获得准确的结果。 更多关于 'Statistics with JS' 的信息可以在https://gist.github.com/rikyperdana/a7349c790cf5b034a1b77db64415e73c/edit找到。

              【讨论】:

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