对于数据分箱,常用到的一个函数叫做pd.cut(),这个函数可以通过指定分箱个数或者每个箱体的分界值对数据进行分箱处理。其实,除了pd.cut(),还有一个函数即pd.qcut()也可以对数据进行分箱,那么和pd.cut()相比,pd.qcut()有什么不同呢?
试想一下如果我们有一个很大的数据集,需要对其中一项进行分箱,分箱的依据不是单纯的等宽箱体或者没有确定的分解值,而是按照分位数进行分箱,比如前四分之一的是一个箱体这种要求,用pd.cut()不是不能实现,只是比较麻烦,还要先计算分位数作为分解值。这个时候,pd.qcut()就方便很多了。
pd.qcut()参数介绍
先看一下官方文档给出的函数作用:
基于分位数的离散化功能。 将变量离散化为基于等级或样本分位数的相等大小的存储桶。
再来看一下这个函数都包含有哪些参数,主要参数的含义与作用都是什么?
和pd.cut()相比,pd.qcut()的参数少了两个,少了right和include_lowest两个参数,剩下的参数几乎和pd.cut()一模一样了。
pd.qcut(x, q, labels=None, retbins=False, precision=3, duplicates='raise')
x :一维数组或者Serise
q : 表示分位数的整数或者数组,
如果是分位数的整数,例如10用于十分位,4用于四分位
如果是分位数数组,例如[0,0.25,0.5,0.75,1]用于四分位数
labels : 数组或者布尔值,默认为none,用于指定每个箱体的标签
如果是数组,长度要与分箱个数一致,比如用四分位数分箱,需要指定四个标签
如果为False,则仅返回分箱的整数指示符,即当前数据位于哪个箱子中
rebines :布尔值,可选。 是否显示分箱的分界值。(由于是按照分位数进行分箱,在不知道分位数具体数值的情况下,可以通过这个参数设置显示分界值即分位数的具体数值)
precision:整数,默认3,存储和显示分箱标签的精度。
duplicates:如果分箱临界值不唯一,则引发ValueError或丢弃非唯一
pd.qcut()的参数就是这些了,并不是所有的参数都常用,下边我们通过代码示例来看一下常用参数的应用。
pd.qcut()代码示例
先看数据源
df_f = pd.read_excel(r"D:\data\football\球队排名比分2019.xlsx")
df_f
参数q
参数q控制箱子的个数以及分界值,我们先来探索这个参数:
pd.qcut(df_f.积分,4,labels=["低","中","高","很高"])
q=4表示分成四个箱子,边界值分别为四分位数,四分之二分位数和四分之三分位数,并给每个箱子都指定了标签,看下结果:
0 很高
1 很高
2 很高
3 很高
4 很高
5 高
6 高
7 高
8 高
9 中
10 中
11 中
12 中
13 中
14 中
15 低
16 低
17 低
18 低
19 低
Name: 积分, dtype: category
Categories (4, object): [低 < 中 < 高 < 很高]
再通过将q设置成数组看下分类结果是否一致:
pd.qcut(df_f.积分,[0,0.25,0.5,0.75,1],labels=["低","中","高","很高"])
直接设置成四分位数,四分之二分位数和四分之三分位数,看下结果:
0 很高
1 很高
2 很高
3 很高
4 很高
5 高
6 高
7 高
8 高
9 中
10 中
11 中
12 中
13 中
14 中
15 低
16 低
17 低
18 低
19 低
Name: 积分, dtype: category
Categories (4, object): [低 < 中 < 高 < 很高]
结果是完全一致的。
温馨提示:不管是pd.cut()还是pd.qcut(),如果直接指定分箱的分界值,即bines和q的取值如果是数字,一定要把每一个箱体的上分界值和下分界值都写上,即每个箱体都是有上下限的,如果分四个箱子参数数组中比如有5个数值才可以。
参数lsbels
探索完q参数我们来看下labels参数,这个参数在介绍pd.cut()时没有具体探讨,其实在两个函数中,labels的作用是一致的,我们在此研究一下,上边例子中labels都指定了标签名字,如果不指定,会有怎样的结果呢?
pd.qcut(df_f.积分,4)
结果如下:
0 (32.5, 61.0]
1 (32.5, 61.0]
2 (32.5, 61.0]
3 (32.5, 61.0]
4 (32.5, 61.0]
5 (28.0, 32.5]
6 (28.0, 32.5]
7 (28.0, 32.5]
8 (28.0, 32.5]
9 (23.5, 28.0]
10 (23.5, 28.0]
11 (23.5, 28.0]
12 (23.5, 28.0]
13 (23.5, 28.0]
14 (23.5, 28.0]
15 (13.999, 23.5]
16 (13.999, 23.5]
17 (13.999, 23.5]
18 (13.999, 23.5]
19 (13.999, 23.5]
Name: 积分, dtype: category
Categories (4, interval[float64]): [(13.999, 23.5] < (23.5, 28.0] < (28.0, 32.5] < (32.5, 61.0]]
如果不指定labels,也就是说每个箱体都没有名字,那么只好把箱体展现出来,即显示每个箱体的两个临界值,至于要不要设置labels,视情况需求而定哦!
参数rebines
这个参数的作用是显示箱体的分界值:
pd.qcut(df_f.积分,4,labels=["低","中","高","很高"],retbins=True)
查看结果,和上边没有设置这个参数的结果做一下对比就可以发现该参数的作用了:
(0 很高
1 很高
2 很高
3 很高
4 很高
5 高
6 高
7 高
8 高
9 中
10 中
11 中
12 中
13 中
14 中
15 低
16 低
17 低
18 低
19 低
Name: 积分, dtype: category
Categories (4, object): [低 < 中 < 高 < 很高],
array([14\. , 23.5, 28\. , 32.5, 61\. ]))
最后位置多了一个数组,数组内就是每个箱体的分界值了。
文章开头提到pd.qcut()比pd.cut()少两个参数,少的参数是控制分界值被分到哪个箱子的,按分位数分箱不能控制分界值被分到哪里,显示分界值后能够发现,每个箱体的数值是包含上分界值的。
再看一眼原数据:
其中28是一个第二个箱体的上限,即标签为“中”的箱体,而在分箱的时候,数值为28的球队都被分到了标签为“中”的箱体中,这个小细节可能很容易被忽视掉,这里做一下小提醒。
转载自:https://zhuanlan.zhihu.com/p/144234097