Python:如何在Pandas中创建加权分位数?

时间:2017-08-06 02:26:31

标签: python pandas

我理解如何使用pd.qcut在Pandas中创建简单的分位数。但在搜索之后,我看不到任何可以创建加权分位数的内容。具体来说,我希望创建一个变量,它将感兴趣的变量(从最小到最大)的值加起来,这样每个bin包含相同的权重。到目前为止,这就是我所拥有的:

def wtdQuantile(dataframe, var, weight = None, n = 10):
    if weight == None:
        return pd.qcut(dataframe[var], n, labels = False)
    else:
        dataframe.sort_values(var, ascending = True, inplace = True)
        cum_sum = dataframe[weight].cumsum()
        cutoff = max(cum_sum)/n
        quantile = cum_sum/cutoff
        quantile[-1:] -= 1
        return quantile.map(int)

是否有一种更简单的方法,或者是我遗失的Pandas预设的东西?

修改:根据要求,我提供了一些示例数据。在下面,我试图将" Var"变量使用"重量"作为重量。使用pd.qcut,我们在每个bin中获得相同数量的观察。相反,我希望每个bin中的等权重,或者在这种情况下,尽可能接近相等。

Weight  Var  pd.qcut(n=5)  Desired_Rslt
   10     1            0              0
   14     2            0              0
   18     3            1              0
   15     4            1              1
   30     5            2              1
   12     6            2              2
   20     7            3              2
   25     8            3              3
   29     9            4              3
   45    10            4              4

1 个答案:

答案 0 :(得分:2)

我不认为这是Pandas内置的,但是下面的函数可以在几行中完成您想要的操作:

import numpy as np
import pandas as pd
from pandas._libs.lib import is_integer

def weighted_qcut(values, weights, q, **kwargs):
    if is_integer(q):
        quantiles = np.linspace(0, 1, q + 1)
    else:
        quantiles = q
    order = weights[values.argsort()].cumsum()
    bins = pd.cut(order / order.iloc[-1], quantiles, **kwargs)
    return bins.sort_index()

我们可以通过以下方式对您的数据进行测试:

data = pd.DataFrame({
    'var': range(1, 11),
    'weight': [10, 14, 18, 15, 30, 12, 20, 25, 29, 45]
})

data['qcut'] = pd.qcut(data['var'], 5, labels=False)
data['weighted_qcut'] = weighted_qcut(data['var'], data['weight'], 5, labels=False)
print(data)

输出与您期望的结果相匹配:

   var  weight  qcut  weighted_qcut
0    1      10     0              0
1    2      14     0              0
2    3      18     1              0
3    4      15     1              1
4    5      30     2              1
5    6      12     2              2
6    7      20     3              2
7    8      25     3              3
8    9      29     4              3
9   10      45     4              4