Pandas的应用-1

Pandas是Wes McKinney在2008年开发的一个强大的分析结构化数据的工具集。Pandas以NumPy为基础(数据表示和运算),提供了用于数据处理的函数和方法,对数据分析和数据挖掘提供了很好的支持;同时Pandas还可以跟数据可视化工具Matplotlib很好的整合在一起,非常轻松愉快的实现数据的可视化展示。

Pandas核心的数据类型是Series(数据系列)、DataFrame(数据表/数据框),分别用于处理一维和二维的数据,除此之外还有一个名为Index的类型及其子类型,它为SeriesDataFrame提供了索引功能。日常工作中以DataFrame使用最为广泛,因为二维的数据本质就是一个有行有列的表格(想一想Excel电子表格和关系型数据库中的二维表)。上述这些类型都提供了大量的处理数据的方法,数据分析师可以以此为基础实现对数据的各种常规处理。

Series的应用

Pandas库中的Series对象可以用来表示一维数据结构,跟数组非常类似,但是多了一些额外的功能。Series的内部结构包含了两个数组,其中一个用来保存数据,另一个用来保存数据的索引。

创建Series对象

提示:在执行下面的代码之前,请先导入pandas以及相关的库文件,具体的做法可以参考上一章。

方法1:通过列表或数组创建Series对象

代码:

  1. # data参数表示数据,index参数表示数据的索引(标签)
  2. # 如果没有指定index属性,默认使用数字索引
  3. ser1 = pd.Series(data=[320, 180, 300, 405], index=['一季度', '二季度', '三季度', '四季度'])
  4. ser1

输出:

  1. 一季度 320
  2. 二季度 180
  3. 三季度 300
  4. 四季度 405
  5. dtype: int64

方法2:通过字典创建Series对象。

代码:

  1. # 字典中的键就是数据的索引(标签),字典中的值就是数据
  2. ser2 = pd.Series({'一季度': 320, '二季度': 180, '三季度': 300, '四季度': 405})
  3. ser2

输出:

  1. 一季度 320
  2. 二季度 180
  3. 三季度 300
  4. 四季度 405
  5. dtype: int64

索引和切片

跟数组一样,Series对象也可以进行索引和切片操作,不同的是Series对象因为内部维护了一个保存索引的数组,所以除了可以使用整数索引通过位置检索数据外,还可以通过自己设置的索引标签获取对应的数据。

使用整数索引

代码:

  1. print(ser2[0], ser[1], ser[2], ser[3])
  2. ser2[0], ser2[3] = 350, 360
  3. print(ser2)

输出:

  1. 320 180 300 405
  2. 一季度 350
  3. 二季度 180
  4. 三季度 300
  5. 四季度 360
  6. dtype: int64

提示:如果要使用负向索引,必须在创建Series对象时通过index属性指定非数值类型的标签。

使用自定义的标签索引

代码:

  1. print(ser2['一季度'], ser2['三季度'])
  2. ser2['一季度'] = 380
  3. print(ser2)

输出:

  1. 350 300
  2. 一季度 380
  3. 二季度 180
  4. 三季度 300
  5. 四季度 360
  6. dtype: int64

切片操作

代码:

  1. print(ser2[1:3])
  2. print(ser2['二季度':'四季度'])

输出:

  1. 二季度 180
  2. 三季度 300
  3. dtype: int64
  4. 二季度 500
  5. 三季度 500
  6. 四季度 520
  7. dtype: int64

代码:

  1. ser2[1:3] = 400, 500
  2. ser2

输出:

  1. 一季度 380
  2. 二季度 400
  3. 三季度 500
  4. 四季度 360
  5. dtype: int64

花式索引

代码:

  1. print(ser2[['二季度', '四季度']])
  2. ser2[['二季度', '四季度']] = 500, 520
  3. print(ser2)

输出:

  1. 二季度 400
  2. 四季度 360
  3. dtype: int64
  4. 一季度 380
  5. 二季度 500
  6. 三季度 500
  7. 四季度 520
  8. dtype: int64

布尔索引

代码:

  1. ser2[ser2 >= 500]

输出:

  1. 二季度 500
  2. 三季度 500
  3. 四季度 520
  4. dtype: int64

属性和方法

Series对象的常用属性如下表所示。

属性 说明
dtype / dtypes 返回Series对象的数据类型
hasnans 判断Series对象中有没有空值
at / iat 通过索引访问Series对象中的单个值
loc / iloc 通过一组索引访问Series对象中的一组值
index 返回Series对象的索引
is_monotonic 判断Series对象中的数据是否单调
is_monotonic_increasing 判断Series对象中的数据是否单调递增
is_monotonic_decreasing 判断Series对象中的数据是否单调递减
is_unique 判断Series对象中的数据是否独一无二
size 返回Series对象中元素的个数
values ndarray的方式返回Series对象中的值

Series对象的方法很多,我们通过下面的代码为大家介绍一些常用的方法。

统计相关的方法

Series对象支持各种获取描述性统计信息的方法。

代码:

  1. # 求和
  2. print(ser2.sum())
  3. # 求均值
  4. print(ser2.mean())
  5. # 求最大
  6. print(ser2.max())
  7. # 求最小
  8. print(ser2.min())
  9. # 计数
  10. print(ser2.count())
  11. # 求标准差
  12. print(ser2.std())
  13. # 求方差
  14. print(ser2.var())
  15. # 求中位数
  16. print(ser2.median())

Series对象还有一个名为describe()的方法,可以获得上述所有的描述性统计信息,如下所示。

代码:

  1. ser2.describe()

输出:

  1. count 4.000000
  2. mean 475.000000
  3. std 64.031242
  4. min 380.000000
  5. 25% 470.000000
  6. 50% 500.000000
  7. 75% 505.000000
  8. max 520.000000
  9. dtype: float64

提示:因为describe()返回的也是一个Series对象,所以也可以用ser2.describe()['mean']来获取平均值。

如果Series对象有重复的值,我们可以使用unique()方法获得去重之后的Series对象;可以使用nunique()方法统计不重复值的数量;如果想要统计每个值重复的次数,可以使用value_counts()方法,这个方法会返回一个Series对象,它的索引就是原来的Series对象中的值,而每个值出现的次数就是返回的Series对象中的数据,在默认情况下会按照出现次数做降序排列。

代码:

  1. ser3 = pd.Series(data=['apple', 'banana', 'apple', 'pitaya', 'apple', 'pitaya', 'durian'])
  2. ser3.value_counts()

输出:

  1. apple 3
  2. pitaya 2
  3. durian 1
  4. banana 1
  5. dtype: int64

代码:

  1. ser3.nunique()

输出:

  1. 4

数据处理的方法

Series对象的isnull()notnull()方法可以用于空值的判断,代码如下所示。

代码:

  1. ser4 = pd.Series(data=[10, 20, np.NaN, 30, np.NaN])
  2. ser4.isnull()

输出:

  1. 0 False
  2. 1 False
  3. 2 True
  4. 3 False
  5. 4 True
  6. dtype: bool

代码:

  1. ser4.notnull()

输出:

  1. 0 True
  2. 1 True
  3. 2 False
  4. 3 True
  5. 4 False
  6. dtype: bool

Series对象的dropna()fillna()方法分别用来删除空值和填充空值,具体的用法如下所示。

代码:

  1. ser4.dropna()

输出:

  1. 0 10.0
  2. 1 20.0
  3. 3 30.0
  4. dtype: float64

代码:

  1. # 将空值填充为40
  2. ser4.fillna(value=40)

输出:

  1. 0 10.0
  2. 1 20.0
  3. 2 40.0
  4. 3 30.0
  5. 4 40.0
  6. dtype: float64

代码:

  1. # backfill或bfill表示用后一个元素的值填充空值
  2. # ffill或pad表示用前一个元素的值填充空值
  3. ser4.fillna(method='ffill')

输出:

  1. 0 10.0
  2. 1 20.0
  3. 2 20.0
  4. 3 30.0
  5. 4 30.0
  6. dtype: float64

需要提醒大家注意的是,dropna()fillna()方法都有一个名为inplace的参数,它的默认值是False,表示删除空值或填充空值不会修改原来的Series对象,而是返回一个新的Series对象来表示删除或填充空值后的数据系列,如果将inplace参数的值修改为True,那么删除或填充空值会就地操作,直接修改原来的Series对象,那么方法的返回值是None。后面我们会接触到的很多方法,包括DataFrame对象的很多方法都会有这个参数,它们的意义跟这里是一样的。

Series对象的mask()where()方法可以将满足或不满足条件的值进行替换,如下所示。

代码:

  1. ser5 = pd.Series(range(5))
  2. ser5.where(ser5 > 0)

输出:

  1. 0 NaN
  2. 1 1.0
  3. 2 2.0
  4. 3 3.0
  5. 4 4.0
  6. dtype: float64

代码:

  1. ser5.where(ser5 > 1, 10)

输出:

  1. 0 10
  2. 1 10
  3. 2 2
  4. 3 3
  5. 4 4
  6. dtype: int64

代码:

  1. ser5.mask(ser5 > 1, 10)

输出:

  1. 0 0
  2. 1 1
  3. 2 10
  4. 3 10
  5. 4 10
  6. dtype: int64

Series对象的duplicated()方法可以帮助我们找出重复的数据,而drop_duplicates()方法可以帮我们删除重复数据。

代码:

  1. ser3.duplicated()

输出:

  1. 0 False
  2. 1 False
  3. 2 True
  4. 3 False
  5. 4 True
  6. 5 True
  7. 6 False
  8. dtype: bool

代码:

  1. ser3.drop_duplicates()

输出:

  1. 0 apple
  2. 1 banana
  3. 3 pitaya
  4. 6 durian
  5. dtype: object

Series对象的apply()map()方法非常重要,它们可以用于数据处理,把数据映射或转换成我们期望的样子,这个操作在数据分析的数据准备阶段非常重要。

代码:

  1. ser6 = pd.Series(['cat', 'dog', np.nan, 'rabbit'])
  2. ser6

输出:

  1. 0 cat
  2. 1 dog
  3. 2 NaN
  4. 3 rabbit
  5. dtype: object

代码:

  1. ser6.map({'cat': 'kitten', 'dog': 'puppy'})

输出:

  1. 0 kitten
  2. 1 puppy
  3. 2 NaN
  4. 3 NaN
  5. dtype: object

代码:

  1. ser6.map('I am a {}'.format, na_action='ignore')

输出:

  1. 0 I am a cat
  2. 1 I am a dog
  3. 2 NaN
  4. 3 I am a rabbit
  5. dtype: object

代码:

  1. ser7 = pd.Series([20, 21, 12], index=['London', 'New York', 'Helsinki'])
  2. ser7

输出:

  1. London 20
  2. New York 21
  3. Helsinki 12
  4. dtype: int64

代码:

  1. ser7.apply(np.square)

输出:

  1. London 400
  2. New York 441
  3. Helsinki 144
  4. dtype: int64

代码:

  1. ser7.apply(lambda x, value: x - value, args=(5, ))

输出:

  1. London 15
  2. New York 16
  3. Helsinki 7
  4. dtype: int64

排序和取头部值的方法

Series对象的sort_index()sort_values()方法可以用于对索引和数据的排序,排序方法有一个名为ascending的布尔类型参数,该参数用于控制排序的结果是升序还是降序;而名为kind的参数则用来控制排序使用的算法,默认使用了quicksort,也可以选择mergesortheapsort;如果存在空值,那么可以用na_position参数空值放在最前还是最后,默认是last,代码如下所示。

代码:

  1. ser8 = pd.Series(
  2. data=[35, 96, 12, 57, 25, 89],
  3. index=['grape', 'banana', 'pitaya', 'apple', 'peach', 'orange']
  4. )
  5. # 按值从小到大排序
  6. ser8.sort_values()

输出:

  1. pitaya 12
  2. peach 25
  3. grape 35
  4. apple 57
  5. orange 89
  6. banana 96
  7. dtype: int64

代码:

  1. # 按索引从大到小排序
  2. ser8.sort_index(ascending=False)

输出:

  1. pitaya 12
  2. peach 25
  3. orange 89
  4. grape 35
  5. banana 96
  6. apple 57
  7. dtype: int64

如果要从Series对象中找出元素中最大或最小的“Top-N”,实际上是不需要对所有的值进行排序的,可以使用nlargest()nsmallest()方法来完成,如下所示。

代码:

  1. # 值最大的3个
  2. ser8.nlargest(3)

输出:

  1. banana 96
  2. orange 89
  3. apple 57
  4. dtype: int64

代码:

  1. # 值最小的2个
  2. ser8.nsmallest(2)

输出:

  1. pitaya 12
  2. peach 25
  3. dtype: int64

绘制图表

Series对象有一个名为plot的方法可以用来生成图表,如果选择生成折线图、饼图、柱状图等,默认会使用Series对象的索引作为横坐标,使用Series对象的数据作为纵坐标。

首先导入matplotlibpyplot模块并进行必要的配置。

  1. import matplotlib.pyplot as plt
  2. # 配置支持中文的非衬线字体(默认的字体无法显示中文)
  3. plt.rcParams['font.sans-serif'] = ['SimHei', ]
  4. # 使用指定的中文字体时需要下面的配置来避免负号无法显示
  5. plt.rcParams['axes.unicode_minus'] = False

创建Series对象并绘制对应的柱状图。

  1. ser9 = pd.Series({'一季度': 400, '二季度': 520, '三季度': 180, '四季度': 380})
  2. # 通过Series对象的plot方法绘图(kind='bar'表示绘制柱状图)
  3. ser9.plot(kind='bar', color=['r', 'g', 'b', 'y'])
  4. # x轴的坐标旋转到0度(中文水平显示)
  5. plt.xticks(rotation=0)
  6. # 在柱状图的柱子上绘制数字
  7. for i in range(4):
  8. plt.text(i, ser9[i] + 5, ser9[i], ha='center')
  9. # 显示图像
  10. plt.show()

70.Pandas的应用-1 - 图1

绘制反映每个季度占比的饼图。

  1. # autopct参数可以配置在饼图上显示每块饼的占比
  2. ser9.plot(kind='pie', autopct='%.1f%%')
  3. # 设置y轴的标签(显示在饼图左侧的文字)
  4. plt.ylabel('各季度占比')
  5. plt.show()

70.Pandas的应用-1 - 图2