Pandas快速入门教程

104 阅读26分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情。

Pandas快速入门教程

Pandas 快速入门教程

思维导图

modao.cc/mind/share/… 在这里插入图片描述

介绍

Pandas 是基于 NumPy 的非常著名的开源数据处理库,该工具是为解决数据分析任务而创建的。 Pandas 纳入了大量库和一些标准的数据模型,提供了高效地操作大型数据集所需的工具。pandas提供了大量能使我们快速便捷地处理数据的函数和方法。我们可以通过它完成对数据集进行快速读取、转换、过滤、分析等一系列操作。除此之外,Pandas 拥有强大的缺失数据处理与数据透视功能,可谓是数据预处理中的必备利器。Pandas被誉数据处理的”瑞士军刀“

知识点

  • 数据类型

  • 数据读取

  • 数据选择

  • 数据删减

  • 数据填充

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R16RNndp-1630489618564)(doc.shiyanlou.com/courses/uid…)]

Pandas 是非常著名的开源数据处理库,基于 NumPy 开发 ,该工具是 Scipy 生态中为了解决数据分析 任务而设计。Pandas 纳入了大量库和一些标准的数据模型,提供了高效地操作大型数据集所需的函数和方法。

特有的数据结构是 Pandas 的优势和核心。简单来讲,我们可以将任意格式的数据转换为 Pandas 的数据类型,并使用 Pandas 提供的一系列方法进行转换、操作,最终得到我们期望的结果。

所以,我们首先需要了解并熟悉 Pandas 支持的数据类型。

数据类型

Pandas 的数据类型主要有以下几种,它们分别是:Series(一维数组),DataFrame(二维数组),Panel(三维数组),Panel4D(四维数组),PanelND(更多维数组)。其中 Series 和 DataFrame 应用的最为广泛,几乎占据了使用频率 90% 以上。

Series

Series 是 Pandas 中最基本的一维数组形式。其可以储存整数、浮点数、字符串等类型的数据。Series 基本结构如下:

pandas.Series(data=None, index=None)

其中,data 可以是字典,或者NumPy 里的 ndarray 对象等。

index 是数据索引,索引是 Pandas 数据结构中的一大特性,它主要的功能是帮助我们更快速地定位数据。

下面,我们基于 Python 字典新建一个示例 Series。

%matplotlib inline  
import pandas as pd

s = pd.Series({'a': 10, 'b': 20, 'c': 30})
s
a    10
b    20
c    30
dtype: int64

如上所示,该 Series 的数据值是 10, 20, 30,索引为 a, b, c,数据值的类型默认识别为 int64。你可以通过 type 来确认 s 的类型。

type(s)
pandas.core.series.Series

由于 Pandas 基于 NumPy 开发 。那么 NumPy 的数据类型 ndarray 多维数组自然就可以转换为 Pandas 中的数据。而 Series 则可以基于 NumPy 中的一维数据转换。

import numpy as np

s = pd.Series(np.random.randn(5))
s
0    1.048190
1    1.104182
2   -0.109292
3    0.967202
4   -0.928208
dtype: float64

⚠️可见Series可以理解为一个更加复杂的字典

如上所示,我们给出了 NumPy 生成的一维随机数组,最终得到的 Series 索引默认从 0 开始,而数值类型为 float64

DataFrame

DataFrame 是 Pandas 中最为常见、最重要且使用频率最高的数据结构 。DataFrame 和平常的电子表格或 SQL 表结构相似。你可以把 DataFrame 看成是 Series 的扩展类型,它仿佛是由多个 Series 拼合而成。它和 Series 的直观区别在于,数据不但具有行索引,且具有列索引。

img

来源

DataFrame 基本结构如下:

pandas.DataFrame(data=None, index=None, columns=None)

区别于 Series,其增加了 columns 列索引。DataFrame 可以由以下多个类型的数据构建:

  • 一维数组、列表、字典或者 Series 字典。

  • 二维或者结构化的 numpy.ndarray

  • 一个 Series 或者另一个 DataFrame。

例如,我们首先使用一个由 Series 组成的字典来构建 DataFrame。

df = pd.DataFrame({'one': pd.Series([1, 2, 3]),
                   'two': pd.Series([4, 5, 6])})                 
df
onetwo
014
125
236

当不指定索引时,DataFrame 的索引同样是从 0 开始。我们也可以直接通过一个列表构成的字典来生成 DataFrame。

df = pd.DataFrame({'one': [1, 2, 3],
                   'two': [4, 5, 6]})
df
onetwo
014
125
236

或者反过来,由带字典的列表生成 DataFrame。

df = pd.DataFrame([{'one': 1, 'two': 4},
                   {'one': 2, 'two': 5},
                   {'one': 3, 'two': 6}])
df

onetwo
014
125
236

NumPy 的多维数组非常常用,同样可以基于二维数值来构建一个 DataFrame。

pd.DataFrame(np.random.randint(5, size=(2, 4)))
0123
02341
10140

至此,你应该已经清楚了 Pandas 常用的 Series 和 DataFrame 数据类型。Series 实际上可以被看出是只有 1 列数据的 DataFrame 。当然,这个说法不严谨,二者的核心区别仍然是 Series 没有列索引 。你可以观察如下所示由 NumPy 一维随机数组生成的 Series 和 DataFrame。

pd.Series(np.arange(1, 6))
0    1
1    2
2    3
3    4
4    5
dtype: int64
pd.DataFrame(np.arange(1, 6)) #可见DataFrame就是比Series多了一个列索引
   0
0  1
1  2
2  3
3  4
4  5

关于 Pandas 中的 Panel (三维数据结构) 等数据类型我们就不再介绍。首先是这些数据类型用的很少(其实已经被弃用),其次就算你用到了,也可以通过从 DataFrame 等学到的技巧进行迁移应用,万变不离其宗。

数据读取

使用 Pandas 来分析数据的第一步是读取数据 。大多数情况下,数据都来源于外部的数据文件或者数据库。Pandas 提供了一系列的方法来读取外部数据 。下面,我们以最常用的 CSV 数据文件为例进行介绍。

读取数据 CSV 文件的方法是 pandas.read_csv(),你可以直接传入一个相对路径,或者是网络 URL。

df = pd.read_csv("https://labfile.oss.aliyuncs.com/courses/906/los_census.csv")
df
Zip CodeTotal PopulationMedian AgeTotal MalesTotal FemalesTotal HouseholdsAverage Household Size
091371173.50111.00
1900015711026.62846828642129714.40
2900025122325.52487626347117314.36
3900036626626.33263133635156424.22
4900046218034.83130230878225472.73
........................
314935523815828.4187111944796903.93
31593553213843.3112110178162.62
316935601891032.49491941964692.92
3179356338844.52631251032.53
31893591728530.93653363219823.67

319 rows × 7 columns

CSV 存储时是一个二维表格(类似excel),Pandas 会自动将其读取为 DataFrame 类型。

不管是什么类型的的数据,在处理前都需要将其转换为 DataFrame 或者 Series 数据类型 ,因为只有 Series 或者 DataFrame 才能使用 Pandas 提供的方法和函数进行处理。

pd.read_ 前缀开始的方法还可以读取各式各样的数据文件、数据库。可以阅读 官方文档相应章节 熟悉这些方法以及搞清楚这些方法包含的参数。

DataFrame与Series的常用操作

通过上面的内容,我们已经知道一个 DataFrame 结构大致由 3 部分组成,它们分别是列名称、索引和数据。

来源

DataFrame 上的大多数操作方法和技巧都同样适用于 Series ,所以主要学习 DataFrame即可。

我们已经读取了一个洛杉矶的人口普查数据,下面是一些常用操作:

df.head()  # 默认显示前 5 条,也可传入参数指定显示数目
Zip CodeTotal PopulationMedian AgeTotal MalesTotal FemalesTotal HouseholdsAverage Household Size
091371173.50111.00
1900015711026.62846828642129714.40
2900025122325.52487626347117314.36
3900036626626.33263133635156424.22
4900046218034.83130230878225472.73
df.tail(7)  # 指定显示后 7 条
Zip CodeTotal PopulationMedian AgeTotal MalesTotal FemalesTotal HouseholdsAverage Household Size
312935507492927.53641438515208643.58
313935515079837.02505625742159633.18
314935523815828.4187111944796903.93
31593553213843.3112110178162.62
316935601891032.49491941964692.92
3179356338844.52631251032.53
31893591728530.93653363219823.67

Pandas 还提供了统计和描述性方法,方便你从宏观的角度去了解数据集。describe() 相当于对数据集进行概览,会输出该数据集每一列数据的计数、最大值、最小值等。

df.describe()
Zip CodeTotal PopulationMedian AgeTotal MalesTotal FemalesTotal HouseholdsAverage Household Size
count319.000000319.000000319.000000319.000000319.000000319.000000319.000000
mean91000.67398133241.34169336.52758616391.56426316849.77742910964.5705332.828119
std908.36020321644.4174558.69299910747.49556610934.9864686270.6464000.835658
min90001.0000000.0000000.0000000.0000000.0000000.0000000.000000
25%90243.50000019318.50000032.4000009763.5000009633.5000006765.5000002.435000
50%90807.00000031481.00000037.10000015283.00000016202.00000010968.0000002.830000
75%91417.00000044978.00000041.00000022219.50000022690.50000014889.5000003.320000
max93591.000000105549.00000074.00000052794.00000053185.00000031087.0000004.670000

Pandas 基于 NumPy 开发,所以任何时候你都可以通过 .values 将 DataFrame 转换为 NumPy 数组。

df.values
array([[9.1371e+04, 1.0000e+00, 7.3500e+01, ..., 1.0000e+00, 1.0000e+00,        1.0000e+00],       [9.0001e+04, 5.7110e+04, 2.6600e+01, ..., 2.8642e+04, 1.2971e+04,        4.4000e+00],       [9.0002e+04, 5.1223e+04, 2.5500e+01, ..., 2.6347e+04, 1.1731e+04,        4.3600e+00],       ...,       [9.3560e+04, 1.8910e+04, 3.2400e+01, ..., 9.4190e+03, 6.4690e+03,        2.9200e+00],       [9.3563e+04, 3.8800e+02, 4.4500e+01, ..., 1.2500e+02, 1.0300e+02,        2.5300e+00],       [9.3591e+04, 7.2850e+03, 3.0900e+01, ..., 3.6320e+03, 1.9820e+03,        3.6700e+00]])

这也就说明可以同时使用 Pandas 和 NumPy 提供的 API 对同一数据进行操作,并在二者之间进行随意转换 。这两者都是Python非常灵活的工具生态圈。

除了 .values,DataFrame 支持的常见属性可以通过 官方文档相应章节 查看。其中常用的有:

df.index  # 查看索引
RangeIndex(start=0, stop=319, step=1)
df.columns  # 查看列名
Index(['Zip Code', 'Total Population', 'Median Age', 'Total Males',
       'Total Females', 'Total Households', 'Average Household Size'],
      dtype='object')
df.shape  # 查看形状
(319, 7)

数据选择

在数据预处理过程中,我们往往会对数据集进行切分,只将需要的某些行、列,或者数据块保留下来,输出到下一个流程中去。这也就是所谓的数据选择,或者数据索引。

由于 Pandas 的数据结构中存在索引、标签,所以我们可以通过多轴索引完成对数据的选择。

基于索引数字选择

当我们新建一个 DataFrame 之后,如果未自己指定行索引或者列对应的标签,那么 Pandas 会默认从 0 开始以数字的形式作为行索引,并以数据集的第一行作为列对应的标签。其实,这里的「列」也有数字索引,默认也是从 0 开始,只是未显示出来。

所以,我们首先可以基于数字索引对数据集进行选择。这里用到的 Pandas 中的 .iloc 方法。该方法可以接受的类型有:

  1. 整数。例如:5

  2. 整数构成的列表或数组。例如:[1, 2, 3]

  3. 布尔数组。

  4. 可返回索引值的函数或参数。

下面,我们使用上方的示例数据进行演示。

首先,我们可以选择前 3 行数据。这和 Python 或者 NumPy 里面的切片很相似。

df.iloc[:3] # 选择前3行
Zip CodeTotal PopulationMedian AgeTotal MalesTotal FemalesTotal HouseholdsAverage Household Size
091371173.50111.00
1900015711026.62846828642129714.40
2900025122325.52487626347117314.36

我们还可以选择特定的一行。

df.iloc[5] # 选择特定第5行
Zip Code                  90005.0
Total Population          37681.0
Median Age                   33.9
Total Males               19299.0
Total Females             18382.0
Total Households          15044.0
Average Household Size        2.5
Name: 5, dtype: float64

那么选择多行,是不是 df.iloc[1, 3, 5] 这样呢?

答案是错误的。df.iloc[][[行],[列]] 里面可以同时接受行和列的位置,如果你直接键入 df.iloc[1, 3, 5] 就会报错。

所以,很简单。如果你想要选择 1,3,5 行,可以这样做。

df.iloc[[1, 3, 5]] # 选择 1,3,5 行
# 或者写成 df.iloc[[1, 3, 5], :],后面可以省略
Zip CodeTotal PopulationMedian AgeTotal MalesTotal FemalesTotal HouseholdsAverage Household Size
1900015711026.62846828642129714.40
3900036626626.33263133635156424.22
5900053768133.91929918382150442.50

选择行学会以后,选择列就应该能想到怎么办了。例如,我们要选择第 2-4 列。

df.iloc[:, 1:4] # 索引从0开始,切片1~3才是实际的2~4
Total PopulationMedian AgeTotal Males
0173.50
15711026.628468
25122325.524876
36626626.332631
46218034.831302
............
3143815828.418711
315213843.31121
3161891032.49491
31738844.5263
318728530.93653

319 rows × 3 columns

这里选择 2-4 列,输入的却是 1:4。这和 Python 或者 NumPy 里面的切片操作非常相似。既然我们能定位行和列,那么只需要组合起来,我们就可以选择数据集中的任何数据了。

基于标签名称选择

除了根据数字索引选择,还可以直接根据标签对应的名称选择 (标签可以理解为行名或列名)。这里用到的方法和上面的 iloc 很相似,少了个 i 为 [df.loc]

df.loc[] 可以接受的类型有:

  1. 单个标签。例如:2'a'这里的 ** 2 指的是标签而不是索引位置** 。

  2. 列表或数组包含的标签。例如:['A', 'B', 'C']

  3. 切片对象。例如:'A':'E',注意这里和上面切片的不同之处,首尾都包含在内。

  4. 布尔数组。

  5. 可返回标签的函数或参数。

下面,我们来演示 df.loc[] 的用法。先选择前 3 行:

df.loc[0:2] # 选择前 3 行
Zip CodeTotal PopulationMedian AgeTotal MalesTotal FemalesTotal HouseholdsAverage Household Size
091371173.50111.00
1900015711026.62846828642129714.40
2900025122325.52487626347117314.36

再选择 1,3,5 行:

df.loc[[0, 2, 4]]
Zip CodeTotal PopulationMedian AgeTotal MalesTotal FemalesTotal HouseholdsAverage Household Size
091371173.50111.00
2900025122325.52487626347117314.36
4900046218034.83130230878225472.73

然后,选择 2-4 列:

df.loc[:, 'Total Population':'Total Males'] # 直接传入列名
Total PopulationMedian AgeTotal Males
0173.50
15711026.628468
25122325.524876
36626626.332631
46218034.831302
............
3143815828.418711
315213843.31121
3161891032.49491
31738844.5263
318728530.93653

319 rows × 3 columns

最后,选择 1,3 行和 Median Age 后面的列:

df.loc[[0, 2], 'Median Age':]
Median AgeTotal MalesTotal FemalesTotal HouseholdsAverage Household Size
073.50111.00
225.52487626347117314.36

数据删减

虽然我们可以通过数据选择方法从一个完整的数据集中拿到我们需要的数据,但有的时候直接删除不需要的数据更加简单直接。Pandas 中,以 ** .drop ** 开头的方法都与数据删减有关

DataFrame.drop 可以直接去掉数据集中指定的列和行。一般在使用时,我们指定 labels 标签参数,然后再通过 axis 指定按列或按行删除即可。当然,你也可以通过索引参数删除数据,具体查看官方文档。

df.drop(labels=['Median Age', 'Total Males'], axis=1)
Zip CodeTotal PopulationTotal FemalesTotal HouseholdsAverage Household Size
0913711111.00
1900015711028642129714.40
2900025122326347117314.36
3900036626633635156424.22
4900046218030878225472.73
..................
31493552381581944796903.93
31593553213810178162.62
3169356018910941964692.92
317935633881251032.53
318935917285363219823.67

319 rows × 5 columns

DataFrame.drop_duplicates 则通常用于数据去重,即剔除数据集中的重复值。使用方法非常简单,指定去除重复值规则,以及 axis 按列还是按行去除即可。

df.drop_duplicates()
Zip CodeTotal PopulationMedian AgeTotal MalesTotal FemalesTotal HouseholdsAverage Household Size
091371173.50111.00
1900015711026.62846828642129714.40
2900025122325.52487626347117314.36
3900036626626.33263133635156424.22
4900046218034.83130230878225472.73
........................
314935523815828.4187111944796903.93
31593553213843.3112110178162.62
316935601891032.49491941964692.92
3179356338844.52631251032.53
31893591728530.93653363219823.67

319 rows × 7 columns

除此之外,另一个用于数据删减的方法 DataFrame.dropna 也十分常用,其主要的用途是删除缺少值,即数据集中空缺的数据列或行。

df.dropna()
Zip CodeTotal PopulationMedian AgeTotal MalesTotal FemalesTotal HouseholdsAverage Household Size
091371173.50111.00
1900015711026.62846828642129714.40
2900025122325.52487626347117314.36
3900036626626.33263133635156424.22
4900046218034.83130230878225472.73
........................
314935523815828.4187111944796903.93
31593553213843.3112110178162.62
316935601891032.49491941964692.92
3179356338844.52631251032.53
31893591728530.93653363219823.67

319 rows × 7 columns

对于提到的这 3 个常用的数据删减方法,大家一定要通过给出的链接去阅读官方文档。这些常用方法没有太多需要注意的地方,通过文档了解其用法即可,所以我们也不会化简为繁地进行介绍。

数据填充

既然提到了数据删减,反之则可能会遇到数据填充的情况。而对于一个给定的数据集而言,我们一般不会乱填数据,而更多的是对缺失值进行填充。

在真实的生产环境中,我们需要处理的数据文件往往没有想象中的那么美好。其中,很大几率会遇到的情况就是缺失值。缺失值主要是指数据丢失的现象,也就是数据集中的某一块数据不存在。除此之外、存在但明显不正确的数据也被归为缺失值一类。例如,在一个时间序列数据集中,某一段数据突然发生了时间流错乱,那么这一小块数据就是毫无意义的,可以被归为缺失值。

缺失值填充

Pandas 为了更方便地检测缺失值,将不同类型数据的缺失均采用 NaN 标记。这里的 NaN 代表 Not a Number,它仅仅是作为一个标记。例外是,在时间序列里,时间戳的丢失采用 NaT 标记。

Pandas 中用于检测缺失值主要用到两个方法,分别是:isna()notna(),故名思意就是「是缺失值」和「不是缺失值」。默认会返回布尔值用于判断。

接下来,我们人为生成一组包含缺失值的示例数据。

df = pd.DataFrame(np.random.rand(9, 5), columns=list('ABCDE'))# 插入 T 列,并打上时间戳
df.insert(value=pd.Timestamp('2017-10-1'), loc=0, column='Time')# 将 1, 3, 5 列的 1,3,5,7 行置为缺失值
df.iloc[[1, 3, 5, 7], [0, 2, 4]] = np.nan# 将 2, 4, 6 列的 2,4,6,8 行置为缺失值
df.iloc[[2, 4, 6, 8], [1, 3, 5]] = np.nan
df
TimeABCDE
02017-10-010.9848820.0806090.1922260.7653500.576209
1NaT0.730057NaN0.938123NaN0.441354
22017-10-01NaN0.393606NaN0.392022NaN
3NaT0.326389NaN0.201245NaN0.671247
42017-10-01NaN0.981729NaN0.896415NaN
5NaT0.132100NaN0.733855NaN0.855810
62017-10-01NaN0.878830NaN0.844778NaN
7NaT0.305320NaN0.501641NaN0.918584
82017-10-01NaN0.014747NaN0.959077NaN

然后,通过 isna()notna() 中的一个即可确定数据集中的缺失值。

df.isna()
TimeABCDE
0FalseFalseFalseFalseFalseFalse
1TrueFalseTrueFalseTrueFalse
2FalseTrueFalseTrueFalseTrue
3TrueFalseTrueFalseTrueFalse
4FalseTrueFalseTrueFalseTrue
5TrueFalseTrueFalseTrueFalse
6FalseTrueFalseTrueFalseTrue
7TrueFalseTrueFalseTrueFalse
8FalseTrueFalseTrueFalseTrue

上面已经对缺省值的产生、检测进行了介绍。实际上,面对缺失值一般就是填充和剔除两项操作。填充和清除都是两个极端。如果你感觉有必要保留缺失值所在的列或行,那么就需要对缺失值进行填充。如果没有必要保留,就可以选择清除缺失值。

其中,缺失值剔除的方法 dropna() 已经在上面介绍过了。下面来看一看填充缺失值 fillna() 方法。

首先,我们可以用相同的标量值替换 NaN,比如用 0

df.fillna(0) # 使用0填充NaN
TimeABCDE
02017-10-01 00:00:000.9848820.0806090.1922260.7653500.576209
100.7300570.0000000.9381230.0000000.441354
22017-10-01 00:00:000.0000000.3936060.0000000.3920220.000000
300.3263890.0000000.2012450.0000000.671247
42017-10-01 00:00:000.0000000.9817290.0000000.8964150.000000
500.1321000.0000000.7338550.0000000.855810
62017-10-01 00:00:000.0000000.8788300.0000000.8447780.000000
700.3053200.0000000.5016410.0000000.918584
82017-10-01 00:00:000.0000000.0147470.0000000.9590770.000000

除了直接填充值,我们还可以通过参数,将缺失值前面或者后面的值填充给相应的缺失值。例如使用缺失值前面的值进行填充:

df.fillna(method='pad') #pad表示使用缺失值前面的值进行填充
TimeABCDE
02017-10-010.9848820.0806090.1922260.7653500.576209
12017-10-010.7300570.0806090.9381230.7653500.441354
22017-10-010.7300570.3936060.9381230.3920220.441354
32017-10-010.3263890.3936060.2012450.3920220.671247
42017-10-010.3263890.9817290.2012450.8964150.671247
52017-10-010.1321000.9817290.7338550.8964150.855810
62017-10-010.1321000.8788300.7338550.8447780.855810
72017-10-010.3053200.8788300.5016410.8447780.918584
82017-10-010.3053200.0147470.5016410.9590770.918584

或者是后面的值:

df.fillna(method='bfill') #bfill表示使用缺失值后面的值进行填充
TimeABCDE
02017-10-010.9848820.0806090.1922260.7653500.576209
12017-10-010.7300570.3936060.9381230.3920220.441354
22017-10-010.3263890.3936060.2012450.3920220.671247
32017-10-010.3263890.9817290.2012450.8964150.671247
42017-10-010.1321000.9817290.7338550.8964150.855810
52017-10-010.1321000.8788300.7338550.8447780.855810
62017-10-010.3053200.8788300.5016410.8447780.918584
72017-10-010.3053200.0147470.5016410.9590770.918584
82017-10-01NaN0.014747NaN0.959077NaN

最后一行由于没有对于的后序值,自然继续存在缺失值。

上面的例子中,我们的缺失值是间隔存在的。那么,如果存在连续的缺失值是怎样的情况呢?试一试。首先,我们将数据集的第 2,4 ,6 列的第 3,5 行也置为缺失值。

df.iloc[[3, 5], [1, 3, 5]] = np.nan
df #可见连续存在的缺失值
TimeABCDE
02017-10-010.9848820.0806090.1922260.7653500.576209
1NaT0.730057NaN0.938123NaN0.441354
22017-10-01NaN0.393606NaN0.392022NaN
3NaTNaNNaNNaNNaNNaN
42017-10-01NaN0.981729NaN0.896415NaN
5NaTNaNNaNNaNNaNNaN
62017-10-01NaN0.878830NaN0.844778NaN
7NaT0.305320NaN0.501641NaN0.918584
82017-10-01NaN0.014747NaN0.959077NaN

然后来正向填充:

df.fillna(method='pad')
TimeABCDE
02017-10-010.9848820.0806090.1922260.7653500.576209
12017-10-010.7300570.0806090.9381230.7653500.441354
22017-10-010.7300570.3936060.9381230.3920220.441354
32017-10-010.7300570.3936060.9381230.3920220.441354
42017-10-010.7300570.9817290.9381230.8964150.441354
52017-10-010.7300570.9817290.9381230.8964150.441354
62017-10-010.7300570.8788300.9381230.8447780.441354
72017-10-010.3053200.8788300.5016410.8447780.918584
82017-10-010.3053200.0147470.5016410.9590770.918584

可以看到,连续缺失值也是按照前序数值进行填充的,并且完全填充。这里,我们可以通过 limit= 参数设置连续填充的限制数量。

df.fillna(method='pad', limit=1)  # 最多填充一项
TimeABCDE
02017-10-010.9848820.0806090.1922260.7653500.576209
12017-10-010.7300570.0806090.9381230.7653500.441354
22017-10-010.7300570.3936060.9381230.3920220.441354
32017-10-01NaN0.393606NaN0.392022NaN
42017-10-01NaN0.981729NaN0.896415NaN
52017-10-01NaN0.981729NaN0.896415NaN
62017-10-01NaN0.878830NaN0.844778NaN
72017-10-010.3053200.8788300.5016410.8447780.918584
82017-10-010.3053200.0147470.5016410.9590770.918584

除了上面的填充方式,还可以通过 Pandas 自带的求平均值方法等来填充特定列或行。举个例子:

df.fillna(df.mean()['C':'E'])
TimeABCDE
02017-10-010.9848820.0806090.1922260.7653500.576209
1NaT0.730057NaN0.9381230.7715290.441354
22017-10-01NaN0.3936060.5439960.3920220.645382
3NaTNaNNaN0.5439960.7715290.645382
42017-10-01NaN0.9817290.5439960.8964150.645382
5NaTNaNNaN0.5439960.7715290.645382
62017-10-01NaN0.8788300.5439960.8447780.645382
7NaT0.305320NaN0.5016410.7715290.918584
82017-10-01NaN0.0147470.5439960.9590770.645382

对 C 列到 E 列用平均值填充。

插值填充

插值 是数值分析中一种方法。简而言之,就是借助于一个函数(线性或非线性),再根据已知数据去求解未知数据的值 。插值在数据领域非常常见,它的好处在于,可以尽量去还原数据本身的样子。

我们可以通过 interpolate() 方法完成线性插值。当然,其他一些插值算法可以阅读官方文档了解。

# 生成一个 DataFrame
df = pd.DataFrame({'A': [1.1, 2.2, np.nan, 4.5, 5.7, 6.9],
                   'B': [.21, np.nan, np.nan, 3.1, 11.7, 13.2]})
df
AB
01.10.21
12.2NaN
2NaNNaN
34.53.10
45.711.70
56.913.20

对于上面存在的缺失值,如果通过前后值,或者平均值来填充是不太能反映出趋势的。这时候,插值最好使。我们用默认的线性插值试一试。

df_interpolate = df.interpolate() #默认线性插值
df_interpolate
AB
01.100.210000
12.201.173333
23.352.136667
34.503.100000
45.7011.700000
56.9013.200000

下图展示了插值后的数据,明显看出插值结果符合数据的变化趋势。如果按照前后数据顺序填充,则无法做到这一点。

对于 interpolate() 支持的插值算法,也就是 method=。下面给出几条选择的建议:

  1. 如果你的数据增长速率越来越快,可以选择 method='quadratic'二次插值。

  2. 如果数据集呈现出累计分布的样子,推荐选择 method='pchip'

  3. 如果需要填补缺省值,以平滑绘图为目标,推荐选择 method='akima'

当然,最后提到的 method='akima',需要你的环境中安装了 Scipy 库。除此之外,method='barycentric'method='pchip' 同样也需要 Scipy 才能使用。

数据可视化

NumPy,Pandas,Matplotlib 构成了一个完善的数据分析生态圈 ,所以 3 个工具的兼容性也非常好,甚至共享了大量的接口。当我们的数据是以 DataFrame 格式呈现时,可以直接使用 Pandas 提供的 DataFrame.plot 方法调用 Matplotlib 接口绘制常见的图形。

例如,我们使用上面插值后的数据 df_interpolate 绘制线形图。

df_interpolate.plot() #默认kind='line'折线图

其他样式的图形也很简单,指定 kind= 参数即可。

df_interpolate.plot(kind='bar')

更多的图形样式和参数,阅读官方文档中的详细说明。Pandas 绘图虽然不可能做到 Matplotlib 的灵活性,但是其简单易用,适合于数据的快速呈现和预览。

其他用法

由于 Pandas 包含的内容实在太多,想学习更多用法请阅读完整的官方文档。本课程的目的是带大家熟悉 Pandas 的常用基础方法,至少你大致清楚了 Pandas 是什么,能干什么。

除了上面提到的一些方法和技巧,实际上 Pandas 常用的还有:

总结

本次我们着重介绍了 Pandas 的数据结构,你需要对 Series 和 DataFrame 有深入的认识,才能对后面采用 Pandas 进行数据预处理有更深刻的理解。除此之外,我们了解了 Pandas 数据读取、数据选择、数据删减、数据填充的方法和技巧,希望大家后续结合官方文档进一步深入理解。