在机器学习中,经常会对数据进行分箱处理操作,即将一段连续的值切分为若干段,每一段的值当成一个分类。
这个将连续值转换成离散值的过程,就是分箱处理。
例如:把年龄划分为18岁以下、18-30岁、30-45岁、45-60岁、60岁以上等5个标签(类别)。
Pandas
包中的 cut
和 qcut
都可以实现分箱操作,区别在于:
- 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使用总结