【pandas 小記】Categoricals數據類型

一,分類變量

在做數據分析統計時,常遇到這樣的類型,比如:性別、社會階層、血型、國籍、觀察時段、讚美程度等等。這類數據都是固定的可能值,取值重複並且多爲字符串。如性別中男和女,血型中A、B、O和AB。pandas中有可以存儲和處理這類數據的數據類型——categorical,categorical是pandas中對應分類變量的一種數據類型。

二,創建方式

1,astype進行類型轉換

import pandas as pd
import numpy as np
path = '../data/sz.xlsx'
sz_frame = pd.read_excel(path)
sz_frame['floor'].astype('category')
0        低樓層
1        低樓層
2        低樓層
3        低樓層
4        低樓層
        ... 
45263    中樓層
45264    高樓層
45265    低樓層
45266    低樓層
45267    中樓層
Name: floor, Length: 45268, dtype: category
Categories (3, object): [中樓層, 低樓層, 高樓層]

2,通過 dtype="category "顯式創建

# Series
floor = pd.Series(sz_frame['floor'],dtype='category')
floor
0        低樓層
1        低樓層
2        低樓層
3        低樓層
4        低樓層
        ... 
45263    中樓層
45264    高樓層
45265    低樓層
45266    低樓層
45267    中樓層
Name: floor, Length: 45268, dtype: category
Categories (3, object): [中樓層, 低樓層, 高樓層]
#DataFrame
floor = pd.DataFrame(sz_frame['floor'],dtype='category')
floor.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 45268 entries, 0 to 45267
Data columns (total 1 columns):
floor    45268 non-null category
dtypes: category(1)
memory usage: 44.4 KB

3,cut/qcut 隱式創建

unit_price_level = pd.cut(sz_frame['unit_price'],3,precision=2)

0          (1.18, 14.8]
1          (1.18, 14.8]
2          (1.18, 14.8]
3          (1.18, 14.8]
4          (1.18, 14.8]
              ...      
45263    (28.38, 41.95]
45264    (28.38, 41.95]
45265    (28.38, 41.95]
45266    (28.38, 41.95]
45267    (28.38, 41.95]
Name: unit_price, Length: 45268, dtype: category
Categories (3, interval[float64]): [(1.18, 14.8] < (14.8, 28.38] < (28.38, 41.95]]
unit_price_level = pd.qcut(sz_frame['unit_price'],3,precision=2)
unit_price_level.value_counts()
(1.21, 4.56]    15090
(6.4, 41.95]    15089
(4.56, 6.4]     15089
Name: unit_price, dtype: int64
# 向cut/qcut 傳入整數個箱數,cut 通常不會使每個箱子具有相同數據量,而qcuts使用樣本的分位數,可以通過qcut獲得等數據量的箱子。

4,Categorical顯式創建

index = pd.Index(data=["Tom", "Bob", "Mary", "James", "Andy", "Alice"], name="name")
user_info = pd.Series(data=["A", "AB", np.nan, "AB", "O", "B"], index=index, name="blood_type") 
# categories:自定義類別數據
pd.Categorical(user_info, categories=["A", "B", "AB"]) 
[A, AB, NaN, AB, NaN, B]    # 對於不存在的類型,則爲NaN
Categories (3, object): [A, B, AB]

三,應用

1,內存使用與效率
Categorical類型使得DataFrame數據佔用更少的內存。

n = 10000000
labels = pd.Series(['1E76B5DCA3A19D03B0FB39BCF2A2F534',
                    '6945300E90C69061B463CCDA370DE5D6',
                    '4F4BEA1914E323156BE0B24EF8205B73',
                    '191115180C29B1E2AF8BE0FD0ABD138F']*(n //4))
draws  = pd.DataFrame({'labels':labels,'data':np.random.randn(n)})
draws.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10000000 entries, 0 to 9999999
Data columns (total 2 columns):
labels    object
data      float64
dtypes: float64(1), object(1)
memory usage: 152.6+ MB
draws['labels'] = draws['labels'].astype('category')
draws.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10000000 entries, 0 to 9999999
Data columns (total 2 columns):
labels    category
data      float64
dtypes: category(1), float64(1)
memory usage: 85.8 MB

memory usage 上減少了。至於對groupby操作性能的提升,也做了測試,感覺提升也不是很多,反而轉換成category時消耗的部分性能,也可能是測試的數據量,或者分類類型不是很多,所以效果不明顯。

%timeit draws.groupby('labels').sum()
# 159 ms ± 5.6 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
draws['labels'] = draws['labels'].astype('category')
%timeit draws.groupby('labels').sum()
# 157 ms ± 4.44 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

2,屬性與方法
Categorical對象有兩個常用到的屬性categories與codes

floor = pd.Series(sz_frame['floor'],dtype='category')
floor.cat.categories #類別數組,Index(['中樓層', '低樓層', '高樓層'], dtype='object')
floor.cat.codes   # 返回一個數據,每個數據對應的類別數據的下標
0        0
1        1
2        1
3        2
4        0
        ..
45263    1
45264    1
45265    1
45266    1
45267    1
Length: 45268, dtype: int8

其他方法,參考官方文檔 ,pandas中用挺大的篇幅介紹的,應該也是蠻實用的。
,
3,one-hot
Categorical類型數據除了在groupby中使用,還有可以用於機器學習的one-hot編碼,通常會將分類數據轉換成虛擬變量,也成one-hot編碼,這將會產生一個datafrme,每個類型對應一列,如爲該類型,則數值爲1,否則爲0。

floor = pd.Series(sz_frame['floor'],dtype='category')
pd.get_dummies(floor)
floor	中樓層	低樓層	高樓層
0	1	0	0
1	0	1	0
2	0	1	0
3	0	0	1
4	1	0	0
...	...	...	...
45263	0	1	0
45264	0	1	0
45265	0	1	0
45266	0	1	0
45267	0	1	0
45268 rows × 3 columns
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章