python - 具有非唯一 bin 边缘的 qcut 会产生错误的分位数
问题描述
我有这个简单的方法来获得我的十分位数:
def output_deciles(model, X, y, order='predictions'):
results = pd.DataFrame(model.predict(X), index=X.index, columns=['predictions'])
results['actual'] = y
results['deciles'] = pd.qcut(results[order], 10, labels=False, duplicates='drop')
return results
如果我根据我的预测在十分位数上使用它,一切正常:
out = output_deciles(pipeline, X, y)
out.groupby('deciles')[['actual', 'predictions']].mean()
这是在大约 9400 条记录上。
但如果我试图得到我的实际值的十分位数,我只会得到 7 而不是 10 十分位数。这是因为我在这个目标中大约一半的值是 0:
out = output_deciles(pipeline, X, y, order='actual')
out.groupby('deciles')[['actual', 'predictions']].mean()
尽管有大量的独特价值:
print(len(out['actual'].unique()))
4593
这是违反直觉的——它几乎就像是丢弃了整个垃圾箱,而不仅仅是一些重复的值。但是,如果我将重复设置更改为“raise”,它会抛出:
ValueError: Bin 边缘必须是唯一的:array([-4.60517019, 0. , 0. , 0. , 0. , 3.47630251, 8.40045698, 10.11776099, 11.46706716, 12.86027487, 17.7007044 ])。
当我的意思是十分位数时,我如何得到十分位数,给定非唯一的 bin 边缘?
解决方案
您可能正在寻找的是一种自己构建“分位数”的方法。您可以通过排序然后使用整数除法来定义组来做到这一点。
我将在 0 处创建质量过大的数据,这样pd.qcut
会抱怨重复。
import pandas as pd
import numpy as np
np.random.seed(410012)
s = pd.Series(np.random.normal(0, 4, 1000))
s = pd.concat([s, pd.Series([0]*500)])
s = s.to_frame('vals')
N = 10
s = s.sort_values('vals')
s['q'] = np.arange(len(s)) // (len(s)/N)
有了 q,我们现在得到 10 个 bin。
s.groupby('q').describe()
# vals
# count mean std min 25% 50% 75% max
#q
#0.0 150.0 -6.5934 1.9208 -12.6041 -7.7703 -6.1546 -5.1073 -4.3421
#1.0 150.0 -3.1922 0.5621 -4.3287 -3.6605 -3.1293 -2.7377 -2.2718
#2.0 150.0 -1.4932 0.4203 -2.2561 -1.8196 -1.5262 -1.1364 -0.7451
#3.0 150.0 -0.1831 0.2400 -0.7425 -0.3371 -0.0110 0.0000 0.0000
#4.0 150.0 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
#5.0 150.0 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
#6.0 150.0 0.0238 0.0678 0.0000 0.0000 0.0000 0.0000 0.2856
#7.0 150.0 1.1555 0.4833 0.3353 0.7615 1.1837 1.5819 1.9513
#8.0 150.0 2.9430 0.6016 1.9660 2.4385 2.9665 3.4764 4.0277
#9.0 150.0 6.1692 1.6616 4.0336 4.8805 5.8176 6.9019 12.3437
不与问题值重叠的 bin 是相同的,但 0 是边缘的两个 bin 是不同的(因为它们已被折叠)
s.groupby(pd.qcut(s['vals'], 10, duplicates='drop'))['vals'].describe()
# count mean std min 25% 50% 75% max
#vals
#(-12.604999999999999, -4.33] 150.0 -6.5934 1.9208 -12.6041 -7.7703 -6.1546 -5.1073 -4.3421
#(-4.33, -2.259] 150.0 -3.1922 0.5621 -4.3287 -3.6605 -3.1293 -2.7377 -2.2718
#(-2.259, -0.743] 150.0 -1.4932 0.4203 -2.2561 -1.8196 -1.5262 -1.1364 -0.7451
#(-0.743, 0.0] 576.0 -0.0477 0.1463 -0.7425 0.0000 0.0000 0.0000 0.0000
#(0.0, 0.301] 24.0 0.1490 0.1016 0.0024 0.0457 0.1497 0.2485 0.2856
#(0.301, 1.954] 150.0 1.1555 0.4833 0.3353 0.7615 1.1837 1.5819 1.9513
#(1.954, 4.028] 150.0 2.9430 0.6016 1.9660 2.4385 2.9665 3.4764 4.0277
#(4.028, 12.344] 150.0 6.1692 1.6616 4.0336 4.8805 5.8176 6.9019 12.3437
推荐阅读
- node.js - 在 WSL 上安装 twilio-cli
- php - 如何根据请求的子目录进行不同的 htaccess 重定向?
- c++ - 从持续时间构造 std::chrono::system_clock::time_point
- javascript - React:如何获取已获取的 Promise 值
- amazon-web-services - Play Framework 如何故意延迟响应
- python-3.x - 如何通过 YouTube API 阻止 YouTube 搜索列表中的特定国家/地区?
- sorting - 如何使用 AQL 通过排序索引来抵消限制?
- vue.js - 什么时候将一个Vue组件拆分成多个组件(子组件)
- api-key - Quizlet API 不可用
- ios - iOS Testflight - 如何邀请个人测试人员