第九章 分类数据

第九章 分类数据

学习参考:http://datawhale.club/t/topic/579

Ex1:统计未出现的类别

在第五章中介绍了crosstab函数,在默认参数下它能够对两个列的组合出现的频数进行统计汇总:

df = pd.DataFrame({'A':['a','b','c','a'], 'B':['cat','cat','dog','cat']})
pd.crosstab(df.A, df.B)

在这里插入图片描述
但事实上有些列存储的是分类变量,列中并不一定包含所有的类别,此时如果想要对这些未出现的类别在crosstab结果中也进行汇总,则可以指定dropna参数为False

df.B = df.B.astype('category').cat.add_categories('sheep')
pd.crosstab(df.A, df.B, dropna=False)

在这里插入图片描述
请实现一个带有dropna参数的my_crosstab函数来完成上面的功能。

def my_crosstab(s1,s2,dropna = True):
    idx1 = (s1.cat.categories if s1.dtype.name == "category" and not dropna  # 构建分类索引
               else s1.unique())
    idx2 = (s2.cat.categories if s2.dtype.name == "category" and not dropna
               else s2.unique())
    res = pd.DataFrame(np.zeros((idx1.shape[0],idx2.shape[0])),index = idx1,columns = idx2)
    for i, j in zip(s1, s2):
        res.at[i,j] += 1  # 对组合元素类型进行计数
    res = res.rename_axis(index = s1.name,columns = s2.name).astype("int")  # 对res数据框的索引和列命名
    return res

df = pd.DataFrame({'A':['a','b','c','a'], 'B':['cat','cat','dog','cat']})
df.B = df.B.astype('category').cat.add_categories('sheep')
my_crosstab(df.A,df.B)

在这里插入图片描述

my_crosstab(df.A,df.B,dropna = False)

在这里插入图片描述

Ex2:钻石数据集

现有一份关于钻石的数据集,其中carat, cut, clarity, price分别表示克拉重量、切割质量、纯净度和价格,样例如下:

df = pd.read_csv('../data/diamonds.csv') 
df.head(3)

在这里插入图片描述

  1. 分别对df.cutobject类型和category类型下使用nunique函数,并比较它们的性能。
  2. 钻石的切割质量可以分为五个等级,由次到好分别是Fair, Good, Very Good, Premium, Ideal,纯净度有八个等级,由次到好分别是I1, SI2, SI1, VS2, VS1, VVS2, VVS1, IF,请对切割质量按照由好到次的顺序排序,相同切割质量的钻石,按照纯净度进行由次到好的排序。
  3. 分别采用两种不同的方法,把cut, clarity这两列按照由好到次的顺序,映射到从0到n-1的整数,其中n表示类别的个数。
  4. 对每克拉的价格分别按照分位数(q=[0.2, 0.4, 0.6, 0.8])与[1000, 3500, 5500, 18000]割点进行分箱得到五个类别Very Low, Low, Mid, High, Very High,并把按这两种分箱方法得到的category序列依次添加到原表中。
  5. 第4问中按照整数分箱得到的序列中,是否出现了所有的类别?如果存在没有出现的类别请把该类别删除。
  6. 对第4问中按照分位数分箱得到的序列,求每个样本对应所在区间的左右端点值和长度。
#1.分别对df.cut在object类型和category类型下使用nunique函数,并比较它们的性能
%timeit -n 30 df.cut.nunique()

在这里插入图片描述

%timeit -n 30 df.cut.astype('category').nunique()

在这里插入图片描述

s_obj, s_cat = df.cut, df.cut.astype('category')
%timeit -n 30 s_obj.nunique()

在这里插入图片描述

%timeit -n 30 s_cat.nunique()

在这里插入图片描述
总体上,直接将列转换为在object类型并进行nunique计算,时间消耗比转换为category类型的少。答案把赋值和nunique计算拆分开来,得到的结论相反。

#2.对切割质量按照由好到次的顺序排序,相同切割质量的钻石,按照纯净度进行由次到好的排序。
df.cut = df.cut.astype('category').cat.reorder_categories(['Fair', 'Good', 'Very Good', 'Premium', 'Ideal'],ordered=True)
df.clarity = df.clarity.astype('category').cat.reorder_categories(['I1', 'SI2', 'SI1', 'VS2', 'VS1', 'VVS2', 'VVS1', 'IF'],ordered=True)
res = df.sort_values(['cut', 'clarity'], ascending=[False, True])
res.head()

在这里插入图片描述

#3.分别采用两种不同的方法,把cut, clarity这两列按照由好到次的顺序,映射到从0到n-1的整数,其中n表示类别的个数。
df.cut = df.cut.cat.reorder_categories(df.cut.cat.categories[::-1])  # 分类索引由好到次排序
df.clarity = df.clarity.cat.reorder_categories(df.clarity.cat.categories[::-1])
df.cut = df.cut.cat.codes  # 方法一:利用codes属性
clarity_cat = df.clarity.cat.categories
dict(zip(clarity_cat, np.arange(len(clarity_cat))))  

在这里插入图片描述

df.clarity = df.clarity.replace(dict(zip(clarity_cat, np.arange(len(clarity_cat)))))  # 方法二:使用replace映射
df.head()

在这里插入图片描述

#4.对每克拉的价格分别按照分位数(q=[0.2, 0.4, 0.6, 0.8])与[1000, 3500, 5500, 18000]割点进行分箱得到五个类别Very Low, Low, Mid, High, Very High,并把按这两种分箱方法得到的category序列依次添加到原表中。
average_price = df['price']/df['carat']
price_num_level = pd.cut(average_price, bins=[-np.infty, 1000, 3500, 5500, 18000, np.infty],labels = ['Very Low', 'Low', 'Mid', 'High', 'Very High'])
price_quantile_level = pd.qcut(average_price,q = [0,0.2,0.4,0.6,0.8,1],labels = ['Very Low', 'Low', 'Mid', 'High', 'Very High'])
df['price_num_level'] = price_num_level
df['price_quantile_level'] = price_quantile_level
df.head()

在这里插入图片描述

#5.第4问中按照整数分箱得到的序列中,是否出现了所有的类别?如果存在没有出现的类别请把该类别删除
df['price_num_level'].unique()  # 结果只出现了Low, Mid, High三个类别

在这里插入图片描述

df['price_num_level'] = df['price_num_level'].cat.remove_unused_categories()
df['price_num_level'].cat.categories

在这里插入图片描述

#6.对第4问中按照分位数分箱得到的序列,求每个样本对应所在区间的左右端点值和长度
interval_avg = pd.IntervalIndex(pd.qcut(average_price,q = [0,0.2,0.4,0.6,0.8,1]))
interval_avg[:3]

在这里插入图片描述

interval_avg.right.to_series().reset_index(drop=True).head(3)

在这里插入图片描述

interval_avg.left.to_series().reset_index(drop=True).head(3)

在这里插入图片描述

interval_avg.length.to_series().reset_index(drop=True).head(3)

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值