pandas 数据类型研究(三)数据类型object与category
数据类型object与category比较
category数据类型
官方文档是这样描述的:
Categoricals 是 pandas 的一种数据类型,对应着被统计的变量。
1.Categoricals 是由固定的且有限数量的变量组成的。比如:性别、社会阶层、血型、国籍、观察时段、赞美程度等等。
2.与其它被统计的变量相比,categorical 类型的数据可以具有特定的顺序——比如:按程度来设定,“强烈同意”与“同意”,“首次观察”与“二次观察”,但是不能做按数值来进行排序操作
(比如:sort_by 之类的,换句话说,categorical 的顺序是创建时手工设定的,是静态的)
3.类型数据的每一个元素的值要么是预设好的类型中的某一个,要么是空值(np.nan)。
创建 Categorical 数据
转化创建[object=>category]
用一段代码从不同角度来展现一下 categorical 类型的数据。
# 用一组数据记录各自的得分情况 import pandas as pd, numpy as np players=['Garsol','Hardon','Bill'] scores=[22,34,12,] teams=['West','West','East'] df=pd.DataFrame({'player':players,'score':scores,'team':teams}) print("df.player.dtype:",df.player.dtype) df
把team字段转为category数据类型
df["team"].astype('category')
colors = pd.DataFrame(['Garsol','Hardon','Bill'],columns=['name']) pd.factorize(colors['name'])
这个返回值是个tuple,内有两个元素。
动态添加category数据类型
d=pd.Series(scores).describe() score_ranges=[d['min']-1,d['mean'],d['max']+1] score_labels=['Role','Star'] # 用pd.cut(ori_data, bins, labels) 方法 # 以 bins 设定的画界点来将 ori_data 归类,然后用 labels 中对应的 label 来作为分类名 df['level']=pd.cut(df['score'],score_ranges,labels=score_labels) df
df['team']
df['level']
直接创建 category类型数据
roles=pd.Categorical(['Role','xxx','Star'],categories=['Role', 'Star'])
roles
构造方法中第二个参数是指定了实例中可以包含的元素,在第一个参数中的元素如果不在 categories 中,就会被转成NaN。
df=pd.DataFrame({'players':['Garsol','Hardon','Bill']}) df['level']=roles df['level']
内存占用分析
import pandas as pd colors = pd.Series(['periwinkle','mint green','burnt orange','periwinkle','burnt orange','rose','rose','mint green','rose','navy']) print('colors type:',colors.dtype,'===>','memory_usage():',colors.memory_usage(index=False, deep=True)) colors=colors.astype('category') print('colors type:',colors.dtype,'===>','memory_usage():',colors.memory_usage(index=False, deep=True)) colors=colors.astype('category').cat.codes print('colors type:',colors.dtype,'===>','memory_usage():',colors.memory_usage(index=False, deep=True))
import matplotlib.pyplot as plt plt.rcParams['font.sans-serif']=['Microsoft YaHei'] colors = pd.Series(['periwinkle','mint green','burnt orange','periwinkle','burnt orange','rose','rose','mint green','rose','navy']) x=range(20) y1=[] y2=[] y3=[] for i in x: colorss=colors.repeat(i) y1.append(colorss.memory_usage(index=False, deep=True)) colorss=colorss.astype('category') y2.append(colorss.memory_usage(index=False, deep=True)) colorss=colorss.cat.codes y3.append(colorss.memory_usage(index=False, deep=True)) plt.plot(x,y1,label='object') plt.plot(x,y2,label='category') plt.plot(x,y3,label='int') # x轴标签 plt.xlabel('数据量') # y轴标签 plt.ylabel('内存占用') # 可视化图标题 plt.title('object-category-int数据类型研究') # 显示图例 plt.legend() # 显示图形 plt.show() print('y1',y1) print('y2',y2) print('y3',y3)
内存占用区别:
1.object所占用的内存则是一个常数乘以数据的长度。这个斜率为很大。
2.int类型基本一个常数乘以数据的长度。这个初始值为0且为10(这里int16)
3.初始值80增速也很慢最终增速为同(2)
其实我们能猜测到category存储的方式,数据用int存储然后再维持一个从int到category的映射。
所以Category内存是成比例的,如果数据集的数据量很大,但不重复分类(unique)值很少的情况下,那么Category的内存占用可以大大的节约内存。
计算效率分析
除了占用内存节省外,另一个额外的好处是计算效率有了很大的提升。
因为对于Category类型的Series,str字符的操作发生在.cat.categories的非重复值上,而并非原Series上的所有元素上。
也就是说对于每个非重复值都只做一次操作,然后再向与非重复值同类的值映射过去。
对于Category的数据类型,可以使用accessor的cat对象,以及相应的属性和方法来操作Category数据。
colors = pd.Series(['periwinkle','mint green','burnt orange','periwinkle','burnt orange','rose','rose','mint green','rose','navy']) colorss=colors.repeat(10001) colorss.astype('category').cat.categories
实际上,对于开始的整数类型映射,我们可以先通过reorder_categories进行重新排序,然后再使用cat.codes来实现对整数的映射,来达到同样的效果。
mapper={'Garsol':0,'Hardon':1,'Bill':2} names= pd.DataFrame(['Garsol','Hardon','Bill'],columns=['name']) colors
names['alias']=names.name.astype('category').cat.codes names
names['alias']=names.astype('category').name.cat.reorder_categories(mapper).cat.codes names
names.astype('category').name.cat返回的是 pandas.core.arrays.categorical.CategoricalAccessor数据类型
[i for i in dir(colors.astype('category').name.cat) if not i.startswith('_')] 输出如下: ['add_categories', 'as_ordered', 'as_unordered', 'categorical', 'categories', 'codes', 'index', 'name', 'ordered', 'remove_categories', 'remove_unused_categories', 'rename_categories', 'reorder_categories', 'set_categories']
完结!!!