來看看 Pandas 中分類(category)數(shù)據(jù)如何處理吧呈驶。
創(chuàng)建分類對(duì)象
1.使用dtype="category"創(chuàng)建
在創(chuàng)建分類數(shù)據(jù)之前任岸,先來了解下什么是分類(Category)數(shù)據(jù)呢乘客?分類數(shù)據(jù)直白來說就是取值為有限的含潘,或者說是固定數(shù)量的可能值。例如:性別飒箭、血型狼电。
這里以血型為例,假定每個(gè)用戶有以下的血型弦蹂,我們?nèi)绾蝿?chuàng)建一個(gè)關(guān)于血型的分類對(duì)象呢肩碟?
一種有效的方法就是明確指定 dtype="category"
import pandas as pd
import numpy as np
index = pd.Index(data=['Tom','Bob','Mary','James','Andy','Alice'])
user_info = pd.Series(data=['A','AB',np.nan,'AB','O','B'],index=index,name='blood_type',dtype='category')
print(user_info)
# Tom A
# Bob AB
# Mary NaN
# James AB
# Andy O
# Alice B
# Name: blood_type, dtype: category
# Categories (4, object): ['A', 'AB', 'B', 'O']
2.使用pd.Categorical 創(chuàng)建
# categories:指定存儲(chǔ)的分類信息
c = pd.Categorical(["A", "AB", np.nan, "AB", "O", "B"], categories=["A", "B", "AB"])
print(c)
# ['A', 'AB', NaN, 'AB', NaN, 'B']
# Categories (3, object): ['A', 'B', 'AB']
3.astype
除了上面這些方法外,經(jīng)常遇到的情況是已經(jīng)創(chuàng)建了一個(gè) Series凸椿,如何將它轉(zhuǎn)為分類數(shù)據(jù)呢削祈?來看看 astype 用法吧。
user_info = pd.Series(data=["A", "AB", np.nan, "AB", "O", "B"], index=index, name="blood_type")
user_info = user_info.astype("category")
print(user_info)
# Tom A
# Bob AB
# Mary NaN
# James AB
# Andy O
# Alice B
# Name: blood_type, dtype: category
# Categories (4, object): ['A', 'AB', 'B', 'O']
此外脑漫,一些其他的方法返回的結(jié)果也是分類數(shù)據(jù)髓抑。如 cut 、 qcut窿撬。具體可以見 Pandas基本功能詳解中的離散化部分。
常用操作
統(tǒng)計(jì)
可以對(duì)分類數(shù)據(jù)使用 .describe() 方法叙凡。
c = user_info.describe()
print(c)
# count 5
# unique 4
# top AB
# freq 2
# Name: blood_type, dtype: object
解釋下每個(gè)指標(biāo)的含義劈伴,count 表示非空的數(shù)據(jù)有5條,unique 表示去重后的非空數(shù)據(jù)有4條握爷,top 表示出現(xiàn)次數(shù)最多的值為 AB跛璧,freq 表示出現(xiàn)次數(shù)最多的值的次數(shù)為2次。
分類數(shù)據(jù)的取值
我們可以使用 .cat.categories 來獲取分類數(shù)據(jù)所有可能的取值新啼。
c = user_info.cat.categories
print(c)
# Index(['A', 'AB', 'B', 'O'], dtype='object')
修改分類名稱
user_info = user_info.cat.rename_categories(["A+", "AB+", "B+", "O+"])
print(user_info)
# Tom A+
# Bob AB+
# Mary NaN
# James AB+
# Andy O+
# Alice B+
# Name: blood_type, dtype: category
# Categories (4, object): ['A+', 'AB+', 'B+', 'O+']
修改分類名稱后追城,也會(huì)將數(shù)據(jù)中的對(duì)應(yīng)進(jìn)行修改。
類似的燥撞,除了重命名座柱,也會(huì)遇到添加類別迷帜,刪除分類的操作,這些都可以通過 .cat.add_categories 色洞,.cat.remove_categories 來實(shí)現(xiàn)戏锹。
user_info = user_info.cat.add_categories(["C"])
print(user_info)
# Tom A+
# Bob AB+
# Mary NaN
# James AB+
# Andy O+
# Alice B+
# Name: blood_type, dtype: category
# Categories (5, object): ['A+', 'AB+', 'B+', 'O+', 'C']
查看數(shù)據(jù)分布統(tǒng)計(jì)
分類數(shù)據(jù)也是支持使用 value_counts 方法來查看數(shù)據(jù)分布的。
c = user_info.value_counts()
print(c)
# AB+ 2
# O+ 1
# B+ 1
# A+ 1
# C 0
# Name: blood_type, dtype: int64
.str
分類數(shù)據(jù)也是支持使用 .str 屬性來訪問的火诸。例如想要查看下是否包含字母 "A"锦针,可以使用 .srt.contains 方法。
c = user_info.str.contains('A')
print(c)
# Tom True
# Bob True
# Mary NaN
# James True
# Andy False
# Alice False
# Name: blood_type, dtype: object
返回一個(gè)bool值的Series序列置蜀,利用花式索引可以獲取到符合條件的數(shù)據(jù)奈搜。
更多關(guān)于 .str 的詳細(xì)介紹可以見 Pandas文本數(shù)據(jù)處理。
合并數(shù)據(jù)
pd.concat([Series,Series])
blood_type1 = pd.Categorical(["A", "AB"])
blood_type2 = pd.Categorical(["B", "O"])
c = pd.concat([pd.Series(blood_type1), pd.Series(blood_type2)])
print(c)
# 0 A
# 1 AB
# 0 B
# 1 O
# dtype: object
可以發(fā)現(xiàn)盯荤,分類數(shù)據(jù)經(jīng)過 pd.concat 合并后類型轉(zhuǎn)為了 object 類型馋吗。如果想要保持分類類型的話,可以借助 union_categoricals 來完成廷雅。
from pandas.api.types import union_categoricals
c = union_categoricals([blood_type1, blood_type2])
print(c)
# 0 A
# 1 AB
# 0 B
# 1 O
# dtype: object
# ['A', 'AB', 'B', 'O']
# Categories (4, object): ['A', 'AB', 'B', 'O']
分類數(shù)據(jù)與Series序列的內(nèi)存對(duì)比
blood_type = pd.Series(["AB","O"]*1000)
blood_type.nbytes
16000
blood_type.astype("category").nbytes
2016
對(duì)比下耗美,是不是發(fā)現(xiàn)分類數(shù)據(jù)非常節(jié)省內(nèi)存。但是當(dāng)類別的數(shù)量接近數(shù)據(jù)的長(zhǎng)度航缀,那么 Categorical 將使用與等效的 object 表示幾乎相同或更多的內(nèi)存商架。
blood_type = pd.Series(['AB%04d' % i for i in range(2000)])
blood_type.nbytes
16000
blood_type.astype("category").nbytes
20000