简介
有时候便于分析数据,我们需要将连续型的数据划分开,也就是离散化。比如:统计人员的年龄分布,需要划分几个档次等,然后就可以做柱状图或者直方图。可以通过pandas的cut()
和qcut()
函数实现,接下来一一介绍。
cut()函数
该函数的使用方法如下:
1 2 3 4 5 6 7 8 |
>>>ages = [6, 12, 17, 18, 22, 25, 31, 35, 44, 55, 66, 71] # 划分年龄段 >>>bin = [0, 18, 30, 50, 100] >>>a = pd.cut(ages, bin) >>>a [(0, 18], (0, 18], (0, 18], (0, 18], (18, 30], ..., (30, 50], (30, 50], (50, 100], (50, 100], (50, 100]] Length: 12 Categories (4, interval[int64]): [(0, 18] < (18, 30] < (30, 50] < (50, 100]] |
在上面的例子中,我们有一些人的年龄,需要将他们划分到各自的年龄段bin
当中。在这里有四个年龄段(0, 18] ,(18, 30] ,(30, 50] ,(50, 100]
,返回的结果是一个属于各个区间的Categorical对象。使用categories
属性可以获的区间形式:
1 2 3 4 |
>>>a.categories IntervalIndex([(0, 18], (18, 30], (30, 50], (50, 100]] closed='right', dtype='interval[int64]') |
需要注意的一点,默认的区间是左开右闭的,可以通过right=False
修改:
1 2 3 4 5 |
>>>b = pd.cut(ages, bin, right=False) >>>b [[0, 18), [0, 18), [0, 18), [18, 30), [18, 30), ..., [30, 50), [30, 50), [50, 100), [50, 100), [50, 100)] Length: 12 Categories (4, interval[int64]): [[0, 18) < [18, 30) < [30, 50) < [50, 100)] |
我们还可以设置区间的名称,使用labels
参数指定一个名称列表:
1 2 3 4 5 |
>>>c = pd.cut(ages, bin, labels=['child', 'young', 'middle', 'old']) >>>c [child, child, child, child, young, ..., middle, middle, old, old, old] Length: 12 Categories (4, object): [child < young < middle < old] |
labels
参数如果设置成False
,就会返回一个表示区间的整数索引:
1 2 3 |
>>>d = pd.cut(ages, bin, labels=False) >>>d array([0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3], dtype=int64) |
整数索引0
表示[0, 18)
,以此类推。
我们也可以不用传入划分的区间形式,可以直接指定数量:
1 2 3 4 5 6 |
>>>e = pd.cut(ages, 4, retbins=True) >>>e ([(5.935, 22.25], (5.935, 22.25], (5.935, 22.25], (5.935, 22.25], (5.935, 22.25], ..., (22.25, 38.5], (38.5, 54.75], (54.75, 71.0], (54.75, 71.0], (54.75, 71.0]] Length: 12 Categories (4, interval[float64]): [(5.935, 22.25] < (22.25, 38.5] < (38.5, 54.75] < (54.75, 71.0]], array([ 5.935, 22.25 , 38.5 , 54.75 , 71. ])) |
在这里,我们指定划分4个区间,程序会自动计算总长度然后平均。通过retbins=True
能够获得划分的数组。
qcut()函数
该函数跟cut()
类似,只是它是根据样本的分位数对数据划分,也就是说保证在每个区间中含有的数量相同。比如:
1 2 3 4 5 |
>>>f = pd.qcut(ages, 4) >>>f ([(5.999, 17.75], (5.999, 17.75], (5.999, 17.75], (17.75, 28.0], (17.75, 28.0], ..., (28.0, 46.75], (28.0, 46.75], (46.75, 71.0], (46.75, 71.0], (46.75, 71.0]] Length: 12 Categories (4, interval[float64]): [(5.999, 17.75] < (17.75, 28.0] < (28.0, 46.75] < (46.75, 71.0]] |
可以看出,该函数根据数据长度,自动划分了4个区域,每个区域的数据数量是相同的:
1 2 3 4 5 6 |
>>>pd.value_counts(f) (46.75, 71.0] 3 (28.0, 46.75] 3 (17.75, 28.0] 3 (5.999, 17.75] 3 dtype: int64 |
我们也可以指定样本分位数:
1 2 3 4 5 6 7 8 9 10 11 12 |
>>>g = pd.qcut(ages, [0, 0.2, 0.5, 0.8, 1]) >>>g [(5.999, 17.2], (5.999, 17.2], (5.999, 17.2], (17.2, 28.0], (17.2, 28.0], ..., (28.0, 52.8], (28.0, 52.8], (52.8, 71.0], (52.8, 71.0], (52.8, 71.0]] Length: 12 Categories (4, interval[float64]): [(5.999, 17.2] < (17.2, 28.0] < (28.0, 52.8] < (52.8, 71.0]] >>>pd.value_counts(g) (52.8, 71.0] 3 (28.0, 52.8] 3 (17.2, 28.0] 3 (5.999, 17.2] 3 dtype: int64 |
总结
本文讲了两个将连续数据离散化的函数cut()
和qcut()
,前者根据样本间距划分,样本数量可以不同;后者根据样本分位数划分,每个间距的样本数一样多。在后面的聚合和分组运算中,我们还会讲到这两个函数的应用。