Categoricals 是 pandas 的一种数据类型,对应着被统计的变量。Categoricals 是由固定的且有限数量的变量组成的。比如:性别、社会阶层、血型、国籍、观察时段、赞美程度等等。
与其它被统计的变量相比,categorical 类型的数据可以具有特定的顺序——比如:按程度来设定,“强烈同意”与“同意”,“首次观察”与“二次观察”,但是不能做按数值来进行排序操作(比如:sort_by 之类的,换句话说,categorical 的顺序是创建时手工设定的,是静态的)
类型数据的每一个元素的值要么是预设好的类型中的某一个,要么是空值(np.nan)。顺序是由预设好的类型集合来决定的,而不是按照类型集合中各个元素的字母顺序排序的。categorical 实例的内部是由类型名字集合和一个整数组成的数组构成的,后者标明了类型集合真正的值
摘录于 https://blog.csdn.net/mengenqing/article/details/80616094
以下学习资源来自学习资源
本节主要内容:
目录
category的创建及其性质
分类变量的排序
分类变量的比较操作
问题与练习
-
category的创建及其性质
-
分类变量的创建
-
#1、对于Series数据结构,传入参数dtype='category'即可 series_cat=pd.Series(["a", "b", "c", "a"], dtype="category") series_cat 结果 0 a 1 b 2 c 3 a dtype: category Categories (3, object): [a, b, c] ## series_cat的类型为category,但是没有声明顺序,这时若对Series排序,实际上还是按照词法的顺序: series_cat.sort_values() 0 a 3 a 1 b 2 c dtype: category Categories (3, object): [a, b, c] #2、对DataFrame指定类型创建 #2、1直接指定类型 temp_df = pd.DataFrame({'A':pd.Series(["a", "b", "c", "a"], dtype="category"),'B':list('abcd')}) print(temp_df) temp_df.dtypes 结果: A B 0 a a 1 b b 2 c c 3 a d A category B object dtype: object #2、2 也可以在定义数据之后转换类型 #创建数据框 df_cat = pd.DataFrame({ 'V1':['A','C','B','D']}) #转换指定列的数据类型为category df_cat['V1'] = df_cat['V1'].astype('category') df_cat['V1'] # 3、利用内置Categorical类型创建 # pd.Categorical(values, categories=None, ordered=None, dtype=None, fastpath=False) #3、1 利用pd.Categorical()生成类别型数据后转换为Series,或替换DataFrame中的内容 cat = pd.Categorical(["a", "b", "c", "a"], categories=['a','b','c']) pd.Series(cat) 结果: 0 a 1 b 2 c 3 a dtype: category Categories (3, object): [a, b, c] #3、2 替换DataFrame中的内容 categorical_ = pd.Categorical(['A','B','D','C'], categories=['B','C','D']) df_cat = pd.DataFrame({'V1':categorical_}) df_cat['V1'] 结果: 0 NaN 1 B 2 D 3 C Name: V1, dtype: category Categories (3, object): [B, C, D] 总结:而pd.Categorical()独立创建categorical数据时有两个新的特性,一是其通过参数 categories定义类别时,若原数据中出现了categories参数中没有的数据,则会自动转换为pd.nan: #3、3 另外pd.Categorical()还有一个bool型参数ordered,设置为True时则会按照categories中的顺序定义从小到大的范围: categorical_ = pd.Categorical(['A','B','D','C'], categories=['A','B','C','D'], ordered=True) df_cat = pd.DataFrame({'V1':categorical_}) df_cat['V1'] #4、利用pandas.api.types中的CategoricalDtype()对已有数据进行转换 from pandas.api.types import CategoricalDtype #创建数据框 df_cat = pd.DataFrame({'V1':['A','C','B','D']}) cat = CategoricalDtype(categories=['A','C','B'],ordered=True) df_cat['V1'] = df_cat['V1'].astype(cat) df_cat['V1'] 结果 0 A 1 C 2 B 3 NaN Name: V1, dtype: category Categories (3, object): [A < C < B] 通过CategoricalDtype(),我们可以结合astype()完成从其他类型数据向categorical数据的转换 过程,利用CategoricalDtype()的参数categories、ordered,弥补.astype('category')的短板(实际 上.astype('category')等价于.astype(CategoricalDtype(categories=None, ordered=False))): # 5、利用cut函数创建 pd.cut(x, bins, right:bool=True, labels=None, retbins:bool=False, precision:int=3, include_lowest:bool=False, duplicates:str='raise') #5、1 默认使用区间类型为标签 pd.cut(np.random.randint(0,60,5), [0,10,30,60]) out: [(30, 60], (0, 10], (30, 60], (30, 60], (30, 60]] Categories (3, interval[int64]): [(0, 10] < (10, 30] < (30, 60]] #可指定字符为标签 pd.cut(np.random.randint(0,60,5), [0,10,30,60], right=False, labels=['0-10','10- 30','30-60']) 结果: [10-30, 30-60, 30-60, 10-30, 30-60] Categories (3, object): [0-10 < 10-30 < 30-60]
-
-
分类变量的结构
-
一个分类变量包括三个部分,元素值(values)、分类类别(categories)、是否有序(order)
-
从上面可以看出,使用cut函数创建的分类变量默认为有序分类变量
-
获取属性
#1、describe方法 s = pd.Series(pd.Categorical(["a", "b", "c", "a",np.nan], categories=['a','b','c','d'])) s.describe() count 4 unique 3 top a freq 2 dtype: object #2、使用 .cat.categories查看类别名称列表 s= pd.Series([‘a’, ‘b’, ‘c’, ‘c’], dtype=’category’) s.cat.categories 结果: Index([‘a’, ‘b’, ‘c’], dtype=’object’) #3、 使用 .cat.ordered 查看类别是否有序 s = pd.Series( pd.Categorical([‘差’, ‘中’, ‘良’, ‘优’], categories=[‘差’, ‘中’, ‘良’, ‘优’], ordered=True)) s.cat.ordered outcome: True a2 = pd.Series([‘a’, ‘b’, ‘c’, ‘c’], dtype=’category’) a2.cat.ordered outcome:False # 4、读取:cat.categories a1 = pd.Series([‘a’, ‘b’, ‘c’, ‘c’], dtype=’category’) a1.cat.categories outcome: Index([‘a’, ‘b’, ‘c’], dtype=’object’)
-
- 类别的修改
#1、修改属性 a1 = pd.Series([‘a’, ‘b’, ‘c’, ‘c’], dtype=’category’) a1.cat.categories outcome: Index([‘a’, ‘b’, ‘c’], dtype=’object’) a1.cat.categories=[‘类别a’, ‘类别b’, ‘c’] a1 outcome: 0 类别a 1 类别b 2 c 3 c dtype: category Categories (3, object): [类别a, 类别b, c] #2、利用set_categories修改 s = pd.Series(pd.Categorical(["a", "b", "c", "a",np.nan], categories= ['a','b','c','d'])) print(s) s.cat.set_categories(['new_a','c']) outcome: 0 a 1 b 2 c 3 a 4 NaN dtype: category Categories (4, object): [a, b, c, d] 0 NaN 1 NaN 2 c 3 NaN 4 NaN dtype: category Categories (2, object): [new_a, c] #3、利用rename_categories修改, 需要注意的是该方法会把值和分类同时修改 s = pd.Series(pd.Categorical(["a", "b", "c", "a",np.nan], categories= ['a','b','c','d'])) print(s) s.cat.rename_categories(['new_%s'%i for i in s.cat.categories]) outcome; 0 a 1 b 2 c 3 a 4 NaN dtype: category Categories (4, object): [a, b, c, d] 0 new_a 1 new_b 2 new_c 3 new_a 4 NaN dtype: category Categories (4, object): [new_a, new_b, new_c, new_d] 5、利用字典修改,也会把值和类型都改变 s.cat.rename_categories({'a':'new_a','b':'new_b'}) outcome 0 new_a 1 new_b 2 c 3 new_a 4 NaN dtype: category Categories (4, object): [new_a, new_b, c, d] # 6、利用add_categories添加 s = pd.Series(pd.Categorical(["a", "b", "c", "a",np.nan], categories=['a','b','c','d'])) s.cat.add_categories(['e']) outcome: 0 a 1 b 2 c 3 a 4 NaN dtype: category Categories (5, object): [a, b, c, d, e] # 7、利用remove_categories移除 s = pd.Series(pd.Categorical(["a", "b", "c", "a",np.nan], categories=['a','b','c','d'])) s.cat.remove_categories(['d']) # 8、 删除元素值未出现的分类类型 s = pd.Series(pd.Categorical(["a", "b", "c", "a",np.nan], categories=['a','b','c','d'])) s.cat.remove_unused_categories() outcome; 0 a 1 b 2 c 3 a 4 NaN dtype: category Categories (3, object): [a, b, c]
-
- 分类变量的排序
-
# 无序变为有序 1、.cat.as_ordered方法 s = pd.Series(["a", "d", "c", "a"]).astype('category').cat.as_ordered() s OUTCOME 0 a 1 d 2 c 3 a dtype: category Categories (3, object): [a < c < d] 2、有序变为无序.cat.as_unordered() s.cat.as_unordered() 3、利用.cat.set_categories方法中的order参数 pd.Series(["a", "d", "c", "a"]).astype('category') .cat.set_categories(['a','c','d'],ordered=True) 4。利用.cat.reorder_categories方法,这个方法的特点在于,新设置的分类必须与原分类为同一集合 s = pd.Series(["a", "d", "c", "a"]).astype('category') s.cat.reorder_categories(['a','c','d'],ordered=True) 5、值排序和索引排序都是适用的
-
- 分类变量的比较操作
- 与标量数据或等长序列的比较:
-
两个分类变量的等式判别需要满足分类完全相同
-
- 与另外一个分类变量比较
- 与标量数据或等长序列的比较:
- 问题与练习
1.4.0.1 【问题一】 如何使用union_categoricals方法?它的作用是什么?
1、
from pandas.api.types import union_categoricals
a = pd.Categorical(["b", "c"])
b = pd.Categorical(["a", "b"])
union_categoricals([a, b])
#对分类数据求集合,下面会报错
a = pd.Categorical(["a", "b"], ordered=True)
b = pd.Categorical(["a", "b", "c"], ordered=True)
union_categoricals([a, b])
TypeError :to union ordered Categoricals, all categories must be the same
1.4.0.2 【问题二】 利用concat方法将两个序列纵向拼接,它的结果一定是分类变量吗?什么情况下不是?
1.4.0.3 【问题三】 当使用groupby方法或者value_counts方法时,分类变量的统计结果和普通变量有什么区别?
1.4.0.4 【问题四】 下面的代码说明了Series创建分类变量的什么“缺陷”?如何避免?(提示:使用Series中的copy参数)¶
【练习一】 现继续使用第四章中的地震数据集,请解决以下问题:
1.4.0.6 (a)现在将深度分为七个等级:[0,5,10,15,20,30,50,np.inf],请以深度等级Ⅰ,Ⅱ,Ⅲ,Ⅳ,Ⅴ,Ⅵ,Ⅶ为索引并按照由浅到深的顺序进行排序。
d=pd.read_csv('data/Earthquake.csv').head()
pd.cut(d['深度'], [0,5,10,15,20,30,50,np.inf],labels=['Ⅰ','Ⅱ','Ⅲ','Ⅳ','Ⅴ','Ⅵ','Ⅶ'])
d.set_index('深度').sort_index().head()
1.4.0.7 (b)在(a)的基础上,将烈度分为4个等级:[0,3,4,5,np.inf],依次对南部地区的深度和烈度等级建立多级索引排序。
方向里边没有南部啊??????
d['烈度'] = pd.cut(d['烈度'], [0,3,4,5,np.inf],labels=['Ⅰ','Ⅱ','Ⅲ','Ⅳ'])
d.set_index(['深度','烈度']).sort_index().head()
【练习二】 对于分类变量而言,调用第4章中的变形函数会出现一个BUG(目前的版本下还未修复):例如对于crosstab函数,按照官方文档的说法,即使没有出现的变量也会在变形后的汇总结果中出现,但事实上并不是这样,比如下面的例子就缺少了原本应该出现的行'c'和列'f'。基于这一问题,请尝试设计my_crosstab函数,在功能上能够返回正确的结果。
参考答案:
def my_crosstab(foo,bar):
num = len(foo)
s1 = pd.Series([i for i in list(foo.categories.union(set(foo)))],name='1nd var')
s2 = [i for i in list(bar.categories.union(set(bar)))]
df = pd.DataFrame({i:[0]*len(s1) for i in s2},index=s1)
for i in range(num):
df.at[foo[i],bar[i]] += 1
return df.rename_axis('2st var',axis=1)
my_crosstab(foo,bar)