前导
更多文章代码详情可查看博主个人网站:https://www.iwtmbtly.com/
导入需要使用的库和文件:
>>> import pandas as pd
>>> import numpy as np
>>> df = pd.read_csv('data/table.csv')
>>> df.head()
School Class ID Gender Address Height Weight Math Physics
0 S_1 C_1 1101 M street_1 173 63 34.0 A+
1 S_1 C_1 1102 F street_2 192 73 32.5 B+
2 S_1 C_1 1103 M street_2 186 82 87.2 B+
3 S_1 C_1 1104 F street_2 167 81 80.4 B-
4 S_1 C_1 1105 F street_4 159 64 84.8 B+
一、category的创建及其性质
(一)分类变量的创建
1. 用Series创建
>>> pd.Series(["a", "b", "c", "a"], dtype="category")
0 a
1 b
2 c
3 a
dtype: category
Categories (3, object): ['a', 'b', 'c']
2. 对DataFrame指定类型创建
>>> temp_df = pd.DataFrame({
'A':pd.Series(["a", "b", "c", "a"], dtype="category"),'B':list('abcd')})
>>> temp_df.dtypes
A category
B object
dtype: object
3. 利用内置Categorical类型创建
>>> 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']
4. 利用cut函数创建
默认使用区间类型为标签:
>>> pd.cut(np.random.randint(0,60,5), [0,10,30,60])
[(0, 10], (10, 30], (10, 30], (10, 30], (30, 60]]
Categories (3, interval[int64, right]): [(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'])
['30-60', '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. categories和ordered属性
查看分类类别以及是否排序:
>>> s.cat.categories
Index(['a', 'b', 'c', 'd'], dtype='object')
>>> s.cat.ordered
False
(三)类别的修改
1. 利用set_categories修改
修改分类,但本身值不会变化:
>>> s = pd.Series(pd.Categorical(["a", "b", "c", "a",np.nan], categories=['a','b','c','d']))
>>> s.cat.set_categories(['new_a','c'])
0 NaN
1 NaN
2 c
3 NaN
4 NaN
dtype: category
Categories (2, object): ['new_a', 'c']
2. 利用rename_categories修改
需要注意的是该方法会把值和分类同时修改:
>>> s = pd.Series(pd.Categorical(["a", "b", "c", "a",np.nan], categories=['a','b','c','d']))
>>> s.cat.rename_categories(['new_%s'%i for i in s.cat.categories])
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']
利用字典修改值:
>>> s.cat.rename_categories({
'a':'new_a','b':'new_b'})
0 new_a
1 new_b
2 c
3 new_a
4 NaN
dtype: category
Categories (4, object): ['new_a', 'new_b', 'c', 'd']
3. 利用add_categories添加
>>> s = pd.Series(pd.Categorical(["a", "b", "c", "a",np.nan], categories=['a','b','c','d']))
>>> s.cat.add_categories(['e'])
0 a
1 b
2 c
3 a
4 NaN
dtype: category
Categories (5, object): ['a', 'b', 'c', 'd', 'e']
4. 利用remove_categories移除
>>> s = pd.Series(pd.Categorical(["a", "b", "c", "a",np.nan], categories=['a','b','c','d']))
>>> s.cat.remove_categories(['d'])
0 a
1 b
2 c
3 a
4 NaN
dtype: category
Categories (3, object): ['a', 'b', 'c']
5. 删除元素值未出现的分类类型
>>> s = pd.Series(pd.Categorical(["a", "b", "c", "a",np.nan], categories=['a','b','c','d']))
>>> s.cat.remove_unused_categories()
0 a
1 b
2 c
3 a
4 NaN
dtype: category
Categories (3, object): ['a', 'b', 'c']
二、分类变量的排序
前面提到,分类数据类型被分为有序和无序,这非常好理解,例如分数区间的高低是有序变量,考试科目的类别一般看做无序变量
(一)序的建立
1. 一般来说会将一个序列转为有序变量,可以利用as_ordered方法
>>> s = pd.Series(["a", "d", "c", "a"]).astype('category').cat.as_ordered()
>>> s
0 a
1 d
2 c
3 a
dtype: category
Categories (3, object): ['a' < 'c' < 'd']
退化为无序变量,只需要使用as_unordered
>>> s.cat.as_unordered()
0 a
1 d
2 c
3 a
dtype: category
Categories (3, object): ['a', 'c', 'd']
2. 利用set_categories方法中的order参数
>>> pd.Series(["a", "d", "c", "a"]).astype('category').cat.set_categories(['a','c','d'],ordered=True)
0 a
1 d
2 c
3 a
dtype: category
Categories (3, object): ['a' < 'c' < 'd']
3. 利用reorder_categories方法
这个方法的特点在于,新设置的分类必须与原分类为同一集合:
>>> s = pd.Series(["a", "d", "c", "a"]).astype('category')
>>> s.cat.reorder_categories(['a','c','d'],ordered=True)
0 a
1 d
2 c
3 a
dtype: category
Categories (3, object): ['a' < 'c' < 'd']
# s.cat.reorder_categories(['a','c'],ordered=True) # 报错
# s.cat.reorder_categories(['a','c','d','e'],ordered=True) # 报错
(二)排序
1. 值排序和索引排序
>>> s = pd.Series(np.random.choice(['perfect','good','fair','bad','awful'],50)).astype('category')
>>> s.cat.set_categories(['perfect','good','fair','bad','awful'][::-1],ordered=True).head()
0 good
1 good
2 fair
3 awful
4 good
dtype: category
Categories (5, object): ['awful' < 'bad' < 'fair' < 'good' < 'perfect']
>>> s.sort_values(ascending=False).head()
49 perfect
41 perfect
38 perfect
34 perfect
31 perfect
dtype: category
Categories (5, object): ['awful', 'bad', 'fair', 'good', 'perfect']
>>> df_sort = pd.DataFrame({
'cat':s.values,'value':np.random.randn(50)}).set_index('cat')
>>> df_sort.head()
value
cat
good -0.492898
good -0.800566
fair 0.355032
awful 0.299062
good -2.321767
>>> df_sort.sort_index().head()
value
cat
awful 0.435638
awful 1.912790
awful -0.204264
awful 0.299062
awful -0.585013
三、分类变量的比较操作
(一)与标量或等长序列的比较
1. 标量比较
>>> s = pd.Series(["a", "d", "c", "a"]).astype('category')
>>> s == 'a'
0 True
1 False
2 False
3 True
dtype: bool
2. 等长序列比较
>>> s == list('abcd')
0 True
1 False
2 True
3 False
dtype: bool
(二)与另一分类变量的比较
1. 等式判别(包含等号和不等号)
两个分类变量的等式判别需要满足分类完全相同:
>>> s = pd.Series(["a", "d", "c", "a"]).astype('category')
>>> s == s
0 True
1 True
2 True
3 True
dtype: bool
>>> s != s
0 False
1 False
2 False
3 False
dtype: bool
>>> s_new = s.cat.set_categories(['a','d','e'])
>>> s == s_new # 报错
raise TypeError(msg)
TypeError: Categoricals can only be compared if 'categories' are the same.
2. 不等式判别(包含>=,<=,<,>)
两个分类变量的不等式判别需要满足两个条件:
-
分类完全相同
-
排序完全相同
>>> s = pd.Series(["a", "d", "c", "a"]).astype('category')
>>> # s >= s # 报错
raise TypeError(
TypeError: Unordered Categoricals can only compare equality or not
>>> s=pd.Series(["a","d","c","a"]).astype('category').cat.reorder_categories(['a','c','d'],ordered=True)
>>> s >= s
0 True
1 True
2 True
3 True
dtype: bool