目录

  • 1 第一章 数据仓库概述
    • 1.1 授课安排
    • 1.2 数据仓库及其历史
      • 1.2.1 数据仓库的概念
        • 1.2.1.1 本节视频
      • 1.2.2 数据仓库特征
        • 1.2.2.1 本节视频
    • 1.3 数据仓库系统结构
      • 1.3.1 数据仓库系统的组成
        • 1.3.1.1 本节视频
      • 1.3.2 ETL
        • 1.3.2.1 本节视频
      • 1.3.3 数据仓库和数据集市的关系
      • 1.3.4 元数据及其管理
      • 1.3.5 数据集市和元数据管理视频
    • 1.4 数据仓库系统开发工具
    • 1.5 数据仓库与操作型数据库的关系
      • 1.5.1 本节视频内容
  • 2 第二章 数据仓库设计
    • 2.1 授课安排
    • 2.2 数据仓库设计概述
    • 2.3 数据仓库的规划和需求分析
    • 2.4 数据仓库的建模
    • 2.5 数据仓库的物理模型设计
    • 2.6 数据仓库的部署和维护
  • 3 第三章 OLAP技术
    • 3.1 授课安排
    • 3.2 OLAP概述
    • 3.3 OLAP的多维数据模型
    • 3.4 OLAP实现
  • 4 第四章 数据
    • 4.1 课程资料
  • 5 第五章 数据挖掘概述
    • 5.1 授课安排
    • 5.2 什么是数据挖掘?
    • 5.3 数据挖掘系统
    • 5.4 视频
    • 5.5 数据挖掘过程
  • 6 第六章 关联分析
    • 6.1 授课安排
    • 6.2 关联分析概念
    • 6.3 Apriori算法
    • 6.4 FP-growth树
    • 6.5 多层关联规则
    • 6.6 【扩充知识】机器学习——关联规则——支持度(support)、置信度(confidence)、提升度(Lift)
  • 7 第七章 序列模式挖掘
    • 7.1 序列模式挖掘概述
    • 7.2 AprioriAll算法
    • 7.3 AprioriSome算法
    • 7.4 FreeSpan算法
    • 7.5 PrefixSpan算法
  • 8 第八章 聚类分析
    • 8.1 聚类概述
  • 9 分类算法
    • 9.1 课件
  • 10 实验1 python基础
    • 10.1 讲解文本内容
    • 10.2 课程PDF
    • 10.3 实验代码
    • 10.4 实验报告封皮
  • 11 实验2-python
    • 11.1 讲解文本内容
    • 11.2 实验代码
    • 11.3 实验报告封面
  • 12 实验3--python
    • 12.1 讲解文本内容
    • 12.2 实验代码
    • 12.3 实验报告封面
  • 13 实验4--python
    • 13.1 讲解文本内容
    • 13.2 21.1实验代码
    • 13.3 实验内容2
    • 13.4 实验内容3
    • 13.5 实验报告封面
  • 14 实验5--python
    • 14.1 文本内容-NumPy模块
    • 14.2 第三方可视化数据分析图表
    • 14.3 数据
    • 14.4 思考题
    • 14.5 实验报告封面
  • 15 实验6--python
    • 15.1 实验 NumPy矩阵的基本操作
    • 15.2 实验 关联规则算法
    • 15.3 实验 商品零售购物篮分析
    • 15.4 实验报告封面
  • 16 实验7--python
    • 16.1 实验1 用关联规则分析方法推荐电影
    • 16.2 实验2 FP-growth算法
    • 16.3 实验3 教育平台的线上课程推荐策略
    • 16.4 实验报告封面
  • 17 实验8-python
    • 17.1 实验1 购物车分析
    • 17.2 实验2 基于关联规则的文本分析
  • 18 实验9--python
    • 18.1 实验1 聚类分析
    • 18.2 实验2 航空公司客户价值分析
    • 18.3 实验3 运输车辆安全驾驶行为分析
    • 18.4 实验报告封面
讲解文本内容

一、初识Pandas

主要简单了解Pandas及如何安装Pandas,通过“牛刀小试”使读者能够快速体验Pandas。

1.1  Pandas概述

Pandas是数据分析的三大剑客之一,是Python的核心数据分析库,它提供了快速、灵活、明确的数据结构,能够简单、直观、快速地处理各种类型的数据,具体介绍如下:

Pandas能够处理以下类型的数据:

 ■ 与SQL或Excel表类似的数据。

 ■ 有序和无序(非固定频率)的时间序列数据。

 ■ 带行列标签的矩阵数据。

 ■ 任意其他形式的观测、统计数据集。

 Pandas提供的两个主要数据结构Series(一维数组结构)与DataFrame(二维数组结构),可以处理金融、统计、社会科学、工程等领域里的大多数典型案例,并且Pandas是基于NumPy开发的,它可以与其他第三方科学计算库完美集成。

Pandas的功能很多,它的优势如下:

■ 处理浮点与非浮点数据里的缺失数据,表示为NaN。

■ 大小可变,例如插入或删除DataFrame等多维对象的列。

■ 自动、显式数据对齐,显式地将对象与一组标签对齐,也可以忽略标签,在Series、DataFrame计算时自动与数据对齐。

■ 强大、灵活的分组统计(groupby)功能,即数据聚合、数据转换。

■ 可以把Python和NumPy数据结构里不规则、不同索引的数据轻松地转换为DataFrame对象。

■ 智能标签,对大型数据集进行切片、花式索引、子集分解等操作。

■ 直观地合并(merge)、连接(join)数据集。

■ 灵活地重塑(reshape)、透视(pivot)数据集。

■ 成熟的导入导出工具,导入文本文件(CSV等支持分隔符的文件)、Excel文件、数据库等来源的数据;导出Excel文件、文本文件等,利用超快的HDF5格式保存或加载数据。

■ 时间序列:支持日期范围生成、频率转换、移动窗口统计、移动窗口线性回归、日期位移等时间序列功能。

 综上所述,Pandas是处理数据时最理想的工具。

1.2  安装Pandas

 下面介绍两种安装Pandas的方法。

 1.2.1  通过PyPI的pip工具安装

 在系统搜索框中输入cmd,单击“命令提示符”,打开“命令提示符”窗口,在命令提示符后输入安装命令。

Pandas可以通过PyPI的pip工具安装,安装命令如下:

pip install Pandas

 知识胶囊:pip是开发人员经常使用,却又不知来历的一个工具,下面简单介绍一下它。pip是一个现代的、通用的Python包管理工具,英文全称是python install packages。

PyPI(Python Package Index)是python官方的第三方库的仓库,所有人都可以下载第三方库或上传自己开发的库到PyPI上。PyPI可帮助用户查找和安装Python社区开发和共享的软件。PyPI推荐使用pip包管理器来下载第三方库,python 2.7.9以后的版本已经内置了pip,所以不需要安装。

1.2.2  通过Pycharm开发环境安装

除了通过pip工具安装以外,还可以通过Pycharm开发环境安装。运行Pycharm,选择File→ Settings菜单项,打开“Settings”窗口,选择Project Interpreter选项,然后单击添加(+)按钮,如图1所示。这里要注意的是,在Project Interprter选项中应选择当前工程项目使用的Python版本。

图1  Settings窗口

单击添加(+)按钮,打开Available Packages窗口,在搜索文本框中输入需要添加的模块名称,例如“pandas”,然后在列表中选择需要安装的模块,如图2所示,单击Install Package按钮,即可实现Pandas模块的安装。

图2  在PyCharm开发环境中安装Pandas模块

另外,还需要注意一点:Pandas有一些依赖库。

例如,当通过Pandas读取Excel文件时,如果只安装Pandas模块,就会出现如图3所示的错误,意思是缺少依赖库xlrd。当通过Pandas导出Excel文件时,也同样会出现缺少依赖库xlwt的错误,如图4所示。

图3  缺少依赖库xlrd

图4  缺少依赖库xlwt

解决办法:

安装xlrd模块和xlwt模块,方法如下:

执行pip install xlrd命令或通过PyCharm开发环境安装xlrd模块。

执行pip install xlwt命令或通过PyCharm开发环境安装xlwt模块。

由于后面举例时经常会用到这两项操作,因此需要同时安装xlrd和xlwt两个模块。

1.2.3  牛刀小试——轻松导入Excel数据

了解Pandas模块后,接下使用Pandas导入Excel数据。

快速示例01  导入英超射手榜数据

以英超射手榜数据为例,导入英超射手榜数据,按照惯例首先导入模块,代码如下:

01 import pandas as pd           #导入pandas模块

02 #解决数据输出时列名不对齐的问题

03 pd.set_option('display.unicode.east_asian_width', True)

04 df=pd.read_excel('data.xlsx')  #读取Excel文件

05 print(df.head())              #显示前5条数据

运行程序,输出结果如图3.5所示。

图 5  英超射手榜TOP5

技巧:Pandas默认输出结果,会出现列不对齐或者多行多列显示不全的问题,使用set_option函数可以解决这两个问题。

■ 解决列名不对齐

通过将display.unicode.east_asian_width设置为True,使列名对齐。例如:

pd.set_option('display.unicode.east_asian_width', True)

■ 行列显示不全

通过将display.max_rows和display.max_columns修改为默认输出最大的行数和列数。例如:

pd.set_option('display.max_rows',1000)

pd.set_option('display.max_columns',1000)

二、 Series对象

Pandas是Python数据分析重要的库,而Series和DataFrame是Pandas库中两个重要的对象,也是Pandas中两个重要的数据结构,如图 6所示。

图 6  Pandas中两个重要的数据结构

2.1  图解Series对象

Series是Python的Pandas库中的一种数据结构,它类似一维数组,由一组数据以及与这组数据相关的标签(即索引)组成,或者仅有一组数据而没有索引也可以创建一个简单的Series对象。Series可以存储整数、浮点数、字符串、Python对象等多种类型的数据。

例如,在成绩表(如图 7所示)中包含了Series对象和DataFrame对象,其中“语文”“数学”和“英语”每一列都是一个Series对象,而“语文”“数学”和“英语”三列组成了一个DataFrame对象,如图 8所示。

图 7  原始数据(成绩表)

图 8  Series对象图解

2.2  创建一个Series对象

创建Series对象时,主要使用Pandas的Series方法,语法如下:

s=pd.Series(data,index=index)

参数说明:

■ data:表示数据,支持Python字典、多维数组、标量值(即只有大小、没有方向的量。也就是说,只是一个数值,如s=pd.Series(5))。

■ index:表示行标签(索引)。

■ 返回值:Series对象。

说明:当data参数是多维数组时,index长度必须与data长度一致。如果没有指定index参数,将自动创建数值型索引(从0~data的数据长度减1)。

快速示例02  为成绩表添加一列“物理”成绩

创建一个Series对象,为成绩表添加一列“物理”成绩,程序代码如下:

01 import pandas as pd

02 s1=pd.Series([88,60,75])

03 print(s1)

运行程序,输出结果为:

08

160

275

上述举例,如果通过pandas模块引入Series对象,那么就可以直接在程序中使用Series对象了,关键代码如下:

01 from pandas import Series

02 s1=Series([88,60,75])

2.3  手动设置Series索引

创建Series对象时会自动生成整数索引,默认值从0开始至数据长度减1。例如,在上一节示例中使用的就是默认索引,如0、1、2。除了使用默认索引,还可以通过index参数手动设置索引。

快速示例03  手动设置索引

下面手动设置索引,将上一节添加的“物理”成绩的索引设置为1、2、3,也可以是“明日同学”“高同学”“七月流火”,程序代码如下:

01 import pandas as pd

02 s1=pd.Series([88,60,75],index=[1,2,3])

03 s2=pd.Series([88,60,75],index=['明日同学','高同学','七月流火'])

04 print(s1)

05 print(s2)

运行程序,输出结果为:

188

260

375

dtype: int64

明日同学88

高同学60

七月流火75

dtype: int64

说明:上述结果中输出的dtype,是DataFrame数据的数据类型,int为整型,后面的数字表示位数。

2.4  Series的索引

2.4.1  Series位置索引

位置索引是从0开始,[0]是Series的第一个数;[1]是series的第二个数,依次类推。

快速示例04  通过位置索引获取学生的物理成绩

获取第一个学生的物理成绩,程序代码如下:

01 import pandas as pd

02 s1=pd.Series([88,60,75])

03 print(s1[0])

运行程序,输出结果为:

88

注意:Series对象不能使用[-1]定位索引。

2.4.2  Series标签索引

Series标签索引与位置索引方法类似,用“[ ]”表示,里面是索引名称,注意index的数据类型是字符串,如果需要获取多个标签索引值,则用“[[ ]]”表示(相当于在“[ ]”中包含一个列表)。

快速示例05  通过标签索引获取学生的物理成绩

通过标签索引“明日同学”和“七月流火”获取物理成绩,程序代码如下:

01 import pandas as pd

02 s1=pd.Series([88,60,75],index=['明日同学','高同学','七月流火'])

03 print(s1['明日同学'])        #通过一个标签索引获取索引值

04 print(s1[['明日同学','七月流火']])  #通过多个标签索引获取索引值

运行程序,输出结果为:

88

明日同学88

七月流火75

2.4.3  Series切片索引

用标签索引做切片,可以包头包尾(即包含了索引开始位置的数据,也包含了索引结束位置的数据)。

快速示例06  通过切片获取数据

通过标签切片索引“明日同学”“七月流火”获取数据,程序代码如下:

print(s1['明日同学':'七月流火'])   #通过切片获取索引值

运行程序,输出结果为:

明日同学8

高同学60

七月流火75

用位置索引做切片,和list列表的用法一样,可以包头不包尾(即包含了索引开始位置的数据,但不包含索引结束位置的数据)。

快速示例07  通过位置切片获取数据

通过位置切片1~4获取数据,程序代码如下:

01 s2=pd.Series([88,60,75,34,68])

02 print(s2[1:4])

运行程序,输出结果为:

160

275

334

2.5  获取Series的索引和值

获取Series的索引和值主要使用Series对象的index方法和values方法。

快速示例08  获取物理成绩的索引和值

下面使用Series的index方法和values方法获取物理成绩的索引和值,程序代码如下:

01 import pandas as pd

02 s1=pd.Series([88,60,75])

03 print(s1.index)

04 print(s1.values)

运行程序,输出结果为:

RangeIndex(start=0, stop=3, step=1)

[88 60 75]

三、DataFrame对象

DataFrame是Pandas库中的一种数据结构,它是由多种类型的列组成的二维表数据结构,类似于Excel、SQL或Series对象构成的字典。DataFrame是最常用的Pandas对象,它与Series对象一样支持多种类型的数据。

3.1  图解DataFrame对象

DataFrame是一个二维表数据结构,即由行列数据组成的表格。DataFrame既有行索引也有列索引,它可以看作是由Series对象组成的字典,不过这些Series对象共用一个索引,如图 9所示。

图 9  DataFrame对象的结构

处理DataFrame表格数据时,用index表示行或用columns表示列更直观,而且用这种方式迭代DataFrame对象的列,代码更易读懂。

快速示例09  遍历DataFrame数据

遍历DataFrame数据,输出成绩表的每一列数据,程序代码如下:

01 import pandas as pd

02 #解决数据输出时列名不对齐的问题

03 pd.set_option('display.unicode.east_asian_width', True)

04 data = [[110,105,99],[105,88,115],[109,120,130]]

05 index = [0,1,2]

06 columns = ['语文','数学','英语']

07 #创建DataFrame数据

08 df = pd.DataFrame(data=data, index=index,columns=columns)

09 print(df)

10 #遍历DataFrame数据的每一列

11 for col in df.columns:

12     series = df[col]

13     print(series)

运行程序,输出结果为:

0110

1105

2109

Name: 语文, dtype: int64

0105

188

2120

Name: 数学, dtype: int64

099

1115

2130

Name: 英语, dtype: int64

从运行结果得知:上述代码返回的其实是Series,如图 10所示。Pandas之所以提供多种数据结构,其目的就是为了代码易读,操作更加方便。

图  10  Series对象

3.2  创建一个DataFrame对象

创建DataFrame主要使用Pandas模块的DataFrame方法,语法如下:

pandas.DataFrame(data,index,columns,dtype,copy)

参数说明:

■ data:表示数据,可以是ndarray数组、series对象、列表、字典等。

■ index:表示行标签(索引)。

■ columns:列标签(索引)。

■ dtype:每一列数据的数据类型,其与Python数据类型有所不同,如object数据类型对应的是Python的字符型。如表 1所示,是Pandas数据类型与Python数据类型的对应。

表 1  数据类型对应表

■ copy:用于复制数据。

■ 返回值:DataFrame。

下面通过两种方法来创建DataFrame对象,即二维数组和字典。

3.2.1  通过二维数组创建DataFrame对象

快速示例10  通过二维数组创建成绩表

通过二维数组创建成绩表,包括语文、数学和英语,程序代码如下:

01 import pandas as pd

02 #解决数据输出时列名不对齐的问题

03 pd.set_option('display.unicode.east_asian_width', True)

04 data = [[110,105,99],[105,88,115],[109,120,130]]

05 columns = ['语文','数学','英语']

06 df = pd.DataFrame(data=data, columns=columns)

07 print(df)

运行程序,输出结果为:

 语文数学英语

011010599

110588115

2109120130

3.2.2  通过字典创建DataFrame对象

通过字典创建DataFrame,需要注意:字典中的value值只能是一维数组或单个的简单数据类型,如果是数组,则要求所有的数组长度一致;如果是单个数据,则每行都需要添加相同数据。

快速示例11  通过字典创建成绩表

通过字典创建成绩表,包括语文、数学、英语和班级,程序代码如下:

01 import pandas as pd

02 #解决数据输出时列名不对齐的问题

03 pd.set_option('display.unicode.east_asian_width', True)

04 df = pd.DataFrame({

05     '语文':[110,105,99],

06      '数学':[105,88,115],

07      '英语':[109,120,130],

08       '班级':'高一7班'

09  },index=[0,1,2])

10 print(df)

运行程序,输出结果为:

 语文数学英语班级

010105109高一7班

110588120高一7班

299115130高一7班

在上述代码中,“班级”的value值是单个数据,所以每一行都添加了相同的数据“高一7班”。

3.3  DataFrame的重要属性和函数

DataFrame是Pandas中一个重要的对象,它的属性和函数有很多,下面先简单了解一下DataFrame对象的几个重要属性和函数,重要属性及描述如表 2所示。

表 2  重要属性及描述

重要函数及描述如表 3所示。

表 3  重要函数及描述

四、导入外部数据

数据分析首先就要有数据。对于多种多样的数据类型,本节介绍如何导入不同类型的外部数据。

4.1  导入.xls或.xlsx文件

导入.xls或.xlsx文件主要使用Pandas的read_excel方法,语法如下:

pandas.read_excel(io,sheet_name=0,header=0,names=None,index_col=None,usecols=None,squeeze=False,dtype=None,engine=None,converters=None,true_values=None,false_values=None,skiprows=None,nrow=None,na_values=None,keep_default_na=True,verbose=False,parse_dates=False,date_parser=None,thousands=None,comment=None,skipfooter=0,conver_float=True,mangle_dupe_cols=True,**kwds)

常用参数说明:

■ io:字符串,xls或xlsx文件路径或类文件对象。

■ sheet_name:None、字符串、整数、字符串列表或整数列表,默认值为0。字符串用于工作表名称;整数为索引,表示工作表位置,字符串列表或整数列表用于请求多个工作表,为None时则获取所有的工作表。参数值如表 4所示。

表 4  sheet_name参数值及说明

■ header:指定作为列名的行,默认值为0,即取第一行的值为列名。数据为除列名以外的数据;若数据不包含列名,则设置为header=None。

■ names:默认值为None,要使用的列名列表。

■ index_col:指定列为索引列,默认值为None,索引0是DataFrame对象的行标签。

■ usecols:int、list或字符串,默认值为None。

● 如果为None,则解析所有列。

● 如果为int,则解析最后一列。

● 如果为list列表,则解析列号和列表的列。

● 如果为字符串,则表示以逗号分隔的Excel列字母和列范围列表(例如,“A:E”或“A,C,E:F”),范围包括双方。

■ squeeze:布尔值,默认值为False,如果解析的数据只包含一列,则返回一个Series。

■ dtype:列的数据类型名称或字典,默认值为None。例如,{为'a':np.float64,'b':np.int32}。

■ skiprows:省略指定行数的数据,从第一行开始。

■ skipfooter:省略指定行数的数据,从尾部数的行开始。

下面将详细介绍如何导入.xlsx文件。

4.1.1  常规导入

快速示例12  导入Excel文件

导入“1月.xlsx”的Excel文件,程序代码如下:

01 import pandas as pd

02 #解决数据输出时列名不对齐的问题

03 pd.set_option('display.unicode.east_asian_width', True)

04 df=pd.read_excel('1.xlsx')

05 print(df.head())         #输出前5条数据

运行程序,输出部分数据,结果如图 11所示。

图 11  前5条的淘宝销售数据(部分数据)

知识胶囊:

导入外部数据,必然要涉及路径问题,下面来复习一下相对路径和绝对路径的知识。

■ 相对路径

相对路径就是以当前文件为基准,从而一级级目录指向被引用的资源文件。以下是常用的表示当前目录和当前目录的父级目录的标识符。

● ../:表示当前文件所在目录的上一级目录。

● ./:表示当前文件所在的目录(可以省略)。

● /:表示当前文件的根目录(域名映射或硬盘目录)。

如果使用系统默认文件路径“\”,那么在Python中则需要在路径最前面加一个r,以避免路径里面的“\”被转义。

■ 绝对路径

绝对路径是文件真正存在的路径,是指从硬盘的根目录(盘符)开始,从而一级级目录指向文件。

4.1.2  导入指定的Sheet页

一个Excel文件包含多个Sheet页,通过设置sheet_name参数就可以导入指定Sheet页的数据。

快速示例13  导入指定Sheet页的数据

一个Excel文件中包含多家店铺的销售数据,导入其中一家店铺(如莫寒)的销售数据,如图 12所示。

图 12  原始数据

程序代码如下:

01 import pandas as pd

02 #解决数据输出时列名不对齐的问题

03 pd.set_option('display.unicode.east_asian_width', True)

04 df=pd.read_excel('1.xlsx',sheet_name='莫寒')

05 print(df.head())         #输出前5条数据

运行程序 ,输出部分数据,结果如图 13所示。

图 13  导入指定的Sheet页(部分数据)

除了指定Sheet页的名字,还可以指定Sheet页的顺序,从0开始。例如,“sheet_name=0”表示导入第一个Sheet页的数据,“sheet_name=1”表示导入第二个Sheet页的数据,以此类推。

如果不指定sheet_name参数,则默认导入第一个Sheet页的数据。

4.1.3  通过行列索引导入指定行列数据

DataFrame是二维数据结构,因此它既有行索引又有列索引。当导入Excel数据时,行索引会自动生成,如0、1、2,而列索引则默认将第0行作为列索引(如A,B,…,J),如图 14所示。

图 14  DataFrame行列索引示意图

快速示例14  指定行索引导入Excel数据

如果通过指定行索引导入Excel数据,则需要设置index_col参数。下面将“买家会员名”作为行索引(位于第0列),导入Excel数据,程序代码如下:

01 import pandas as pd

02 #解决数据输出时列名不对齐的问题

03 pd.set_option('display.unicode.east_asian_width', True)

04 df1=pd.read_excel('1.xlsx',index_col=0)   #设置“买家会员名”为行索引

05 print(df1.head())                           #输出前5条数据

运行程序,输出结果如图 15所示。

图 15  通过设置行索引导入Excel数据

如果通过指定列索引导入Excel数据,则需要设置header参数,关键代码如下:

df2=pd.read_excel('1月.xlsx',header=1)   #设置第1行为列索引

运行程序,输出结果如图 16所示。

图 16  通过设置列索引导入Excel数据

如果将数字作为列索引,可以设置header参数为None,关键代码如下:

df3=pd.read_excel('1.xlsx',header=None) #列索引为数字

运行程序,输出结果如图 17所示。

图 17  设置列索引

那么,为什么要指定索引呢?因为通过索引可以快速地检索数据,例如根据df3[0],就可以快速检索到“买家会员名”这一列数据。

4.1.4  导入指定列数据

一个Excel表中往往包含多列数据,如果只需要其中的几列,可以通过usecols参数指定需要的列,从0开始(表示第1列,依次类推)。

快速示例15  导入第一列数据

下面导入第一列数据(索引为0),程序代码如下:

01 import pandas as pd

02 #解决数据输出时列名不对齐的问题

03 pd.set_option('display.unicode.east_asian_width', True)

04 df1=pd.read_excel('1.xlsx',usecols=[0]) #导入第一列数据

05 print(df1.head())

运行程序,输出结果如图 18所示。

图 18  导入第一列数据

如果导入多列,则可以在列表中指定多个值。例如,导入第一列和第四列,关键代码如下:

df1=pd.read_excel('1.xlsx',usecols=[0,3])

也可以指定列名称,关键代码如下:

df1=pd.read_excel('1.xlsx',usecols=['买家会员名','宝贝标题'])

运行程序,输出结果如图 19所示。

图 19  导入第一列和第四列的数据

4.2  导入.csv文件

导入.csv文件时主要使用Pandas的read_csv方法,语法如下:

pandas.read_csv(filepath_or_buffer,sep=',',delimiter=None,header='infer',names=None,index_col=None,usecols=None,squeeze=False,prefix=None,mangle_dupe_cols=True,dtype=None,engine=None,converters=None,true_values=None,false_values=None,skipinitialspace=False,skiprows=None,nrows=None,na_values=None,keep_default_na=True,na_filter=True,verbose=False,skip_blank_lines=True,parse_dates=False,infer_datetime_format=False,keep_date_col=False,date_parser=None,dayfirst=False,iterator=False,chunksize=None,compression='infer',thousands=None,decimal=b'.',lineterminator=None,quotechar='"',quoting=0,escapechar=None,comment=None, encoding=None)

常用参数说明:

■ filepath_or_buffer:字符串,文件路径,也可以是URL链接。

■ sep、delimiter:字符串,分隔符。

■ header:指定作为列名的行,默认值为0,即取第一行的值为列名。数据为除列名以外的数据;若数据不包含列名,则设置header=None。

■ names:默认值为None,要使用的列名列表。

■ index_col:指定列为索引列,默认值为None,索引0是DataFrame对象的行标签。

■ usecols:int、list或字符串,默认值为None。

● 如果为None,则解析所有列。

● 如果为int,则解析最后一列。

● 如果为list列表,则解析列号、列表的列。

● 如果为字符串,则表示以逗号分隔的Excel列字母和列范围列表(例如,“A:E”或“A,C,E:F”),范围包括双方。

■ dtype:列的数据类型名称或字典,默认值为None。例如,{'a':np.float64,'b':np.int32}。

■ parse_dates:布尔类型值、int类型值的列表、列表或字典,默认值为False。可以通过parse_dates参数直接将某列转换成datetime64的日期类型。例如,“df1=pd.read_csv('1月.csv', parse_dates=['订单付款时间'])”。

● parse_dates为True时,尝试解析索引。

● parse_dates为int类型值组成的列表时,如[1,2,3],则解析1、2、3列的值作为独立的日期列。

● parse_date为列表组成的列表,如[[1,3]],则将1、3列合并,作为一个日期列使用。

● parse_date为字典时,如{'总计':[1, 3]},则将1、3列合并,合并后的列名为“总计”。

■ encoding:字符串,默认值为None,文件的编码格式。

■ 返回值:返回一个DataFrame对象。

快速示例16  导入.csv文件

导入.csv文件,程序代码如下:

01 import pandas as pd

02 #设置数据显示的最大列数和宽度

03 pd.set_option('display.max_columns',500)

04 pd.set_option('display.width',1000)

05 #解决数据输出时列名不对齐的问题

06 pd.set_option('display.unicode.east_asian_width', True)

07 df1=pd.read_csv('1.csv',encoding='gbk')     #导入.csv文件,并指定编码格式

08 print(df1.head())                                #输出前5条数据

运行程序,输出结果如图 20所示。

图 20  导入.csv文件

注意:上述代码中指定了编码格式,即encoding='gbk'。Python常用的编码格式是UTF-8和gbk格式,默认编码格式为UTF-8。导入.csv文件时,需要通过encoding参数指定编码格式。当我们将Excel文件另存为.csv文件时,默认编码格式为gbk,此时编写代码导入.csv文件时,就需要设置编码格式为gbk,与原文件的编码格式保持一致,否则会提示错误。

4.3  导入.txt文本文件

导入.txt文件同样使用Pandas模块的read_csv方法,不同的是需要指定sep参数(如制表符/t)。read_csv方法读取.txt文件后将返回一个DataFrame对象,像表格一样的二维数据结构,如图 21所示。

快速示例17  导入.txt文本文件

下面使用read_csv方法导入1月的.txt文件,关键代码如下:

01 import pandas as pd

02 df1=pd.read_csv('1.txt',sep='\t',encoding='gbk')

03 print(df1.head())

运行程序,输出结果如图 22所示。

图 22  导入.txt文本的效果

4.4  导入HTML网页

导入HTML网页数据主要使用Pandas的read_html方法,该方法用于导入带有table标签的网页表格数据,语法如下:

pandas.read_html(io,match='.+',flavor=None,header=None,index_col=None,skiprows=None,attrs=None,parse_dates=False,thousands=',',encoding=None,decimal='.',converters=None,na_values=None,keep_default_na=True,displayed_only=True)

常用参数说明:

■ io:字符串,文件路径,也可以是URL链接。网址不接受https,可以尝试去掉https中的s后爬取,如http://www.mingribook.com。

■ match:正则表达式,返回与正则表达式匹配的表格。

■ flavor:解析器默认为“lxml”。

■ header:指定列标题所在的行,列表list为多重索引。

■ index_col:指定行标题对应的列,列表list为多重索引。

■ encoding:字符串,默认为None,文件的编码格式。

■ 返回值:返回一个DataFrame对象。

使用read_html方法前,首先要确定网页表格是否为table标签。例如,NBA球员薪资网页(http://www.espn.com/nba/salaries),右键单击该网页中的表格,在弹出的菜单中选择“检查元素”,查看代码中是否含有表格标签<table>…</table>的字样,如图 23所示,确定后才可以使用read_html方法。

图 23  <table>…</table>表格标签页面

快速示例18  导入NBA球员的薪资数据

下面使用read_html方法导入NBA球员的薪资数据,程序代码如下:

01 import pandas as pd

02 df = pd.DataFrame()

03 url_list = ['http://www.espn.com/nba/salaries/_/seasontype/4']

04 for i in range(2, 13):

05 url = 'http://www.espn.com/nba/salaries/_/page/%s/seasontype/4' % i

06 url_list.append(url)

07 #遍历网页中的table标签读取网页表格数据

08 for url in url_list:

09 df = df.append(pd.read_html(url), ignore_index=True)

10 #列表解析:遍历dataframe对象的第3列,以子字符串$开头

11 df = df[[x.startswith('$') for x in df[3]]]

12 print(df)

13 df.to_csv('NBA.csv',header=['RK','NAME','TEAM','SALARY'], index=False)  #导出.csv文件

运行程序,输出结果如图 24所示。

图 24  导入网页数据

注意:运行程序,如果出现“ImportError: lxml not found, please install it”的错误提示信息,则需要安装lxml模块。

五、数据抽取

在数据分析过程中,并不是所有的数据都是我们想要的,此时可以抽取部分数据,主要使用DataFrame对象中的loc属性和iloc属性,如图 25所示。

图 25  loc属性和iloc属性示意图

DataFrame对象中的loc属性和iloc属性都可以抽取数据,区别如下:

■ loc属性:以列名(columns)和行名(index)作为参数,当只有一个参数时,默认是行名,即抽取整行数据,包括所有列,如df.loc['A']

■ iloc属性:以行和列位置索引(即0,1,2,…)作为参数,0表示第一行;1表示第二行,以此类推。当只有一个参数时,默认是行索引,即抽取整行数据,包括所有列,如抽取第一行数据,df.iloc[0]。

5.1  抽取一行数据

抽取一行数据需要使用loc属性。

快速示例19  抽取一行考试成绩数据

抽取1行名为“明日”的考试成绩数据(包括所有列),程序代码如下:

01 import pandas as pd

02 #解决数据输出时列名不对齐的问题

03 pd.set_option('display.unicode.east_asian_width', True)

04 data = [[110,105,99],[105,88,115],[109,120,130],[112,115]]

05 name = ['明日','七月流火','高袁圆','二月二']

06 columns = ['语文','数学','英语']

07 df = pd.DataFrame(data=data, index=name, columns=columns)

08 print(df.loc['明日'])

运行程序,输出结果如图 26所示。

图 26  抽取一行数据

想要使用iloc属性抽取第一行数据,指定行索引即可,如df.iloc[0],输出结果同图3.26一样。

5.2  抽取多行数据

■ 抽取任意多行数据

通过loc属性和iloc属性指定行名和行索引即可实现抽取任意多行数据。

快速示例20  抽取多行考试成绩数据

抽取行名为“明日”和“高袁圆”(即第1行和第3行数据)的考试成绩数据,关键代码如下:

01 print(df.loc[['明日','高袁圆']])

02 print(df.iloc[[0,2]])

运行程序,输出结果如图 27所示。

图 27  抽取多行数据

■ 抽取连续任意多行数据

在loc属性和iloc属性中合理使用冒号“:”,即可抽取连续任意多行数据。

快速示例21  抽取连续几个学生的考试成绩

实现抽取连续几个学生的考试成绩,关键代码如下:

01 print(df.loc['明日':'二月二']) #从“明日”到“二月二”

02 print(df.loc[:'七月流火':])     #第1行到“七月流火”

03 print(df.iloc[0:4])             #第1行到第4行

04 print(df.iloc[1::])             #第2行到最后1行

运行程序,输出结果如图 28所示。

图 28  抽取连续几个学生的考试成绩

5.3  抽取指定列数据

想要抽取指定列数据,可以直接使用列名,也可以使用loc属性和iloc属性。

■ 直接使用列名

快速示例22  抽取“语文”和“数学”的考试成绩

抽取列名为“语文”和“数学”的考试成绩数据,程序代码如下:

01 import pandas as pd

02 #解决数据输出时列名不对齐的问题

03 pd.set_option('display.unicode.east_asian_width', True)

04 data = [[110,105,99],[105,88,115],[109,120,130],[112,115]]

05 name = ['明日','七月流火','高袁圆','二月二']

06 columns = ['语文','数学','英语']

07 df = pd.DataFrame(data=data, index=name, columns=columns)

08 print(df[['语文','数学']])

运行程序,输出结果如图 29所示。

图 29  直接使用列名

■ 使用loc属性和iloc属性

前面介绍loc属性和iloc属性都包含了两个参数,第一个参数代表行;第二个参数代表列,那么这里在抽取指定列数据时,行参数不能省略。

快速示例23  抽取指定学科的考试成绩

下面使用loc属性和iloc属性抽取指定列数据,关键代码如下:

01 print(df.loc[:,['语文','数学']])    #抽取“语文”和“数学”

02 print(df.iloc[:,[0,1]])           #抽取第1列和第2列

03 print(df.loc[:,'语文':])            #抽取从“语文”开始到最后一列

04 print(df.iloc[:,:2])               #连续抽取从1列开始到第3列,但不包括第3列

运行程序,输出结果如图 30所示。

图 30  使用loc属性和iloc属性抽取指定列数据

5.4  抽取指定行列数据

抽取指定行列数据主要使用loc属性和iloc属性,这两个方法中的两个参数都指定后,就可以实现指定行列数据的抽取。

快速示例24  抽取指定学科和指定学生的考试成绩

使用loc属性和iloc属性抽取指定学科和指定学生的考试成绩,程序代码如下:

01 import pandas as pd

02 #解决数据输出时列名不对齐的问题

03 pd.set_option('display.unicode.east_asian_width', True)

04 data = [[110,105,99],[105,88,115],[109,120,130],[112,115]]

05 name = ['明日','七月流火','高袁圆','二月二']

06 columns = ['语文','数学','英语']

07 df = pd.DataFrame(data=data, index=name, columns=columns)

08 print(df.loc['七月流火','英语'])           #“英语”成绩

09 print(df.loc[['七月流火'],['英语']])        #“七月流火”的“英语”成绩

10 print(df.loc[['七月流火'],['数学','英语']]) #“七月流火”的“数学”和“英语”成绩

11 print(df.iloc[[1],[2]])                      #第2行第3列

12 print(df.iloc[1:,[2]])                    #第2行到最后一行的第3列

13 print(df.iloc[1:,[0,2]])                   #第2行到最后一行的第1列和第3列

14 print(df.iloc[:,2])                         #所有行,第3列

运行程序,输出结果如图 31所示。

图 31  抽取指定行列数据

在上述结果中,第一个输出结果是一个数字,不是数据,这是由于“df.loc['七月流火','英语']”语句中没有使用方括号[],导致输出的数据不是DataFrame对象。

5.5  按指定条件抽取数据

使用DataFrame对象实现数据查询有以下3种方式:

(1)取其中的一个元素,如.iat[x,x]。

(2)基于位置的查询,如.iloc[]、iloc[2,1]。

(3)基于行列名称的查询,如.loc[x]。

快速示例25  抽取指定学科和指定分数的数据

抽取语文成绩大于105分,数学成绩大于88分的数据,程序代码如下:

01 import pandas as pd

02 #解决数据输出时列名不对齐的问题

03 pd.set_option('display.unicode.east_asian_width', True)

04 data = [[110,105,99],[105,88,115],[109,120,130],[112,115]]

05 name = ['明日','七月流火','高袁圆','二月二']

06 columns = ['语文','数学','英语']

07 df = pd.DataFrame(data=data, index=name, columns=columns)

08 print(df.loc[(df['语文'] > 105) & (df['数学'] >88)])

运行程序,输出结果如图 32所示。

图 32  按指定条件抽取数据

六、数据的增加、修改和删除

本节主要介绍如何操纵DataFrame对象中的各种数据。例如,数据的增加、修改和删除等。

6.1  增加数据

在DataFrame对象中增加数据主要包括列数据和行数据的增加。首先看下原始数据,如图 33所示。

图 33  原始数据

6.1.1  按列增加数据

按列增加数据,可以通过以下3种方式实现:

(1)直接为DataFrame对象赋值。

快速示例26  增加一列“物理”成绩

增加一列“物理”成绩,程序代码如下:

01 import pandas as pd

02 #解决数据输出时列名不对齐的问题

03 pd.set_option('display.unicode.east_asian_width', True)

04 data = [[110,105,99],[105,88,115],[109,120,130],[112,115,140]]

05 name = ['明日','七月流火','高袁圆','二月二']

06 columns = ['语文','数学','英语']

07 df = pd.DataFrame(data=data, index=name, columns=columns)

08 df['物理']=[88,79,60,50]

09 print(df)

运行程序,输出结果如图 34所示。

图 34  按列增加数据

(2)使用loc属性在DataFrame对象的最后增加一列。

快速示例27  使用loc属性增加一列“物理”成绩

使用loc属性在DataFrame对象的最后增加一列。例如,增加“物理”一列,关键代码如下:

df.loc[:,'物理'] = [88,79,60,50]

在DataFrame对象的最后增加一列“物理”,其值为等号的右边数据。

(3)在指定位置插入一列。

在指定位置插入一列,主要使用insert方法。

快速示例28  在第一列的后面插入“物理”成绩

例如,在第一列的后面插入“物理”,其值为wl的数值,关键代码如下:

01 wl =[88,79,60,50]

02 df.insert(1,'物理',wl)

03 print(df)

运行程序,输出结果如图 35所示。

图 35  使用insert方法在第一列的后面增加数据

6.1.2  按行增加数据

按行增加数据,可以通过以下两种方式实现:

(1)增加一行数据。

增加一行数据主要使用loc属性实现。

快速示例29  在成绩表中增加一行数据

在成绩表中增加一行数据,即“钱多多”同学的成绩,关键代码如下:

df.loc['钱多多'] = [100,120,99]

(2)增加多行数据

增加多行数据主要使用字典并结合append方法实现。

快速示例30  在原有数据中增加几名同学的考试成绩

在原有数据中增加“钱多多”“童年”和“无名”同学的考试成绩,关键代码如下:

01 df_insert=pd.DataFrame({'语文':[100,123,138],'数学':[99,142,60],'英语':[98,139,99]},index = ['钱多多','童年','无名'])

02 df1 = df.append(df_insert)

运行程序,输出结果如图 36和图 37所示。

图 36  增加一行数据

图 37  增加多行数据

6.2  修改数据

修改数据包括行列标题和数据的修改,首先看下原始数据,如图 38所示。

图 38  原始数据

6.2.1  修改列标题

修改列标题主要使用DataFrame对象中的cloumns属性,直接赋值即可。

快速示例31  修改“数学”的列名

将“数学”修改为“数学(上)”,关键代码如下:

df.columns=['语文','数学(上)','英语']

在上述代码中,即使只修改“数学”为“数学(上)”,但是也要将所有列的标题全部写上,否则将报错。

下面再介绍一种方法,使用DataFrame对象中的rename方法修改列标题。

快速示例32  修改多个学科的列名

将“语文”修改为“语文(上)”“数学”修改为“数学(上)”“英语”修改为“英语(上)”,关键代码如下:

df.rename(columns = {'语文':'语文(上)','数学':'数学(上)','英语':'英语(上)'},inplace = True)

在上述代码中,参数inplace为True,表示直接修改df;否则不修改df,只返回修改后的数据。

运行程序,输出结果如图 39和图 40所示。

图 39  修改列标题1

图 40  修改列标题2

6.2.2  修改行标题

修改行标题主要使用DataFrame对象中的index属性,直接赋值即可。

快速示例33  将行标题统一修改为数字编号

将行标题统一修改为数字编号,关键代码如下:

df.index=list('1234')

使用DataFrame对象中的rename方法也可以修改行标题。例如,将行标题统一修改为数字编号,关键代码如下:

df.rename({'明日':1,'七月流火':2,'高袁圆':3,'二月二':4},axis=0,inplace = True)

6.2.3  修改数据

修改数据主要使用DataFrame对象中的loc属性和iloc属性。

快速示例34  修改学生成绩数据

(1)修改整行数据

例如,修改“明日”同学的各科成绩,关键代码如下:

df.loc['明日']=[120,115,109]

如果各科成绩均加10分,可以直接在原有值加10,关键代码如下:

df.loc['明日']=df.loc['明日']+10

(2)修改整列数据

例如,修改所有同学的“语文”成绩,关键代码如下:

df.loc[:,'语文']=[115,108,112,118]

(3)修改某一处数据

例如,修改“明日”同学的“语文”成绩,关键代码如下:

df.loc['明日','语文']=115

(4)使用iloc属性修改数据

通过iloc属性指定行列位置实现修改数据,关键代码如下:

01df.iloc[0,0]=115                 #修改某一处数据

02df.iloc[:,0]=[115,108,112,118]   #修改整列数据

03df.iloc[0,:]=[120,115,109]       #修改整行数据

6.3  删除数据

删除数据主要使用DataFrame对象中的drop方法。语法如下:

DataFrame.drop(labels=None, axis=0, index=None, columns=None, level=None, inplace=False, errors='raise')

参数说明:

■ labels:表示行标签或列标签。

■ axis:axis = 0,表示按行删除;axis = 1,表示按列删除,默认值为0。

■ index:删除行,默认值为None。

■ columns:删除列,默认值为None。

■ level:针对有两级索引的数据。level = 0,表示按第1级索引删除整行;level = 1,表示按第2级索引删除整行,默认值为None。

■ inplace:可选参数,对原数组作出修改并返回一个新数组。默认值为False,如果值为True,那么原数组直接就将被替换。

■ errors:参数值为ignore或raise,默认值为raise,如果值为ignore(忽略),则取消错误。

6.3.1  删除行列数据

快速示例35  删除指定的学生成绩数据

删除指定的学生成绩数据,关键代码如下:

01 df.drop(['数学'],axis=1,inplace=True) #删除某列

02 df.drop(columns='数学',inplace=True)                 #删除columns为“数学”的列

03 df.drop(labels='数学', axis=1,inplace=True)          #删除列标签为“数学”的列

04 df.drop(['明日','二月二'],inplace=True)             #删除某一行

05 df.drop(index='明日',inplace=True)                   #删除index为“明日”的行

06 df.drop(labels='明日', axis=0,inplace=True)        #删除行标签为“明日”的行

6.3.2  删除特定条件的行

删除满足特定条件的行,首先找到满足该条件的行索引,然后再使用drop方法将其删除。

快速示例36  删除符合条件的学生成绩数据

删除“数学”中包含分数88的行“语文”小于分数110的行,关键代码如下:

01 df.drop(index=df[df['数学'].isin([88])].index[0],inplace=True)#删除“数学”包含分数88的行

02 df.drop(index=df[df['语文']<110].index[0],inplace=True)       #删除“语文”小于分数110的行

说明:以上代码中的方法都可以实现删除指定的行列数据,读者自行选择一种就可以。

七、 数据清洗

7.1  查看与处理缺失值

缺失值指的是由于某种原因导致数据为空,这种情况一般有四种处理方式:一是不处理;二是删除;三是填充或替换,四是插值(以均值、中位数、众数等填补)。

7.1.1  查看缺失值

首先需要找到缺失值,主要使用DataFrame对象中的info方法。

快速示例37  查看数据概况

以淘宝销售数据为例,首先输出数据,然后使用info方法查看数据,程序代码如下:

01 import pandas as pd

02 df=pd.read_excel('TB2018.xls')

03 print(df)

04 print(df.info())

运行程序,输出结果如图 41所示。

图 41  查看缺失值

在Python中,缺失值一般以NaN表示,如图3.41所示,通过info方法可以看到“买家会员名”“买家实际支付金额”“宝贝标题”和“订单付款时间”的非空数量是10,而“宝贝总数量”和“类别”的非空数量是8,则说明这两项存在空值。

快速示例38  判断数据是否存在缺失值

现在判断数据是否存在缺失值,还可以使用isnull方法和notnull方法,关键代码如下:

01 print(df.isnull())

02 print(df.notnull())

运行程序,输出结果如图 42所示。

图 42  判断是否存在缺失值

使用isnull方法,缺失值返回True;非缺失值返回False;而notnull方法与isnull方法正好相反,即缺失值返回False;非缺失值返回True。

如果使用“df[df.isnull() == False]”语句,则会将所有不是缺失值的数据找出来,但是只针对Series对象。

7.1.2  缺失值删除处理

通过前面的判断得知了数据缺失情况,下面将缺失值删除,主要使用dropna方法,该方法用于删除含有缺失值的行,关键代码如下:

df.dropna()

运行程序,输出结果如图 43所示。

图43  缺失值删除处理效果1

说明:有些时候,数据可能存在整行为空的情况,此时可以在dropna方法中指定参数how='all',删除所有空行。

从运行结果得知:dropna方法将所有包含缺失值的数据全部删除了。那么,此时如果认为有些数据虽然存在缺失值,但是不影响数据分析,那么可以使用以下方法进行处理。例如,在上述数据中只保留“宝贝总数量”中不存在缺失值的数据,而类别是否缺失无所谓,则可以使用notnull方法判断,关键代码如下:

df1=df[df['宝贝总数量'].notnull()]

运行程序,输出结果如图 44所示。

图 44  缺失值删除处理效果2

7.1.3  缺失值填充处理

对于缺失数据,如果比例高于30%,则可以选择放弃这个指标,进行删除处理;低于30%时,尽量不要删除,而是选择将这部分数据填充,一般以0、均值、众数(大多数)填充。DataFrame对象中的fillna函数可以实现填充缺失数据,pad/ffill函数表示用前一个非缺失值去填充该缺失值;backfill/bfill函数表示用下一个非缺失值填充该缺失值;None用于指定一个值去替换缺失值。

快速示例39  将NaN填充为0

对于用于计算的数值型数据,如果为空,可以选择用“0”填充。例如,将“宝贝总数量”为空的数据填充为“0”,关键代码如下:

df['宝贝总数量'] = df['宝贝总数量'].fillna(0)

运行程序,输出结果如图 45所示。

图 45  缺失值填充处理

7.2  重复值处理

对于数据中存在的重复数据,包括重复的行或者某几行中某几列的值重复,一般做删除处理,主要使用DataFrame对象中的drop_duplicates方法。

快速示例40  处理淘宝电商销售数据中的重复数据

下面以“1月.xlsx”的淘宝销售数据为例,对其中的重复数据进行处理。

■ 判断每一行数据是否重复(完全相同)

df1.duplicated()

如果返回值为False,表示不重复;返回值为True,表示重复。

■ 去除全部的重复数据

df1.drop_duplicates()

■ 去除指定列的重复数据

df1.drop_duplicates(['买家会员名'])

■ 保留重复行中的最后一行

df1.drop_duplicates(['买家会员名'],keep='last')

说明:以上代码中参数keep的值有三个。当keep='first'表示保留第一次出现的重复行时,是默认值;当keep为另外两个取值last和False时,分别表示保留最后一次出现的重复行和去除所有的重复行。

■ 直接删除,保留一个副本

df1.drop_duplicates(['买家会员名','买家支付宝账号'],inplace=Fasle)

inplace=True表示直接在原来的DataFrame对象上删除重复项,而默认值False表示删除重复项后再生成一个副本。

7.3  异常值的检测与处理

首先了解一下什么是异常值。在数据分析中,异常值是指超出或低于正常范围的值,如年龄大于200、身高大于3米、宝贝总数量为负数等类似数据。那么这些数据如何检测呢?主要有以下几种方法:

■ 根据给定的数据范围进行判断,不在范围内的数据视为异常值。

■ 均方差。

在统计学中,如果一个数据分布近似正态分布(数据分布的一种形式,呈钟型,两头低,中间高,左右对称,因其曲线呈钟形),那么大约68%的数据值都会在均值的一个标准差范围内,大约95%的数据值会在两个标准差范围内,大约99.7%的数据值会在三个标准差范围内。

■ 箱形图。

箱形图是显示一组数据分散情况资料的统计图。它可以将数据通过四分位数的形式进行图形化描述,箱形图通过上限和下限作为数据分布的边界。任何高于上限或低于下限的数据都可以认为是异常值,如图 46所示。

图 46  箱形图

说明:有关箱形图的介绍以及如何通过箱形图识别异常值可参见第5章的内容。

了解异常值的检测后,接下来介绍如何处理异常值,主要包括以下几种处理方式:

(1)最常用的方式是删除。

(2)将异常值当缺失值处理,以某个值填充。

(3)将异常值当特殊情况进行分析,研究异常值出现的原因。

八、索引设置

索引能够快速查询数据,本节主要介绍索引的作用以及应用。

8.1  索引的作用

索引的作用相当于图书的目录,可以根据目录中的页码快速找到所需的内容。Pandas索引的作用如下:

■ 更方便地查询数据。

■ 使用索引可以提升查询性能。

● 如果索引是唯一的,Pandas会使用哈希表优化,查找数据的时间复杂度为O(1)。

● 如果索引不是唯一的,但是有序,Pandas会使用二分查找算法,查找数据的时间复杂度为O(logN)。

● 如果索引是完全随机的,那么每次查询都要扫描数据表,查找数据的时间复杂度为O(N)。

利用索引实现自动的数据对齐功能,如图 47所示。

图 47  自动数据对齐示意图

实现上述效果,程序代码如下:

01 import pandas as pd

02 s1 = pd.Series([10,20,30],index= list("abc"))

03 s2 = pd.Series([2,3,4],index=list("bcd"))

04 print(s1 + s2)

■ 强大的数据结构。

● 基于分类数的索引,提升性能。

● 多维索引,用于group by多维聚合结果等。

● 时间类型索引,强大的日期和时间的方法支持。

8.2  重新设置索引

Pandas有一个很重要的方法是reindex,它的作用是创建一个适应新索引的新对象。语法如下:

DataFrame.reindex(labels = None,index = None,column = None,axis = None,method = None,copy = True,level = None,fill_value = nan,limit = None,tolerance = None)

常用参数说明:

■ labels:标签,可以是数组,默认值为None。

■ index:行索引,默认值为None。

■ columns:列索引,默认值为None。

■ axis:轴,0表示行;1表示列,默认值为None。

■ method:默认值为None,重新设置索引时,选择插值(用来填充缺失数据)方法,其值可以是None、bfill/backfill(向后填充)、ffill/pad(向前填充)等。

■ fill_value:缺失值要填充的数据。如缺失值不用NaN填充,用0填充,则设置“fill_value=0”即可。

8.2.1  对Series对象重新设置索引

快速示例41  重新设置物理成绩的索引

在3.2.3小节已经建立了一组学生的物理成绩,下面重新设置索引,程序代码如下:

01 import pandas as pd

02 s1=pd.Series([88,60,75],index=[1,2,3])

03 print(s1)

04 print(s1.reindex([1,2,3,4,5]))

运行程序,对比效果如图 48和图 49所示。

图 48  原数据

图 49  重新设置索引

从运行结果得知:reindex方法根据新索引进行了重新排序,并且对缺失值自动填充NaN。如果不想用NaN填充,可以为fill_value参数指定值,例如0,关键代码如下:

s1.reindex([1,2,3,4,5],fill_value=0)

而对于有一定顺序的数据,则可能需要插值来填充缺失的数据,这时可以使用method参数。

快速示例42  向前和向后填充数据

实现向前填充(和前面数据一样)、向后填充(和后面数据一样),关键代码如下:

01 print(s1.reindex([1,2,3,4,5],method='ffill'))   #向前填充

02 print(s1.reindex([1,2,3,4,5],method='bfill'))   #向后填充

8.2.2  对DataFrame对象重新设置索引

对于DataFrame对象,reindex方法用于修改行索引和列索引。

快速示例43  创建成绩表并重新设置索引

通过二维数组创建成绩表,程序代码如下:

01 timport pandas as pd

02 #解决数据输出时列名不对齐的问题

03 pd.set_option('display.unicode.east_asian_width', True)

04 data = [[110,105,99],[105,88,115],[109,120,130]]

05 index=['mr001','mr003','mr005']

06 columns = ['语文','数学','英语']

07 tdf = pd.DataFrame(data=data, index=index,columns=columns)

08 print(df)

通过reindex方法重新设置行索引,关键代码如下:

df.reindex(['mr001','mr002','mr003','mr004','mr005'])

通过reindex方法重新设置列索引,关键代码如下:

df.reindex(columns=['语文','物理','数学','英语'])

通过reindex方法重新设置行索引和列索引,关键代码如下:

df.reindex(index=['mr001','mr002','mr003','mr004','mr005'],columns=['语文','物理','数学','英语'])

运行程序,如图 50所示,为原始数据、重新设置行索引、重新设置列索引、重新设置行列索引。

图 50  原始数据、重新设置行索引、重新设置列索引、重新设置行列索引

8.3  设置某列为索引

设置某列为行索引主要使用set_index方法。

快速示例44  设置“买家会员名”为行索引

首先,导入“1月.xlsx”的Excel文件,程序代码如下:

01 import pandas as pd

02 #解决数据输出时列名不对齐的问题

03 pd.set_option('display.unicode.east_asian_width', True)

04 df=pd.read_excel('1.xlsx')

05 print(df.head())

运行程序,输出结果如图 51所示。

图 51  1月淘宝销售数据(部分数据)

此时默认行索引为0、1、2、3、4,下面将“买家会员名”作为行索引,关键代码如下:

df=df.set_index(['买家会员名'])

运行程序,输出结果如图 52所示。

图 52  设置“买家会员名”为索引

如果在set_index方法中传入参数“drop=True”,则会删除“买家会员名”;如果传入“drop=False”,则会保留“买家会员名”,默认为False。

8.4  数据清洗后重新设置连续的行索引

当我们对Dataframe对象进行数据清洗之后,例如,去掉含NaN的行之后,发现行索引没有变化,对比效果如图 53和图 54所示。

图 53  原始数据效果

图 54  数据清洗后索引还是原来的索引

快速示例45  删除数据后重新设置索引

如果要重新设置索引则可以使用reset_index方法,在删除缺失数据后重新设置索引,关键代码如下:

df=df.dropna().reset_index(drop=True)

运行程序,输出结果如图 55所示。

图 55  数据清洗后重新设置连续的行索引

另外,对于分组统计后的数据,有时也需要重新设置连续的行索引,方法同上。

九、数据排序与排名

本节主要介绍数据的各种排序和排名方法。

9.1  数据排序

DataFrame数据排序时主要使用sort_values方法,该方法类似于SQL中的order by方法。sort_values方法可以根据指定行/列进行排序,语法如下:

DataFrame.sort_values(by,axis=0,ascending=True,inplace=False,kind='quicksort',na_position='last',ignore_index=False)

参数说明:

■ by:要排序的名称列表。

■ axis:轴,0表示行;1表示列,默认按行排序。

■ ascending:升序或降序排序,布尔值,指定多个排序可以使用布尔值列表,降序。

■ inplace:布尔值,默认值为False,如果值为True,则就地排序。

■ kind:指定排序算法,值为“quicksort”(快速排序)、“mergesort”(混合排序)或“heapsort”(堆排),默认值为“quicksort”。

■ na_position:空值(NaN)的位置,值为“first”空值在数据开头,值为“last”空值在数据最后,默认值为“last”。

■ ignore_index:布尔值,是否忽略索引,值为True标记索引(从0开始按顺序的整数值),值为False则忽略索引。

9.1.1  按一列数据排序

快速示例46  按“销量”进行降序排序

按“销量”降序排序,排序的对比效果如图 56和图 57所示。

图 56  原始数据

图 57  按“销量”降序排序

程序代码如下:

01 import pandas as pd

02 excelFile = 'mrbook.xlsx'

03 df = pd.DataFrame(pd.read_excel(excelFile))

04 #设置数据显示的列数和宽度

05 pd.set_option('display.max_columns',500)

06 pd.set_option('display.width',1000)

07 #解决数据输出时列名不对齐的问题

08 pd.set_option('display.unicode.ambiguous_as_wide', True)

09 pd.set_option('display.unicode.east_asian_width', True)

10  #按“销量”列升序排序

11 df=df.sort_values(by='销量',ascending=False)

12 print(df)

9.1.2  按多列数据排序

多列排序是按照给定列的先后顺序进行排序。

快速示例47  按照“图书名称”和“销量”降序排序

按照“图书名称”和“销量”进行降序排序,首先按“图书名称”降序排序,然后再按“销量”降序排序,关键代码如下:

df.sort_values(by=['图书名称','销量'])

排序后的效果如图 58所示。

图 58  按照“图书名称”和“销量”降序排序

9.1.3  对统计结果排序

快速示例48  对分组统计数据进行排序

按“类别”分组统计销量并进行降序排序,排序后的效果如图 59所示。

图 59  按“类别”分组统计销量并降序排序

关键代码如下:

01 df1=df.groupby(["类别"])["销量"].sum().reset_index()

02 df2=df1.sort_values(by='销量',ascending=False)

9.1.4  按行数据排序

快速示例49  按行数据进行排序

按行排序,关键代码如下:

dfrow.sort_values(by=0,ascending=True,axis=1)

注意:按行排序的数据类型要一致,否则会出现错误提示。

9.2  数据排名

排名是根据Series或DataFrame对象的某几列的值进行排名,主要使用rank方法,语法如下:

DataFrame.rank(axis=0,method='average',numeric_only=None,na_option='keep',ascending=True,pct=False)

参数说明:

axis:轴,0表示行;1表示列,默认按行排序。

method:表示在具有相同值的情况下所使用的排序方法。设置值如下:

average:默认值,平均排名。

min:最小值排名。

max:最大值排名。

first:按值在原始数据中的出现的顺序分配排名。

● dense:密集排名,类似最小值排名,但是排名每次只增加1,即排名相同的数据只占一个名次。

numeric_only:对于DataFrame对象,如果设置值为True,则只对数字列进行排序。

na_option:空值的排序方式,设置值如下:

keep:保留,将空值等级赋值给NaN值。

top:如果按升序排序,则将最小排名赋值给NaN值。

bottom:如果按升序排序,则将最大排名赋值给NaN值。

ascending:升序或降序排序,布尔值,指定多个排序可以使用布尔值列表,默认值为True

pct:布尔值,是否以百分比形式返回排名,默认值为False

9.2.1  顺序排名

快速示例50  对产品销量按顺序进行排名

下面对销量相同的产品,按照出现的先后顺序进行排名,程序结果如图所示,程序代码如下:

01 import pandas as pd

02 excelFile = 'mrbook.xlsx'

03 df = pd.DataFrame(pd.read_excel(excelFile))

04 #设置数据显示的列数和宽度

05 pd.set_option('display.max_columns',500)

06 pd.set_option('display.width',1000)

07 #解决数据输出时列名不对齐的问题

08 pd.set_option('display.unicode.ambiguous_as_wide', True)

09 pd.set_option('display.unicode.east_asian_width', True)

10 #按“销量”列降序排序

11 df=df.sort_values(by='销量',ascending=False)

12 # 顺序排名

13 df['顺序排名'] = df['销量'].rank(method="first", ascending=False)

14 print(df[['图书名称', '销量', '顺序排名']])

9.2.2  平均排名

快速示例51  对产品销量进行平均排名

现在对销量相同的产品,按照顺序排名的平均值进行平均排名,关键代码如下:

df['平均排名']=df['销量'].rank(ascending=False)

运行程序,下面对比一下顺序排名与平均值排名的不同,效果如图 60和 61所示。

图 60  销量相同按出现的先后顺序排名

图 61  销量相同按顺序排名的平均值排名

9.2.3  最小值排名

销量相同的,按顺序排名并取最小值作为排名,关键代码如下:

df['销量'].rank(method="min",ascending=False)

9.2.4  最大值排名

销量相同的,按顺序排名并取最大值作为排名,关键代码如下:

df['销量'].rank(method="max",ascending=False)