公众号:尤而小屋 作者:Peter 编辑:Pete
大家好,我是Peter~
本文中介绍的是Categorical类型,主要实现的数据分类问题,用于承载基于整数的类别展示或编码的数据,帮助使用者获得更好的性能和内存使用。
<!--MORE-->
在一个Series数据中经常会出现重复值,我们需要提取这些不同的值并且分别计算它们的频数:
import numpy as np
import pandas as pd
data = pd.Series(["语文","数学","英语","数学","英语","地理","语文","语文"])
data
0 语文
1 数学
2 英语
3 数学
4 英语
5 地理
6 语文
7 语文
dtype: object
# 1、提取不同的值
pd.unique(data)
array(['语文', '数学', '英语', '地理'], dtype=object)
# 2、统计每个值的个数
pd.value\_counts(data)
语文 3
数学 2
英语 2
地理 1
dtype: int64
通过整数展现的方式,被称作分类或者字典编码。不同的数组可以称之为数据的类别、字典或者层级
df = pd.Series([0,1,1,0] \* 2)
df
0 0
1 1
2 1
3 0
4 0
5 1
6 1
7 0
dtype: int64
# dim使用维度表
dim = pd.Series(["语文","数学"])
dim
0 语文
1 数学
dtype: object
如何将0-语文,1-数学在df进行一一对应呢?使用**take**方法来实现
df1 = dim.take(df)
df1
0 语文
1 数学
1 数学
0 语文
0 语文
1 数学
1 数学
0 语文
dtype: object
type(df1) # Series数据
pandas.core.series.Series
通过例子来讲解Categorical类型的使用
subjects = ["语文","数学","语文","语文"] \* 2
N = len(subjects)
df2 = pd.DataFrame({
"subject":subjects,
"id": np.arange(N), # 连续整数
"score":np.random.randint(3,15,size=N), # 随机整数
"height":np.random.uniform(165,180,size=N) # 正态分布的数据
},
columns=["id","subject","score","height"]) # 指定列名称的顺序
df2
可以将subject转成Categorical类型:
subject\_cat = df2["subject"].astype("category")
subject\_cat
我们发现了subject_cat的两个特点:
s = subject\_cat.values
s
['语文', '数学', '语文', '语文', '语文', '数学', '语文', '语文']
Categories (2, object): ['数学', '语文']
type(s)
pandas.core.arrays.categorical.Categorical
s.categories # 查看分类
Index(['数学', '语文'], dtype='object')
s.codes # 查看分类编码
array([1, 0, 1, 1, 1, 0, 1, 1], dtype=int8)
主要是两种方式:
# 方式1
df2["subject"] = df2["subject"].astype("category")
df2.subject
0 语文
1 数学
2 语文
3 语文
4 语文
5 数学
6 语文
7 语文
Name: subject, dtype: category
Categories (2, object): ['数学', '语文']
# 方式2
fruit = pd.Categorical(["苹果","香蕉","葡萄","苹果","苹果","香蕉"])
fruit
['苹果', '香蕉', '葡萄', '苹果', '苹果', '香蕉']
Categories (3, object): ['苹果', '葡萄', '香蕉']
# 方式3
categories = ["height","score","subject"]
codes = [0,1,0,2,1,0]
my\_data = pd.Categorical.from\_codes(codes, categories)
my\_data
['height', 'score', 'height', 'subject', 'score', 'height']
Categories (3, object): ['height', 'score', 'subject']
一般分类转换是不会指定类别的顺序,我们可以通过一个参数ordered来指定有有意义的顺序:
['height', 'score', 'height', 'subject', 'score', 'height']
Categories (3, object): ['height' < 'score' < 'subject']
上面的输出结果height<socre
,表明height的顺序在score的前面。如果某个分类实例未排序,我们使用as_ordered进行排序:
# my\_data未排序
my\_data.as\_ordered()
['height', 'score', 'height', 'subject', 'score', 'height']
Categories (3, object): ['height' < 'score' < 'subject']
np.random.seed(12345)
data1 = np.random.randn(100)
data1[:10]
array([-0.20470766, 0.47894334, -0.51943872, -0.5557303 , 1.96578057,
1.39340583, 0.09290788, 0.28174615, 0.76902257, 1.24643474])
# 计算data1的4分位分箱,并提取统计值
bins\_1 = pd.qcut(data1,4)
bins\_1
[(-0.717, 0.106], (0.106, 0.761], (-0.717, 0.106], (-0.717, 0.106], (0.761, 3.249], ..., (0.761, 3.249], (0.106, 0.761], (-2.371, -0.717], (0.106, 0.761], (0.106, 0.761]]
Length: 100
Categories (4, interval[float64]): [(-2.371, -0.717] < (-0.717, 0.106] < (0.106, 0.761] < (0.761, 3.249]]
可以看到上面的结果返回的值Categories对象
# 在上面的4分位数中使用四分位数名称:Q1\Q2\Q3\Q4
bins\_2 = pd.qcut(data1,4,labels=["Q1","Q2","Q3","Q4"])
bins\_2
['Q2', 'Q3', 'Q2', 'Q2', 'Q4', ..., 'Q4', 'Q3', 'Q1', 'Q3', 'Q3']
Length: 100
Categories (4, object): ['Q1' < 'Q2' < 'Q3' < 'Q4']
bins\_2.codes[:10]
array([1, 2, 1, 1, 3, 3, 1, 2, 3, 3], dtype=int8)
统计groupby来进行汇总统计:
bins\_2 = pd.Series(bins\_2, name="quartile") # 取名为quartile
bins\_2
0 Q2
1 Q3
2 Q2
3 Q2
4 Q4
..
95 Q4
96 Q3
97 Q1
98 Q3
99 Q3
Name: quartile, Length: 100, dtype: category
Categories (4, object): ['Q1' < 'Q2' < 'Q3' < 'Q4']
下面的代码示例是对data1的数据通过bins_2进行分组,生成3个统计函数
results = pd.Series(data1).groupby(bins\_2).agg(["count","min","max"]).reset\_index()
results
results["quartile"] # quartile列保持的原始分类信息
0 Q1
1 Q2
2 Q3
3 Q4
Name: quartile, dtype: category
Categories (4, object): ['Q1' < 'Q2' < 'Q3' < 'Q4']
N = 10000000 # 千万的数据
data3 = pd.Series(np.random.randn(N))
labels3 = pd.Series(["foo", "bar", "baz", "quz"] \* (N // 4))
categories3 = labels3.astype("category") # 分类转换
# 比较两个的内存
print("data3: ",data3.memory\_usage())
print("categories3: ",categories3.memory\_usage())
data3: 80000128
categories3: 10000332
分类方法主要是通过特殊属性cat来实现
data
0 语文
1 数学
2 英语
3 数学
4 英语
5 地理
6 语文
7 语文
dtype: object
cat\_data = data.astype("category")
cat\_data # 分类数据
0 语文
1 数学
2 英语
3 数学
4 英语
5 地理
6 语文
7 语文
dtype: category
Categories (4, object): ['地理', '数学', '英语', '语文']
当实际数据的类别超过了数据中观察到的4个数值:
actual\_cat = ["语文","数学","英语","地理","生物"]
cat\_data2 = cat\_data.cat.set\_categories(actual\_cat)
cat\_data2
上面的分类结果中就出现了"生物"
cat\_data.value\_counts()
语文 3
数学 2
英语 2
地理 1
dtype: int64
cat\_data2.value\_counts() # 下面的结果中出现了“生物”
语文 3
数学 2
英语 2
地理 1
生物 0
dtype: int64
cat\_data3 = cat\_data[cat\_data.isin(["语文","数学"])] # 只筛选出语文和数学
cat\_data3
0 语文
1 数学
3 数学
6 语文
7 语文
dtype: category
Categories (4, object): ['地理', '数学', '英语', '语文']
cat\_data3.cat.remove\_unused\_categories() # 删除未使用的分类
0 语文
1 数学
3 数学
6 语文
7 语文
dtype: category
Categories (2, object): ['数学', '语文']
将分类数据转成虚拟变量,也就是one-hot编码(独热码);产生的DataFrame中不同的类别都是它的一列,看下面的例子:
data4 = pd.Series(["col1","col2","col3","col4"] \* 2, dtype="category")
data4
0 col1
1 col2
2 col3
3 col4
4 col1
5 col2
6 col3
7 col4
dtype: category
Categories (4, object): ['col1', 'col2', 'col3', 'col4']
pd.get\_dummies(data4) # get\_dummies:将一维的分类数据转换成一个包含虚拟变量的DataFrame
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。