当前位置:   article > 正文

图解Pandas中的数据分类_pandas对表内数据分类储存到数组

pandas对表内数据分类储存到数组

公众号:尤而小屋
作者:Peter
编辑:Peter

大家好,我是Peter~

本文中介绍的是Categorical类型,主要实现的数据分类问题,用于承载基于整数的类别展示或编码的数据,帮助使用者获得更好的性能和内存使用。

背景:统计重复值

在一个Series数据中经常会出现重复值,我们需要提取这些不同的值并且分别计算它们的频数:

import numpy as np
import pandas as pd
  • 1
  • 2
'
运行
data = pd.Series(["语文","数学","英语","数学","英语","地理","语文","语文"])
data
  • 1
  • 2
0    语文
1    数学
2    英语
3    数学
4    英语
5    地理
6    语文
7    语文
dtype: object
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
# 1、提取不同的值

pd.unique(data)
  • 1
  • 2
  • 3
array(['语文', '数学', '英语', '地理'], dtype=object)
  • 1
# 2、统计每个值的个数

pd.value_counts(data)
  • 1
  • 2
  • 3
语文    3
数学    2
英语    2
地理    1
dtype: int64
  • 1
  • 2
  • 3
  • 4
  • 5

分类、字典编码

通过整数展现的方式,被称作分类或者字典编码。不同的数组可以称之为数据的类别、字典或者层级

df = pd.Series([0,1,1,0] * 2)
df
  • 1
  • 2
0    0
1    1
2    1
3    0
4    0
5    1
6    1
7    0
dtype: int64
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
# dim使用维度表

dim = pd.Series(["语文","数学"])
dim
  • 1
  • 2
  • 3
  • 4
0    语文
1    数学
dtype: object
  • 1
  • 2
  • 3

如何将0-语文,1-数学在df进行一一对应呢?使用take方法来实现

df1 = dim.take(df)
df1
  • 1
  • 2
0    语文
1    数学
1    数学
0    语文
0    语文
1    数学
1    数学
0    语文
dtype: object
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
type(df1)  # Series数据
  • 1
pandas.core.series.Series
  • 1

Categorical类型创建

生成一个Categorical实例对象

通过例子来讲解Categorical类型的使用

subjects = ["语文","数学","语文","语文"] * 2

N = len(subjects)
  • 1
  • 2
  • 3
'
运行
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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

可以将subject转成Categorical类型:

subject_cat = df2["subject"].astype("category")
subject_cat
  • 1
  • 2

我们发现了subject_cat的两个特点:

  • 它不是numpy数组,而是一个category数据类型
  • 它里面有两个取值:语文和数学
s = subject_cat.values
s
  • 1
  • 2
['语文', '数学', '语文', '语文', '语文', '数学', '语文', '语文']
Categories (2, object): ['数学', '语文']
  • 1
  • 2
type(s)
  • 1
pandas.core.arrays.categorical.Categorical
  • 1
s.categories  # 查看分类
  • 1
Index(['数学', '语文'], dtype='object')
  • 1
s.codes  # 查看分类编码
  • 1
array([1, 0, 1, 1, 1, 0, 1, 1], dtype=int8)
  • 1

如何生成Categorical对象

主要是两种方式:

  • 指定DataFrame的一列为Categorical对象
  • 通过pandas.Categorical来生成
  • 通过构造函数from_codes,前提是你必须先获得分类编码数据
# 方式1

df2["subject"] = df2["subject"].astype("category")
df2.subject
  • 1
  • 2
  • 3
  • 4
0    语文
1    数学
2    语文
3    语文
4    语文
5    数学
6    语文
7    语文
Name: subject, dtype: category
Categories (2, object): ['数学', '语文']
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
# 方式2

fruit = pd.Categorical(["苹果","香蕉","葡萄","苹果","苹果","香蕉"])
fruit
  • 1
  • 2
  • 3
  • 4
['苹果', '香蕉', '葡萄', '苹果', '苹果', '香蕉']
Categories (3, object): ['苹果', '葡萄', '香蕉']
  • 1
  • 2
# 方式3

categories = ["height","score","subject"]
codes = [0,1,0,2,1,0]

my_data = pd.Categorical.from_codes(codes, categories)
my_data
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
['height', 'score', 'height', 'subject', 'score', 'height']
Categories (3, object): ['height', 'score', 'subject']
  • 1
  • 2

一般分类转换是不会指定类别的顺序,我们可以通过一个参数ordered来指定有有意义的顺序:

['height', 'score', 'height', 'subject', 'score', 'height']
Categories (3, object): ['height' < 'score' < 'subject']
  • 1
  • 2

上面的输出结果height<socre,表明height的顺序在score的前面。如果某个分类实例未排序,我们使用as_ordered进行排序:

# my_data未排序

my_data.as_ordered()
  • 1
  • 2
  • 3
['height', 'score', 'height', 'subject', 'score', 'height']
Categories (3, object): ['height' < 'score' < 'subject']
  • 1
  • 2

Categorical对象计算

统计计算

np.random.seed(12345)

data1 = np.random.randn(100)
data1[:10]
  • 1
  • 2
  • 3
  • 4
array([-0.20470766,  0.47894334, -0.51943872, -0.5557303 ,  1.96578057,
        1.39340583,  0.09290788,  0.28174615,  0.76902257,  1.24643474])
  • 1
  • 2
# 计算data1的4分位分箱,并提取统计值

bins_1 = pd.qcut(data1,4)
bins_1
  • 1
  • 2
  • 3
  • 4
[(-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]]
  • 1
  • 2
  • 3

可以看到上面的结果返回的值Categories对象

  • 有4种取值情况
  • 看到整个数据的最大值和最小值分别在头尾部
# 在上面的4分位数中使用四分位数名称:Q1\Q2\Q3\Q4

bins_2 = pd.qcut(data1,4,labels=["Q1","Q2","Q3","Q4"])
bins_2
  • 1
  • 2
  • 3
  • 4
['Q2', 'Q3', 'Q2', 'Q2', 'Q4', ..., 'Q4', 'Q3', 'Q1', 'Q3', 'Q3']
Length: 100
Categories (4, object): ['Q1' < 'Q2' < 'Q3' < 'Q4']
  • 1
  • 2
  • 3
bins_2.codes[:10]
  • 1
array([1, 2, 1, 1, 3, 3, 1, 2, 3, 3], dtype=int8)
  • 1

统计groupby来进行汇总统计:

bins_2 = pd.Series(bins_2, name="quartile")  # 取名为quartile
bins_2
  • 1
  • 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']
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

下面的代码示例是对data1的数据通过bins_2进行分组,生成3个统计函数

results = pd.Series(data1).groupby(bins_2).agg(["count","min","max"]).reset_index()
results
  • 1
  • 2

results["quartile"] # quartile列保持的原始分类信息
  • 1
0    Q1
1    Q2
2    Q3
3    Q4
Name: quartile, dtype: category
Categories (4, object): ['Q1' < 'Q2' < 'Q3' < 'Q4']
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

分类后内存减少

N = 10000000  # 千万的数据

data3 = pd.Series(np.random.randn(N))
labels3 = pd.Series(["foo", "bar", "baz", "quz"] * (N // 4))
  • 1
  • 2
  • 3
  • 4
categories3 = labels3.astype("category")  # 分类转换
  • 1
# 比较两个的内存

print("data3: ",data3.memory_usage())
print("categories3: ",categories3.memory_usage())
  • 1
  • 2
  • 3
  • 4
data3:  80000128
categories3:  10000332
  • 1
  • 2

分类方法

访问分类信息

分类方法主要是通过特殊属性cat来实现

data
  • 1
0    语文
1    数学
2    英语
3    数学
4    英语
5    地理
6    语文
7    语文
dtype: object
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
cat_data = data.astype("category")
cat_data  # 分类数据
  • 1
  • 2
0    语文
1    数学
2    英语
3    数学
4    英语
5    地理
6    语文
7    语文
dtype: category
Categories (4, object): ['地理', '数学', '英语', '语文']
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

新增分类

当实际数据的类别超过了数据中观察到的4个数值:

actual_cat = ["语文","数学","英语","地理","生物"]

cat_data2 = cat_data.cat.set_categories(actual_cat)
cat_data2
  • 1
  • 2
  • 3
  • 4

上面的分类结果中就出现了"生物"

cat_data.value_counts()
  • 1
语文    3
数学    2
英语    2
地理    1
dtype: int64
  • 1
  • 2
  • 3
  • 4
  • 5
cat_data2.value_counts()  # 下面的结果中出现了“生物”
  • 1
语文    3
数学    2
英语    2
地理    1
生物    0
dtype: int64
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

删除分类

cat_data3 = cat_data[cat_data.isin(["语文","数学"])]  # 只筛选出语文和数学

cat_data3
  • 1
  • 2
  • 3
0    语文
1    数学
3    数学
6    语文
7    语文
dtype: category
Categories (4, object): ['地理', '数学', '英语', '语文']
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
cat_data3.cat.remove_unused_categories()  # 删除未使用的分类
  • 1
0    语文
1    数学
3    数学
6    语文
7    语文
dtype: category
Categories (2, object): ['数学', '语文']
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

创建虚拟变量

将分类数据转成虚拟变量,也就是one-hot编码(独热码);产生的DataFrame中不同的类别都是它的一列,看下面的例子:

data4 = pd.Series(["col1","col2","col3","col4"] * 2, dtype="category")
data4
  • 1
  • 2
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']
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
pd.get_dummies(data4)  # get_dummies:将一维的分类数据转换成一个包含虚拟变量的DataFrame
  • 1

分类方法

  • add_categories:添加新的分类到尾部
  • as_ordered:类别排序
  • as_unordered:使类别无序
  • remove_categories:去除类别,将被移除的值置为null
  • remove_unused_categories:去除所有未出现的类别
  • rename_categories:替换分类名,不改变分类的数量
  • reorder_categories:类进行排序
  • set_categories:用指定的一组新类替换原来的类,可以添加或者删除
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/寸_铁/article/detail/949952
推荐阅读
相关标签
  

闽ICP备14008679号