【问题标题】:Map each value of a list to its weighted percentile将列表的每个值映射到其加权百分位数
【发布时间】:2018-06-24 07:23:47
【问题描述】:

我想计算一个列表(或 numpy 数组)中每个值的百分位数,由另一个列表中的权重加权。例如,给定一些 f 我想要:

x = [1, 2, 3, 4]
weights = [2, 2, 3, 3]
f(x, weights)

产生[20, 40, 70, 100]

我可以使用

计算单个项目的未加权百分位数
from scipy import stats
stats.percentileofscore(x, 3)
# 75.0

Map each list value to its corresponding percentile 我也可以为每个使用计算这个

[stats.percentileofscore(x, a, 'rank') for a in x]
# [25.0, 50.0, 75.0, 100.0]

根据Weighted version of scipy percentileofscore,我可以使用以下方法计算单个项目的加权百分位数:

def weighted_percentile_of_score(x, weights, score, kind='weak'):
    npx = np.array(x)
    npw = np.array(weights)

    if kind == 'rank':  # Equivalent to 'weak' since we have weights.
        kind = 'weak'

    if kind in ['strict', 'mean']:
        indx = npx < score
        strict = 100 * sum(npw[indx]) / sum(weights)
    if kind == 'strict':
        return strict

    if kind in ['weak', 'mean']:    
        indx = npx <= score
        weak = 100 * sum(npw[indx]) / sum(weights)
    if kind == 'weak':
        return weak

    if kind == 'mean':
        return (strict + weak) / 2

称为:

weighted_percentile_of_score(x, weights, 3))  # 70.0 as desired.

我如何(有效地)为列表中的每个项目执行此操作?

【问题讨论】:

    标签: python numpy scipy


    【解决方案1】:

    这不是很有效,但您可以结合问题中列出的方法:

    [weighted_percentile_of_score(x, weights, val) for val in x]
    # [20.0, 40.0, 70.0, 100.0]
    

    【讨论】:

      【解决方案2】:

      this answer 调整为Weighted percentile using numpy,您可以对数组进行排序,然后将cumsum 的权重除以总权重:

      def weighted_percentileofscore(values, weights=None, values_sorted=False):
          """ Similar to scipy.percentileofscore, but supports weights.
          :param values: array-like with data.
          :param weights: array-like of the same length as `values`.
          :param values_sorted: bool, if True, then will avoid sorting of initial array.
          :return: numpy.array with percentiles of sorted array.
          """
          values = np.array(values)
          if weights is None:
              weights = np.ones(len(values))
          weights = np.array(weights)
      
          if not values_sorted:
              sorter = np.argsort(values)
              values = values[sorter]
              weights = weights[sorter]
      
          total_weight = weights.sum()
          return 100 * np.cumsum(weights) / total_weight
      

      验证:

      weighted_percentileofscore(x, weights)
      # array([20., 40., 70., 100. ])
      

      如果传递了未排序的数组,则必须将其映射回原始排序,因此最好先排序。

      这应该比单独计算每个值要快得多。

      【讨论】:

        猜你喜欢
        • 2012-09-07
        • 2018-05-15
        • 2021-12-03
        • 2019-05-28
        • 2016-05-26
        • 2021-02-21
        • 2019-04-05
        • 1970-01-01
        相关资源
        最近更新 更多