在机器学习中,经常会对数据进行分箱处理操作,即将一段连续的值切分为若干段,每一段的值当成一个分类。

这个将连续值转换成离散值的过程,就是分箱处理。

例如:把年龄划分为18岁以下、18-30岁、30-45岁、45-60岁、60岁以上等5个标签(类别)。

Pandas 包中的 cutqcut 都可以实现分箱操作,区别在于:

  • cut:按照数值进行分割,等间隔
  • qcut:按照数据分布进行分割,等频率

一、pd.cut函数

1.使用语法

pandas.cut(x,   # 被切分的数组
          bins, # 被切割后的区间(桶、箱)
          right=True, # 是否包含区间右部 默认为真
          labels=None, # 区间标签 与区间个数一致
          retbins=False, # 是否返回分割后的bins
          precision=3, # 小数点位
          include_lowest=False, # 左开区间
          duplicates='raise') # 是否允许重复区间
                   # raise:不允许  drop:允许

2.实操

  • 构造测试集
import pandas as pd
import numpy as np

ages = np.array([1,5,10,40,36,12,58,62,77,89,100,18,20,25,30,32])
  • 平分为5个区间
# 平分为5个区间
pd.cut(ages, 5)
'''
[(0.901, 20.8], (0.901, 20.8], (0.901, 20.8], (20.8, 40.6], (20.8, 40.6], ..., (0.901, 20.8], (0.901, 20.8], (20.8, 40.6], (20.8, 40.6], (20.8, 40.6]]
Length: 16
Categories (5, interval[float64]): [(0.901, 20.8] < (20.8, 40.6] < (40.6, 60.4] < (60.4, 80.2] <
                                    (80.2, 100.0]]
'''

pd.cut(ages, 5).value_counts()
'''
(0.901, 20.8]    6
(20.8, 40.6]     5
(40.6, 60.4]     1
(60.4, 80.2]     2
(80.2, 100.0]    2
dtype: int64
'''

区间两边均有扩展,以包含最大值和最小值。

  • 平分并指定labels
pd.cut(ages, 5, labels=['婴儿', '青年', '中年', '壮年', '老年'])
'''
['婴儿', '婴儿', '婴儿', '青年', '青年', ..., '婴儿', '婴儿', '青年', '青年', '青年']
Length: 16
Categories (5, object): ['婴儿' < '青年' < '中年' < '壮年' < '老年']
'''
  • 指定区间进行分割
pd.cut(ages, 
       bins=[0,5,20,30,50,100],
       labels=['婴儿', '青年', '中年', '壮年', '老年'])
'''
['婴儿', '婴儿', '青年', '壮年', '壮年', ..., '青年', '青年', '中年', '中年', '壮年']
Length: 16
Categories (5, object): ['婴儿' < '青年' < '中年' < '壮年' < '老年']
'''
  • 返回分割后的bins(设置 retbins=True 即可)
pd.cut(ages, 
       bins=[0,5,20,30,50,100],
       labels=['婴儿', '青年', '中年', '壮年', '老年'],
       retbins=True)
'''
(['婴儿', '婴儿', '青年', '壮年', '壮年', ..., '青年', '青年', '中年', '中年', '壮年']
 Length: 16
 Categories (5, object): ['婴儿' < '青年' < '中年' < '壮年' < '老年'],
 array([  0,   5,  20,  30,  50, 100]))
'''
  • 只返回数据所属的bins(设置 labels=False 即可)
pd.cut(ages,
       bins=[0,5,20,30,50,100],
       labels=False)
# array([0, 0, 1, 3, 3, 1, 4, 4, 4, 4, 4, 1, 1, 2, 2, 3], dtype=int64)

默认情况下,每个区间包括最大值,不包括最小值。

最左边的值, 一般设置成最小值减去最大值的 0.1%。

二、pd.qcut函数

1.使用语法

pd.qcut 实现按数据的数量进行分割,尽量保证每个分组里变量的个数相同。

pd.qcut(
    x, # 数组
    q, # 组数 int
    labels=None, # 标签
    retbins: bool = False, # 是否返回边界值
    precision: int = 3, # 精度
    duplicates: str = "raise",
)

2.实操

  • 简单按个数分箱
import numpy as np
import pandas as pd

factors = np.random.randn(9)
pd.qcut(factors, 3)
'''
[(-0.272, 0.33], (0.33, 1.116], (0.33, 1.116], (0.33, 1.116], (-0.272, 0.33], (-1.101, -0.272], (-1.101, -0.272], (-0.272, 0.33], (-1.101, -0.272]]
Categories (3, interval[float64]): [(-1.101, -0.272] < (-0.272, 0.33] < (0.33, 1.116]]
'''
pd.qcut(factors, 3).value_counts() # 均分
'''
(-1.101, -0.272]    3
(-0.272, 0.33]      3
(0.33, 1.116]       3
dtype: int64
'''

  • 添加labels标签
pd.qcut(factors,
        3,
        labels=['a','b','c'])
'''
['b', 'c', 'c', 'c', 'b', 'a', 'a', 'b', 'a']
Categories (3, object): ['a' < 'b' < 'c']
'''
# 返回对应的分组下标
pd.qcut(factors, 3, labels=False)
# array([1, 2, 2, 2, 1, 0, 0, 1, 0], dtype=int64)

  • 返回bins值
pd.qcut(factors, 3, retbins=True)
'''
([(-0.272, 0.33], (0.33, 1.116], (0.33, 1.116], (0.33, 1.116], (-0.272, 0.33], (-1.101, -0.272], (-1.101, -0.272], (-0.272, 0.33], (-1.101, -0.272]]
 Categories (3, interval[float64]): [(-1.101, -0.272] < (-0.272, 0.33] < (0.33, 1.116]],
 array([-1.09994407, -0.27157169,  0.32984035,  1.11614022]))
'''

三、综合用法

1.一个栗子

import pandas as pd
import numpy as np

df = pd.DataFrame([x**2 for x in range(11)],
                  columns=['number'])

# 按照数值由小到大 将数据分成4份
df['cut_group'] = pd.cut(df['number'], 4)


# 分成四组 并且让每组变量的数量相同
df['qcut_group'] = pd.qcut(df['number'], 4)
df['qcut_group'].value_counts()
'''
(-0.001, 6.5]    3
(6.5, 25.0]      3
(56.5, 100.0]    3
(25.0, 56.5]     2
'''

3.日常工作使用

cz_fee_cut = [min(df_copy.cz_fee)-10, 30, 50, 100, 150, 200, max(df_copy.cz_fee)+10]
df_copy["cz_fee"] = pd.cut(df_copy['cz_fee'], 
                           bins=cz_fee_cut, 
                           right=False,
                           labels=['<30','[30,50)','[50,100)','[100,150)','[150,200)','≥200'])

参考链接:pandas.cut

参考链接:pandas.cut使用总结

参考链接:Pandas —— qcut( )与cut( )的区别

参考链接:pandas的cut,qcut函数的使用和区别