print(pd.Series(["a", "b", "c", "a"], dtype="category"))
0 a
1 b
2 c
3 a
dtype: category
Categories (3, object): [a, b, c]
print(pd.DataFrame({'A':pd.Series(["a", "b", "c", "a"], dtype="category"),'B':list('abcd')}).dtypes)
A category
B object
dtype: object
print(pd.Categorical(["a", "b", "c", "a"], categories=['a','b','c']))
print(pd.Series(pd.Categorical(["a", "b", "c", "a"], categories=['a','b','c'])))
[a, b, c, a]
Categories (3, object): [a, b, c]
0 a
1 b
2 c
3 a
dtype: category
Categories (3, object): [a, b, c]
print('默认使用区间类型为标签')
print(pd.cut(np.random.randint(0,60,5), [0,10,30,60]))
print('可指定字符为标签')
print(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], (10, 30], (0, 10], (10, 30]]
Categories (3, interval[int64]): [(0, 10] < (10, 30] < (30, 60]]
可指定字符为标签
[10-30, 30-60, 10-30, 30-60, 0-10]
Categories (3, object): [0-10 < 10-30 < 30-60]
一个分类变量包括三个部分,元素值(values)、分类类别(categories)、是否有序(order)。从上面可以看出,使用cut函数创建的分类变量默认为有序分类变量。
该方法描述了一个分类序列的情况,包括非缺失值个数、元素值类别数(不是分类类别数)、最多次出现的元素及其频数
s = pd.Series(pd.Categorical(["a", "b", "c", "a",np.nan], categories=['a','b','c','d']))
print(s.describe())
count 4
unique 3
top a
freq 2
dtype: object
categories和ordered查看分类类别和是否排序
print(s.cat.categories)
print(s.cat.ordered)
Index(['a', 'b', 'c', 'd'], dtype='object')
False
修改分类,但本身值不会变化
s = pd.Series(pd.Categorical(["a", "b", "c", "a",np.nan], categories=['a','b','c','d']))
print(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]
需要注意的是该方法会把值和分类同时修改
s = pd.Series(pd.Categorical(["a", "b", "c", "a",np.nan], categories=['a','b','c','d']))
print(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]
利用字典修改值
print(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]
s = pd.Series(pd.Categorical(["a", "b", "c", "a",np.nan], categories=['a','b','c','d']))
print(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]
s = pd.Series(pd.Categorical(["a", "b", "c", "a",np.nan], categories=['a','b','c','d']))
print(s.cat.remove_categories(['d']))
0 a
1 b
2 c
3 a
4 NaN
dtype: category
Categories (3, object): [a, b, c]
s = pd.Series(pd.Categorical(["a", "b", "c", "a",np.nan], categories=['a','b','c','d']))
print(s.cat.remove_unused_categories())
0 a
1 b
2 c
3 a
4 NaN
dtype: category
Categories (3, object): [a, b, c]
前面提到,分类数据类型被分为有序和无序,这非常好理解,例如分数区间的高低是有序变量,考试科目的类别一般看做无序变量。
print(pd.Series(["a", "d", "c", "a"]).astype('category').cat.as_ordered())
0 a
1 d
2 c
3 a
dtype: category
Categories (3, object): [a < c < d]
s = pd.Series(["a", "d", "c", "a"]).astype('category').cat.as_ordered()
print(s.cat.as_unordered())
0 a
1 d
2 c
3 a
dtype: category
Categories (3, object): [a, c, d]
print(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]
s = pd.Series(["a", "d", "c", "a"]).astype('category')
print(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]
先前在pandas基础 四、排序介绍的值排序和索引排序都是适用的
s = pd.Series(np.random.choice(['perfect','good','fair','bad','awful'],50)).astype('category')
print(s.cat.set_categories(['perfect','good','fair','bad','awful'][::-1],ordered=True).head())
0 perfect
1 fair
2 good
3 good
4 awful
dtype: category
Categories (5, object): [awful < bad < fair < good < perfect]
print(s.sort_values(ascending=False).head())
24 perfect
34 perfect
11 perfect
13 perfect
21 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')
print(df_sort.head())
print('\n')
print(df_sort.sort_index().head())
value
cat
perfect 0.635729
fair -0.595803
good -1.527069
good -0.639531
awful -1.245262
value
cat
awful -2.320631
awful 0.519921
awful -1.245262
awful 0.388255
awful -0.034745
s = pd.Series(["a", "d", "c", "a"]).astype('category')
print('标量比较')
print(s == 'a')
print('等长序列比较')
print(s == list('abcd'))
标量比较
0 True
1 False
2 False
3 True
dtype: bool
等长序列比较
0 True
1 False
2 True
3 False
dtype: bool
print('等式判别(包含等号和不等号)')
print('两个分类变量的等式判别需要满足分类完全相同')
s = pd.Series(["a", "d", "c", "a"]).astype('category')
print(s == s)
print(s != s)
print('不等式判别(包含>=,<=,<,>)')
print('两个分类变量的不等式判别需要满足两个条件:① 分类完全相同 ② 排序完全相同')
s = pd.Series(["a", "d", "c", "a"]).astype('category')
#s >= s #报错
s = pd.Series(["a", "d", "c", "a"]).astype('category').cat.reorder_categories(['a','c','d'],ordered=True)
print(s >= s)
等式判别(包含等号和不等号)
两个分类变量的等式判别需要满足分类完全相同
0 True
1 True
2 True
3 True
dtype: bool
0 False
1 False
2 False
3 False
dtype: bool
不等式判别(包含>=,<=,<,>)
两个分类变量的不等式判别需要满足两个条件:① 分类完全相同 ② 排序完全相同
0 True
1 True
2 True
3 True
dtype: bool
【问题一】 如何使用union_categoricals方法?它的作用是什么?
在这里插入代码片
【问题二】 利用concat方法将两个序列纵向拼接,它的结果一定是分类变量吗?什么情况下不是?
在这里插入代码片
【问题三】 当使用groupby方法或者value_counts方法时,分类变量的统计结果和普通变量有什么区别?
在这里插入代码片
【问题四】 下面的代码说明了Series创建分类变量的什么“缺陷”?如何避免?(提示:使用Series中的copy参数)
在这里插入代码片
【练习一】 现继续使用第四章中的地震数据集Earthquake.csv
,请解决以下问题:
(a)现在将深度分为七个等级:[0,5,10,15,20,30,50,np.inf],请以深度等级Ⅰ,Ⅱ,Ⅲ,Ⅳ,Ⅴ,Ⅵ,Ⅶ为索引并按照由浅到深的顺序进行排序。
(b)在(a)的基础上,将烈度分为4个等级:[0,3,4,5,np.inf],依次对南部地区的深度和烈度等级建立多级索引排序。
ex1 = pd.read_csv('work/Earthquake.csv')
print('(a)')
ex1_a = ex1.copy()
ex1_a['深度'] = pd.cut(ex1_a['深度'], [-1e-10,5,10,15,20,30,50,np.inf],labels=['Ⅰ','Ⅱ','Ⅲ','Ⅳ','Ⅴ','Ⅵ','Ⅶ'])
print(ex1_a.set_index('深度').sort_index().head())
print('(b)')
ex1_a['烈度'] = pd.cut(ex1_a['烈度'], [-1e-10,3,4,5,np.inf],labels=['Ⅰ','Ⅱ','Ⅲ','Ⅳ'])
print(ex1_a.set_index(['深度','烈度']).sort_index().head())
(a)
日期 时间 维度 经度 方向 距离 烈度
深度
Ⅰ 2009.09.09 12:54:13 AM 42.42 43.03 north_east 95.4 0.0
Ⅰ 1997.06.16 12:18:04 AM 37.92 29.17 north_east 3.2 0.0
Ⅰ 2011.10.25 12:29:45 AM 38.96 43.64 south_east 1.6 3.9
Ⅰ 1995.07.23 12:05:04 AM 37.61 29.29 north_east 3.2 0.0
Ⅰ 2013.06.10 12:39:19 AM 38.53 43.85 south_east 1.6 3.7
(b)
日期 时间 维度 经度 方向 距离
深度 烈度
Ⅰ Ⅰ 1978.05.07 12:41:37 AM 38.58 27.61 south_west 0.1
Ⅰ 2000.02.07 12:11:45 AM 40.05 34.07 south_east 0.1
Ⅰ 1971.05.20 12:08:46 AM 37.72 30.00 north_east 0.1
Ⅰ 1985.01.28 12:20:56 AM 38.85 29.06 north_east 0.1
Ⅰ 1990.07.05 12:43:04 AM 37.87 29.18 east 0.1
【练习二】 对于分类变量而言,调用第4章中的变形函数会出现一个BUG(目前的版本下还未修复):例如对于crosstab函数,按照官方文档的说法,即使没有出现的变量也会在变形后的汇总结果中出现,但事实上并不是这样,比如下面的例子就缺少了原本应该出现的行’c’和列’f’。基于这一问题,请尝试设计my_crosstab函数,在功能上能够返回正确的结果。
foo = pd.Categorical(['a', 'b'], categories=['a', 'b', 'c'])
bar = pd.Categorical(['d', 'e'], categories=['d', 'e', 'f'])
print(pd.crosstab(foo, bar))
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)