pandas分类数据category

快速浏览

    • 分类变量的创建
      • 用Series创建
      • 对DataFrame指定类型创建
      • 利用内置Categorical类型创建
      • 利用cut函数创建
    • 分类变量的结构与性质
      • describe方法
      • categories和ordered属性
      • 利用set_categories修改类别
      • 利用rename_categories修改类别
      • 利用add_categories添加
      • 利用remove_categories移除
      • 删除元素值未出现的分类类型
    • 分类变量的排序
      • 一般来说会将一个序列转为有序变量,可以利用as_ordered方法
      • 退化为无序变量,只需要使用as_unordered
      • 利用set_categories方法中的order参数
      • 利用reorder_categories方法,新设置的分类必须与原分类为同一集合
      • 排序
    • 分类变量的比较操作
      • 与标量或等长序列的比较
      • 与另一分类变量的比较
    • 问题与练习
    • Reference

分类变量的创建

用Series创建

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]

对DataFrame指定类型创建

print(pd.DataFrame({'A':pd.Series(["a", "b", "c", "a"], dtype="category"),'B':list('abcd')}).dtypes)
A    category
B      object
dtype: object

利用内置Categorical类型创建

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]

利用cut函数创建

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函数创建的分类变量默认为有序分类变量。

describe方法

该方法描述了一个分类序列的情况,包括非缺失值个数、元素值类别数(不是分类类别数)、最多次出现的元素及其频数

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属性

categories和ordered查看分类类别和是否排序

print(s.cat.categories)
print(s.cat.ordered)
Index(['a', 'b', 'c', 'd'], dtype='object')
False

利用set_categories修改类别

修改分类,但本身值不会变化

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]

利用rename_categories修改类别

需要注意的是该方法会把值和分类同时修改

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]

利用add_categories添加

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]

利用remove_categories移除

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]

分类变量的排序

前面提到,分类数据类型被分为有序和无序,这非常好理解,例如分数区间的高低是有序变量,考试科目的类别一般看做无序变量。

一般来说会将一个序列转为有序变量,可以利用as_ordered方法

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]

退化为无序变量,只需要使用as_unordered

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]

利用set_categories方法中的order参数

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]

利用reorder_categories方法,新设置的分类必须与原分类为同一集合

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参数)
pandas分类数据category_第1张图片

在这里插入代码片

【练习一】 现继续使用第四章中的地震数据集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)

Reference

  1. pandas官网
  2. Joyful-Pandas

你可能感兴趣的:(Pandas教程)