pandas 数据类型研究(三)数据类型object与category

数据类型object与category比较

category数据类型

官方文档是这样描述的:

Categoricals 是 pandas 的一种数据类型,对应着被统计的变量。

  1.Categoricals 是由固定的且有限数量的变量组成的。比如:性别、社会阶层、血型、国籍、观察时段、赞美程度等等。

  2.与其它被统计的变量相比,categorical 类型的数据可以具有特定的顺序——比如:按程度来设定,“强烈同意”与“同意”,“首次观察”与“二次观察”,但是不能做按数值来进行排序操作

                                          (比如:sort_by 之类的,换句话说,categorical 的顺序是创建时手工设定的,是静态的)

  3.类型数据的每一个元素的值要么是预设好的类型中的某一个,要么是空值(np.nan)。

  4.categorical 实例的内部是由类型名字集合和一个整数组成的数组构成的,后者标明了类型集合真正的值。顺序是由预设好的类型集合来决定的,而不是按照类型集合中各个元素的字母顺序排序的。

创建 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')

df.team 的变量类型变成了 category
 相似用法factorize
colors = pd.DataFrame(['Garsol','Hardon','Bill'],columns=['name'])
pd.factorize(colors['name'])

这个返回值是个tuple,内有两个元素。

 

 

 

 

动态添加category数据类型

如按照得分来划分,将高于平均分的划为 Star,低于平均分的划为 Role。计算过程就应该是这样:
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)
object-category-int数据类型研究

 

 内存占用区别:

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']

 完结!!!

 

 

posted @ 2020-04-27 13:47  wqbin  阅读(3085)  评论(0编辑  收藏  举报