将一组数据按指定的大小来划分成离散的区间类别,可以通过用pandas.cut轻松实现,如将连续型的年龄数值划分成婴儿、青年等不同年龄段的区间。Categoricals 是 pandas 的一种数据类型,通常是由固定的且有限数量(即可以看成类别数据)的值组成的。比如:人年龄段、性别、社会阶层、血型、国籍、观察时段、赞美程度等都可以转换成。本文介绍pandas.cut 的用法和补充categoricals数据类型的含义。
pandas.cut语法
pandas.cut(x, bins, right=True, labels=None, retbins=False, precision=3, include_lowest=False, duplicates='raise')
解析:
x
:传入的数据,即被切分的类数组(array-like)数据,注意必须是1维的(不能用DataFrame);bins
:被切割后的区间(或者叫“桶”、“箱”、“面元”),有3中形式:一个int型的标量、标量序列(数组)或者pandas.IntervalIndex 。
- 一个int型的标量(等频划分)
当bins为一个int型的标量时,代表将x平分成bins份。x的范围在每侧扩展0.1%,以包括x的最大值和最小值。 - 标量序列(自定义区间大小)
标量序列定义了被分割后每一个bin的区间边缘,此时x没有扩展。此即自己指定划分区间的边界值。 - pandas.IntervalIndex
定义要使用的精确区间。
right
:bool型参数,默认为True,表示是否包含区间右部。比如如果bins=[1,2,3],right=True,则区间为(1,2],(2,3];right=False,则区间为(1,2),(2,3)。labels
:给分割后的bins打标签,比如把年龄x分割成年龄段bins后,可以给年龄段打上诸如青年、中年的标签。labels的长度必须和划分后的区间长度相等,比如bins=[1,2,3],划分后有2个区间(1,2],(2,3],则labels的长度必须为2。如果指定labels=False,则返回x中的数据在第几个bin中(从0开始)。retbins
:bool型的参数,表示是否将分割后的bins返回,当bins为一个int型的标量时比较有用,这样可以得到划分后的区间,默认为False。precision
:保留区间小数点的位数,默认为3.include_lowest
:bool型的参数,表示区间的左边是开还是闭的,默认为false,也就是不包含区间左部(闭)。duplicates
:是否允许重复区间。有两种选择:raise
:不允许,drop
:允许。
返回
out
:一个pandas.Categorical, Series或者ndarray类型的值,代表分区后x中的每个值在哪个bin(区间)中,如果指定了labels,则返回对应的label。bins
:分隔后的区间,当指定retbins为True时返回。
pandas.cut 案例
等频划分,只指定了bins的区间个数
import numpy as np
import pandas as pd
ages = np.array([1,5,10,40,36,12,58,62,77,89,100,18,20,25,30,32]) #年龄数据
agesCut=pd.cut(ages, 5) # 此处的指定了划分的bins桶的个数,并未指定具体区间段大小,则当bins为一个int型的标量(如此的5)时,代表将x等频平分成bins份。x的范围在每侧扩展0.1%,以包括x的最大值和最小值。
print("agesCut:{}".format(agesCut)) # 将各个值划分到了对应的区间里面去了,以区间的值来表示了。
输出
# agesCut:[(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, object): [(0.901, 20.8] < (20.8, 40.6] < (40.6, 60.4] < (60.4, 80.2] < (80.2, 100]]
划分成区间并指定label
# 划分成区间并指定label
ages = np.array([1,5,10,40,36,12,58,62,77,89,100,18,20,25,30,32]) #年龄数据
agesCutLabel=pd.cut(ages, 5, labels=[u"婴儿",u"青年",u"中年",u"壮年",u"老年"]) # 此按默认的等频平分的区间
print("agesCutLabel:{}".format(agesCutLabel))
输出:agesCutLabel:[婴儿, 婴儿, 婴儿, 青年, 青年, ..., 婴儿, 婴儿, 青年, 青年, 青年] Length: 16 Categories (5, object): [婴儿 < 青年 < 中年 < 壮年 < 老年] 。由于婴儿对应的lable区间为[(0.901, 20.8],所以前三个数1,5,10对应的label均为婴儿,即返回的结果中前三个值都为婴儿。
自定义划分区间的间隔进行分割
注意自己定义的区间边界值两端的值最左边的要小于等于待划分的数x的最小值,如下面的bins区间第一个值0就小于x中最小的值1,否则比bins区间序列中最左边值小的会被分为NaN。同理最右边的值要大于等于x中的最大值,否则比bins序列中最右边值大的会被分为NaN.
bins 序列里的个数注意要比labels 序列里的值个数多一。
# 自定义划分区间的间隔进行分割
ages = np.array([1,5,10,40,36,12,58,62,77,89,100,18,20,25,30,32]) #年龄数据
agesCutLabelSelf=pd.cut(ages, [0,5,20,30,50,100], labels=[u"婴儿",u"青年",u"中年",u"壮年",u"老年"])
print("agesCutLabelSelf的范围 {}".format(agesCutLabelSelf))
输出:agesCutLabelSelf的范围 [婴儿, 婴儿, 青年, 壮年, 壮年, ..., 青年, 青年, 中年, 中年, 壮年] Length: 16 Categories (5, object): [婴儿 < 青年 < 中年 < 壮年 < 老年]
将分割后的bins 返回,并查看具体的值
# 将分割后的bins 返回
ages = np.array([1,5,10,40,36,12,58,62,77,89,100,18,20,25,30,32]) #年龄数据
retbins=pd.cut(ages, [0,5,20,30,50,100], labels=[u"婴儿",u"青年",u"中年",u"壮年",u"老年"],retbins=True)
print("retbins:{}".format(retbins))
print(type(retbins)) # 返回的retbins是一个tuple ,<type 'tuple'>
print("retbins[0]的值为{}".format(retbins[0]))
print("retbins[1]的值为{}".format(retbins[1]))
print(len(retbins))
retbins:([婴儿, 婴儿, 青年, 壮年, 壮年, ..., 青年, 青年, 中年, 中年, 壮年]
Length: 16
Categories (5, object): [婴儿 < 青年 < 中年 < 壮年 < 老年], array([ 0, 5, 20, 30, 50, 100]))
<type 'tuple'>
retbins[0]的值为[婴儿, 婴儿, 青年, 壮年, 壮年, ..., 青年, 青年, 中年, 中年, 壮年]
Length: 16
Categories (5, object): [婴儿 < 青年 < 中年 < 壮年 < 老年]
retbins[1]的值为[ 0 5 20 30 50 100]
2
只返回分桶的索引
# 只返回x中的数据在哪个bin
# 令labels=False即可.如果指定labels=False,则返回x中的数据在第几个bin中(从0开始)。
ages = np.array([1,5,10,40,36,12,58,62,77,89,100,18,20,25,30,32]) #年龄数据
labelsFalse=pd.cut(ages, [0,5,20,30,50,100], labels=False)
print("labelsFalse:{}".format(labelsFalse))
输出:
labelsFalse:[0 0 1 3 3 1 4 4 4 4 4 1 1 2 2 3]
另一个实例:将列dssm_dot的值划分到-1到1的20个等长间隔的桶内(因此需要20+1个间隔值),得到新的表示对应桶id列的 dssm_dot_bins
# 将数据等长划分到[-1,和1之间,分桶],得到21个桶
bins=np.linspace(-1,1,num=21)
# print(bins)
# 标签 ,-1到1,20个数
labels=np.arange(-1,1,0.1)
# print(labels) # 划分到了-1到1的20个区间,并打上了label ,注意0.04会划分到0这个label(-2.22e-16 很小的数,即0)
part_data['dssm_dot_bins']=pd.cut(part_data['dssm_dot'],bins,labels=labels)
显示创建Categorical数据
cg=pd.Categorical(['Role','Role','Star','Role','Killer','Star'],categories=['Role', 'Star'])
print(cg)
输出:
[Role, Role, Star, Role, NaN, Star]
Categories (2, object): [Role, Star]