pandas學習 第8章 分類數據

第8章 分類數據

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. 分類變量的創建

(a)用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]

(b)對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

(c)利用內置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]

(d)利用cut函數創建

默認使用區間類型爲標籤

pd.cut(np.random.randint(0,60,5), [0,10,30,60])
[(10, 30], (0, 10], (10, 30], (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]

2. 分類變量的結構

一個分類變量包括三個部分,元素值(values)、分類類別(categories)、是否有序(order)

從上面可以看出,使用cut函數創建的分類變量默認爲有序分類變量

下面介紹如何獲取或修改這些屬性

(a)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

(b)categories和ordered屬性

查看分類類別和是否排序

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

3. 類別的修改

(a)利用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]

(b)利用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]

(c)利用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]

(d)利用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]

(e)刪除元素值未出現的分類類型

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. 序的建立

(a)一般來說會將一個序列轉爲有序變量,可以利用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]

(b)利用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]

(c)利用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) #報錯

2. 排序

先前在第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       fair
2        bad
3    perfect
4    perfect
dtype: category
Categories (5, object): [awful < bad < fair < good < perfect]
s.sort_values(ascending=False).head()
29    perfect
17    perfect
31    perfect
3     perfect
4     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 -1.746975
fair 0.836732
bad 0.094912
perfect -0.724338
perfect -1.456362
df_sort.sort_index().head()
value
cat
awful 0.245782
awful 0.063991
awful 1.541862
awful -0.062976
awful 0.472542

三、分類變量的比較操作

1. 與標量或等長序列的比較

(a)標量比較

s = pd.Series(["a", "d", "c", "a"]).astype('category')
s == 'a'
0     True
1    False
2    False
3     True
dtype: bool

(b)等長序列比較

s == list('abcd')
0     True
1    False
2     True
3    False
dtype: bool

2. 與另一分類變量的比較

(a)等式判別(包含等號和不等號)

兩個分類變量的等式判別需要滿足分類完全相同

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 #報錯

(b)不等式判別(包含>=,<=,<,>)

兩個分類變量的不等式判別需要滿足兩個條件:① 分類完全相同 ② 排序完全相同

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)
s >= s
0    True
1    True
2    True
3    True
dtype: bool

四、問題與練習

【問題一】 如何使用union_categoricals方法?它的作用是什麼?

【問題二】 利用concat方法將兩個序列縱向拼接,它的結果一定是分類變量嗎?什麼情況下不是?

【問題三】 當使用groupby方法或者value_counts方法時,分類變量的統計結果和普通變量有什麼區別?

【問題四】 下面的代碼說明了Series創建分類變量的什麼“缺陷”?如何避免?(提示:使用Series中的copy參數)

cat = pd.Categorical([1, 2, 3, 10], categories=[1, 2, 3, 4, 10])
s = pd.Series(cat, name="cat")
cat
[1, 2, 3, 10]
Categories (5, int64): [1, 2, 3, 4, 10]
s.iloc[0:2] = 10
cat
[10, 10, 3, 10]
Categories (5, int64): [1, 2, 3, 4, 10]

【練習一】 現繼續使用第四章中的地震數據集,請解決以下問題:

(a)現在將深度分爲七個等級:[0,5,10,15,20,30,50,np.inf],請以深度等級Ⅰ,Ⅱ,Ⅲ,Ⅳ,Ⅴ,Ⅵ,Ⅶ爲索引並按照由淺到深的順序進行排序。

(b)在(a)的基礎上,將烈度分爲4個等級:[0,3,4,5,np.inf],依次對南部地區的深度和烈度等級建立多級索引排序。

pd.read_csv('data/Earthquake.csv').head()
日期 時間 維度 經度 方向 距離 深度 烈度
0 2003.05.20 12:17:44 AM 39.04 40.38 west 0.1 10.0 0.0
1 2007.08.01 12:03:08 AM 40.79 30.09 west 0.1 5.2 4.0
2 1978.05.07 12:41:37 AM 38.58 27.61 south_west 0.1 0.0 0.0
3 1997.03.22 12:31:45 AM 39.47 36.44 south_west 0.1 10.0 0.0
4 2000.04.02 12:57:38 AM 40.80 30.24 south_west 0.1 7.0 0.0

【練習二】 對於分類變量而言,調用第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'])
pd.crosstab(foo, bar)
col_0 d e
row_0
a 1 0
b 0 1
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章