我理解如何使用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
答案 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