第1章 python数据分析的概述
由于数据量比较大,已经远远超过了人力所能处理的范畴。那么管理和使用这些数据,就成为一个全新的研究课题
1.1 认识数据分析
数据分析技能,成为数据从业人员需要具备的技能之一。
明确数据分析概念、分析流程、和分析方法等相关知识,成为迈出数据分析的第1步
1.1.1 数据分析的概念
数据分析:就是用适当的方法,对收集来的数据进行分析,提取有用的信息和形成结论。以此帮助企业管理层做出决策
广义的数据分析:狭义数据分析和数据挖掘
1.狭义数据分析:指根据分析目的,采用对比分析、分组分析、交叉分析和回归分析等分析方法,对收集的数据进行处理和分析,提取有价值的信息,发挥数据的作用
2.数据挖掘:是从大量的,不完全的,有噪声的,模糊的,随机的实际应用数据中,通过应用聚类模型,分类模型,回归或关联规则等技术,挖掘潜在的价值的过程。
因此:狭义数据分析后得到的结论是‘指标统计量’
数据挖掘得到的结论是‘模型或规则’
1.1.2 数据分析的流程
需求分析--数据获取--数据预处理--分析与建模--模型评价与优化--部署
1.需求分析:决定了产品的方向
根据业务、生产和财务等部分的需要,结合现有的数据情况,提出数据分析需求的整体分析方向、内容,最终和需求方达成一致意见
2.数据获取:是数据分析的基础
方式:本地数据和网络数据
3.数据预处理:是对数据进行数据合并、清晰、标准化和数据变换的过程
合并:多个表合成一个表
清洗:去掉重复,缺失,异常,不一致的数据
标准化:去掉特征间的量纲差异
数据变换:通过离散化,哑变量等技术满足后期分析和建模的数据需求
4.分析和建模:通过对比/分组/交叉/回归等,以及聚类/分类/关联等方法,发现数据中有价值的信息,并得出结论
分类:如果分析目标是描述客户行为模式,可以采用描述型分析方法,同时还可以考虑关联规则,序列规则,聚类模型
如果分析目标是量化未来一段时间内某个事件发生的概率,则可以使用两大预测分析模型:分类预测模型和回归预测模型
分类预测模型的目标特征都是二元数据
回归预测模型的目标特征是连续型的数据
5.模型评价与优化
不同的模型有不同的指标评价其性能的优劣
聚类模型的评价指标
分类模型的评价指标
回归模型的评价指标:
模型优化是在模型评价后,如果进入实际生产环境应用后,模型的性能不理想的话,进而对模型进行重构和优化的过程
6.部署
是将数据分析结果与结论应用到实际生产系统的过程
具体内容:
可以是一份整改措施的报告
也可以是将模型部署到整个生产系统的解决方案
1.1.3 数据分析应用场景
客户分析:界定目标客户--了解客户的采购过程--客户特征分析,忠诚度分析,注意力分析,收益分析,营销分析
目的:将客户细分,使得运营策略达到最优
营销分析:产品分析--价格分析--渠道分析--广告与促销分析
社交媒体分析:用户分析--访问分析--互动分析
网络安全:
设备管理:
交通物流分析:
欺诈行为分析:
1.2 熟悉python数据分析的工具
是数据分析的首选语言
1.2.1 数据分析的常用工具:python、R、MATLAB
python:有强大的库
R:用于统计分析,绘图的语言
MATLAB:矩阵运算,回执函数与数据、实现算法
1.2.2 python数据分析的优势
语法简单--又很多库--功能强大--模型构建--胶水语言
1.2.3 python数据分析常用类库
Ipython:是py科学计算标准工具集的组成部分
NumPy:科学计算基础包
1.多维数据对象ndarray
2.数组元素级计算
3.读写硬盘上基于数组的工具
4.随机数生成功能
5.作为算法之间传递数据的容器
ScriPy:解决科学计算中各种标准问题域的模块的集合
pandas:数据分析核心库
1.为时间序列分析提供了很好的支持
Matplotlib:用于绘制图表的库
scikit-learn:数据挖掘和数据分析工具,对一些常用的算法进行了封装。基本模块包括(数据预处理,模型选择,分类,聚类,数据降维,回归)
Spyder:是交互式的Python语言开发环境
1.3 安装python的Anaconda发行版
https://www.anoconda.com/download
特点:开源免费--全平台支持--包含了众多库
1.4 jupyter notebook常用
代码功能和Markdown功能
第2章 NumPy数值计算基础
特点:1.科学计算 2.多维数据的容器 3.存储/处理大型矩阵
3.容器可以保存任意类型的数据
2.1 NumPy的数组对象ndarray
任务描述:python中有一个array模块,但不支持多维,也没有函数,因此要使用
NumPy中的ndarray
2.1.1 创建数组对象
说明:NumPy提供了两种基本的对象:ndarray(N-dimensional Array Object)多维数组
ufunc(Universal Function Object) 通用函数
ndarray特点:存储单一数据类型的多维数组
ufunc特点:能够对数组进行处理的函数
1.数组属性
ndim 维度
shape 尺寸,形状(几行几列)
size 元素总数
dtype 元素类型
itemsize 每一个元素的大小
2.数据创建
方法1:numpy.array(数组名)
可以建立一维数组,可以建立二维数组,还可以改变维度
2.1改变维度:数组名.shape = (m,n)
特点:先创建一个python序列,然后再将其转换为数组,效率低
方法2:用arange函数创建
np.arange(开始,结束,步长)
特点:不包含结束值
例如:np.arange(1,10,1)
np.linspace(开始,结束,元素个数)
特点:包含结束值
例如:np.linspace(1,10,5)
np.logspace(开始幂,结束幂,元素个数)
例如:np.logspace(0,5,5)
np.zeros((m,n)) 全为0的数组(m行n列)
np.eye(m,n) 单位矩阵 (m行n列)
np.diag([1,2,3,4]) 对角线的值为1,2,3,4
np.ones((m,n)) 全为1的矩阵(m行n列)
3.数据数据类型
特点:所有数组的数据类型是一样的。
类型列表:bool,inti,int8,int16,int32,int64,
uint8,uint16,uint32,uint64,
float16,float32
complex
数组类型转换函数:
float,int,bool
修改数组的数据类型:
数组名.dtype = np.类型名
创建数据类型:
df = np.dtype([('name',np.str_,40),('numitems',np.int64),('price',np.float64)])
用以上创建的类型创建数组
np.array([('曹操',20,34.5),('刘备',20,34.5)],dtype = df)
2.1.2 生成随机数
np.random.random(100) --100个0-1之间的数
np.random.rand(10,5) --10行5列均匀分布的数
np.random.randn(10,5) --10行5列正态分布的数
np.random.randint(最小值,最大值,size = (10,5)) --10行5列的数
np.random.Shuffle(arr1) --对数组进行随机排序,并返回排序的结果,(打乱顺序)
2.1.3 通过索引访问数组
1.一维数组的索引
类似于python的list的索引
2.多维数组的索引
arr2[2,3]
2.1.4 变换数组的形态
1.改变形态
数组名.reshape(m,n) --不改变原始数组的形态
2.数据展平
数组名.ravel() --数组横向展平
数组名.flatten() --数据横向展平
数组名.flatten('f') --数据纵向展平
3.数据组合
np.hstack((数组1,数组2))
np.vstack((数组1,数组2))
np.concatenate((数组1,数组2),axis = 1/0)
说明:axis为1表示横向组合
axis为0表示纵向组合
4.数组分割
np.hsplit(数组,n) 横向分割
np.vsplit(数组,n) 纵向分割
np.split(数组,n,axis=1/0)
2.2 掌握NumPy矩阵与通用函数
数组和矩阵的区别:
数组包含:n维数组对象和通用函数对象
矩阵:是继承自二维数组对象,要单独用命令创建
矩阵计算方便:矩阵相乘 *
数组相乘 .dot
2.2.1 创建NumPy矩阵
np.mat("1,2,3;4,5,6")
np.mat([(1,2,3),(4,5,6)])
np.matrix("1,2,3;4,5,6")
np.matrix([(1,2,3),(4,5,6)])
np.bmat('arr1,arr2;arr1,arr2') --小矩阵组合成大矩阵
matr2 = matr1*3
matr2 = matr1-3
matr2 = matr1+3
matr2 * matr1 --矩阵点乘
T --返回自身的转置
H --返回自身的共轭转置
I --逆矩阵
A --返回视图
2.2.2 掌握ufunc函数
说明:是一种对数组中的所有元素进行操作的函数
1.常用的ufunc函数运算
四则运算是对数组中的每个元素进行计算,因此四则运算的两个数组的形状必须相同
+ - * /
< > == <= !=
np.all(x == y)
np.any(x == y)
2.ufunc函数的广播机制
特点:输入数组向其中shape最长的数组看齐,不足的部分在前面加1补齐
输出数组的shape是输入数组各个轴上的最大值
一维数组和二维数组的广播机制为例.
2.3 利用NumPy进行统计分析
2.3.1 读/写文件
学会读写文件是利用Numpy进行数据处理的基础
1.也可以把结果存储到二进制或文本文件中。
2.提供了从文件读取数据并将其转换为数组的方法
1.save函数以二进制的格式保存数据
命令1:np.save(文件路径,数组)
说明:文件扩展名为.npy
import numpy as np
arr = np.arange(100).reshape(10,10)
np.save('C:/Users/peter/Desktop/数据分析/bit1',arr)
命令2:np.savez(文件路径,数组列表)
说明:多个数组保存到1个文件中,扩展名为Npz
2.load函数从二进制的文件中读取数据
load_data = np.load(文件名)
读取有一个数组的文件时,直接访问即可
读取有多个数组的文件时,需要用关键字访问
load_data['arr_0'] load_data['arr_1']等
3.在实际的数据分析中,我们更多的是将数据存储到txt或csv格式的文件中
np.savetxt('C:/Users/peter/Desktop/数据分析/text1.txt',arr,fmt = '%d',delimiter = ',')
说明:保存到text文件中,保存的格式是整数,分隔符是逗号
方法1:
load_arr2 = np.loadtxt('C:/Users/peter/Desktop/数据分析/text2.txt',delimiter = ',',dtype=str)
方法2:
注意:1.要导入的文本文档中,是汉字字符时,使用dtype格式限定
2.如果导入的数据的类型不同,就先定义类型
例如:
df = np.dtype([('name',np.str_,40),('sex',np.str_,4),('age',np.int32),('class',np.str_,40)]) --定义类型
load_arr4 = np.genfromtxt('C:/Users/peter/Desktop/数据分析/text2.txt',delimiter = ',',dtype=df) --导入文本文档,以df的格式
2.3.2 使用函数进行简单的统计分析
1.排序
分类:直接排序和间接排序
直接排序:就是把数值直接排序即可
间接排序:就是指定一个或多个键来进行排序
1.直接排序的名(sort)
例如:
np.random.seed(42)
arr1 = np.random.randint(1,10,size=10)
arr1.sort()
arr2 = np.random.randint(1,10,size=(3,3))
arr2.sort(axis=1)
arr2.sort(axis=0)
2.指定一个或多个键进行排序(argsort和lexsort)
arr2 = np.random.randint(1,10,size=10)
arr2.argsort() --返回的值是重新排序值的下标
a = np.array([3,2,6,4,5])
b = np.array([5,3,4,1,2])
c = np.array([4,3,6,1,1])
d = np.lexsort((a,b,c))
print(d) --排序后下标的顺序
print(list(zip(a[d],b[d],c[d]))) --zip解压后,排序的值的顺序
2.去重与重复数据
重复数据就是脏数据之一,去掉重复值numpy中用unique
arr1= np.array([1,2,2,2,3,4,5,5,1,1,5])
去重方法1:
np.unique(arr1) --去掉重复值,并返回排序后的结果
等价于sorted(set(arr1))
二维数组,怎么用这两种方法完成?
重复数据方法:
1.np.tile(数组,重复次数) --对数组进行操作
2.数组名.repeat(重复次数,axis=1/0) --对数组中的元素操作
3.常用的统计函数
聚合函数:sum,mean,std,var,min,max
聚合函数就是,直接产出一个最后结果
注意:一定要注意轴的概念,否则默认的是一个总值
axis = 0 --纵轴
axis = 1 --横轴
默认的是计算一个总值
argmin() --最小元素的索引
argmax() --最大元素的索引
np.sum(arr4)
np.mean(arr4)
np.std(arr4)
np.var(arr4)
不聚合函数:cumsum cumprod
2.3.3
作业一:1.导入数据iris_seqal_length.csv中的数据到数组arr1中
2.去重并排序,将结果放入arr2中
3.计算数组arr1的累计和
4.计算数组arr1的和,均值,标准差,方差,最小值,最大值
作业二:生成一个国际象棋的棋盘
1.创建一个8*8的矩阵
2.1,3,5,7行为1;2,4,6为0
作业三:创建一个数值范围为0-1,间隔为0.01的数组
创建100个服从正态分布的随机数
对随机数数组进行简单的统计分析
对两个数组进行四则运算
作业四:生成两个2*2的矩阵,并计算矩阵的乘积
生成1个0-1之间,服从均匀分布的数组
第3章 Matplotlib数据可视化基础
说明:mat--plot--lib
应用最多的是pyplot模块
3.1 掌握绘图基础语法与常用参数
说明:每一幅图的绘制都涉及为数不少的参数,我们掌握参数的设置后,才能更好的辅助绘制图形
3.1.1 掌握pyplot基础语法
pyplot基本绘制流程有三部分
1.创建画布与创建子图
作用:创建空白画布,并可以选择是否将画布划分成多个部分,方便在同一个图上绘制多个图形
函数1:plt.figure 创建空白画布,可以指定大小和像素
函数2:plt.add_subplot 创建并选中子图,指定子图的行/列数和选中图片的编号
注意:只是绘制一幅简单的图形是,这个画布可以省略
但要绘制子图时,画布必须有
import numpy as np
import matplotlib.pyplot as plt
data = np.arange(0,1.1,0.01)
p1 = plt.figure(figsize = (8,6),dpi=80)
ax1 = p1.add_subplot(2,2,1)
#plt.plot(data,data**2)
ax2 = p1.add_subplot(2,2,2)
#plt.plot(data,data*np.pi)
plt.savefig('C:/Users/peter/Desktop/数据分析/a1.jpg')
plt.show()
2.添加画布内容
包含:
标题 --plt.title(字符串)
坐标轴名称 --plt.xlabel(字符串),plt.ylabel(字符串)
坐标轴取值范围 --plt.xlim((元组)) ,plt.ylim((元组))
坐标轴刻度 --plt.xsticks([列表]),plt.ysticks([列表])
绘制图形 --plt.plot(x轴,y轴)
图例 --plt.legend()
3.保存与显示图形
plt.savefig('路径')
plt.show()
例如1:
#绘制测试图形
import numpy as np
import matplotlib.pyplot as plt
data = np.arange(0,10,2)
plt.figure(figsize=(6,8),dpi=80)
#绘制sin和cos
import numpy as np
import matplotlib.pyplot as plt
data = np.arange(0,np.pi*2,0.01)
plt.rcParams['font.sans-serif'] = 'SimHei' #设置中文字体
#plt.rcParams['axes.unicode_minus'] = False #设置正常显示符号
p1 = plt.figure(figsize=(6,8),dpi=80)
ax1 = p1.add_subplot(2,1,1) --绘制子图
plt.title('测试图形')
plt.xlabel('x轴')
plt.ylabel('y轴')
plt.xlim((0,np.pi*2))
plt.ylim((-1,1))
plt.yticks([-1,-0.5,0,0.5,1])
plt.xticks([0,np.pi/2,np.pi,np.pi*1.5,np.pi*2])
plt.plot(data,np.sin(data)) #绘制三角函数
plt.plot(data,np.cos(data))
plt.legend(['sin','cos'])
plt.savefig('C:/Users/peter/Desktop/数据分析/a2.jpg')
plt.show()
ax2 = p1.add_subplot(2,1,2)
plt.title('测试图形')
plt.xlabel('x轴')
plt.ylabel('y轴')
plt.xlim((0,1))
plt.ylim((0,1))
plt.xticks([0,0.2,0.4,0.6,0.8,1])
plt.yticks([0,0.2,0.4,0.6,0.8,1])
plt.plot(data,data**2)
plt.plot(data,data**4)
plt.legend(['y = x^2','y=x^4'])
plt.savefig('C:/Users/peter/Desktop/数据分析/a2.jpg')
plt.show()
3.1.2 设置pyplot的动态rc参数
说明:所有存储在字典变量中的rc参数,被称为rcParams
包含:窗口大小
每英寸点数
线条宽度 #lines.linewidth取值0-10之间
颜色
线条样式 #lines.linestyle - -- -. :
线条上点的形状 #lines.marker o D h . , S
线条上点的尺寸 #lines.markersize 0-10
坐标轴
坐标
网格属性
文本
字体
例如2:
import numpy as np
import matplotlib.pyplot as plt
data = np.arange(0,np.pi*2,0.01)
plt.rcParams['font.sans-serif']='SimHei' #设置显示中文字体
plt.rcParams['axes.unicode_minums'] = False #设置正常显示符号
pl = plt.figure(figsize=(8,8),dpi=80)
#plt.title('测试图形')
plt.rcParams['lines.linestyle']='-.' #设置线条样式
plt.rcParams['lines.linewidth']=3 #设置线条宽度
plt.plot(data,data**2,label = '$sin(x)$')
plt.show()
3.2 分析特征间的关系
说明:散点图(用来分析特征间的相关关系)
折线图(用来分析自变量和因变量特征之间的趋势关系)
3.2.1 绘制散点图
原理:一个特征为横坐标,另一个为纵坐标,利用坐标点的分布形态,反映特征间的分布形态
说明:值有点在图表中的位置表示,类别由图表中的标记表示,通常用来比较跨类别的数据
语法:plt.scatter(values[:,0],values[:,2],marker='o',c='red')
例如3:
import numpy as np
import matplotlib.pyplot as plt
data = np.load('F:/曹晓龙课程/课程/数据分析/第3章/任务程序/data/国民经济核算季度数据.npz')
plt.rcParams['font.sans-serif']='SimHei'
plt.rcParams['axes.unicode_minus']=False
name = data['columns'] #取数据的列标题
values = data['values'] #取数据的值
plt.figure(figsize=(8,7))
plt.title('散点图')
plt.scatter(values[:,0],values[:,2],marker='o',c='red')
plt.scatter(values[:,0],values[:,3],marker='D',c='blue')
plt.scatter(values[:,0],values[:,4],marker='h',c='yellow')
plt.xticks(range(0,70,4),values[range(0,70,4),1],rotation=45) #把列标题作为x坐标出现,rotation切斜
plt.ylim((0,np.max(values[:,2]+1000)))
plt.savefig('F:/曹晓龙课程/课程/数据分析/第3章/任务程序/data/a.jpg')
plt.show()
3.2.2 绘制折线图
说明:查看因变量y随自变量x改变的趋势,最适合用于随时间而变化的连续数据
还可以看出数量的差异,增长趋势的变化
语法:plt.plot(values[:,0],values[:,2],marker='o',c='red')
属性:color # b g r y w m:品红 c:青色 k:黑色
linestyle #--
alpha #0-1
import numpy as np
import matplotlib.pyplot as plt
data = np.load('F:/曹晓龙课程/课程/数据分析/第3章/任务程序/data/国民经济核算季度数据.npz')
plt.rcParams['font.sans-serif']='SimHei'
plt.rcParams['axes.unicode_minus']=False
name = data['columns'] #取数据的列标题
values = data['values'] #取数据的值
plt.figure(figsize=(8,7))
plt.title('散点图')
plt.plot(values[:,0],values[:,2],linestyle='--',c='red')
plt.scatter(values[:,0],values[:,3],marker='D',c='blue')
plt.scatter(values[:,0],values[:,4],marker='h',c='yellow')
#等价于
plt.plot(values[:,0],values[:,2],'bs-',
values[:,0],values[:,3],'ro-',
values[:,0],values[:,4],'gH-')
plt.xticks(range(0,70,4),values[range(0,70,4),1],rotation=45) #把列标题作为x坐标出现,rotation切斜
plt.ylim((0,np.max(values[:,2]+1000)))
plt.savefig('F:/曹晓龙课程/课程/数据分析/第3章/任务程序/data/a.jpg')
plt.show()
3.3 分析特征内部数据分布与分散状况
说明:主要用于分析数据内部的分布状态和分散状态,
直方图:查看各组数据的数量分布,及数量比较 --数量状况
饼图:查看各组数据在总数据中的占比 --占比情况
箱线图:发现整体数据的分布分散情况 --分散情况
3.3.1 绘制直方图
作用:能直观地看出产品质量特性的分布状态,便于判断总体质量分布情况
plt.bar(left,height,width = 0.8,color='')
#2017年三个产品的数据直方图
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = 'SimHei'## 设置中文显示
plt.rcParams['axes.unicode_minus'] = False
data = np.load('F:/曹晓龙课程/课程/数据分析/第3章/任务程序/data/国民经济核算季度数据.npz')
name = data['columns']## 提取其中的columns数组,视为数据的标签
values = data['values']## 提取其中的values数组,数据的存在位置
label = ['第一产业','第二产业','第三产业']## 刻度标签
plt.figure(figsize=(6,5))## 设置画布
plt.bar(range(3),values[-1,3:6],width = 0.5,data = values[-1,3:6])## 绘制散点图
plt.xlabel('产业')## 添加横轴标签
plt.ylabel('生产总值(亿元)')## 添加y轴名称
plt.xticks(range(3))
plt.title('2017年第一季度各产业国民生产总值直方图')## 添加图表标题
plt.savefig('F:/曹晓龙课程/课程/数据分析/第3章/2017年第一季度各产业国民生产总值直方图.png')
plt.show()
3.3.2 绘制饼图
作用:易于显示每组数据相对于总体的大小
格式:
plt.pie(x,explode,labels,autopct)
说明:
x:表示绘制饼图的数据
explode:指定距离饼图圆心的距离 --间隔
pctdistance: autopct距离圆心的距离
labeldistance: 标签距离圆心的距离
radius:饼图的半径
labels:指定每一项的名称
autopct:值的显示方式
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = 'SimHei'## 设置中文显示
plt.rcParams['axes.unicode_minus'] = False
data = np.load('F:/曹晓龙课程/课程/数据分析/第3章/任务程序/data/国民经济核算季度数据.npz')
name = data['columns']## 提取其中的columns数组,视为数据的标签
values = data['values']## 提取其中的values数组,数据的存在位置
plt.figure(figsize=(6,6))## 将画布设定为正方形,则绘制的饼图是正圆
label= ['第一产业','第二产业','第三产业']## 定义饼状图的标签,标签是列表
explode = [0.01,0.01,0.01]## 设定各项离心n个半径
plt.pie(values[-1,3:6],explode=explode,labels=label,
autopct='%1.1f%%')## 绘制饼图
plt.title('2017年第一季度各产业国民生产总值饼图')
plt.savefig('F:/曹晓龙课程/课程/数据分析/第3章/2017年第一季度各产业生产总值占比饼图')
plt.show()
3.3.3 绘制箱线图
作用:能提供有关数据位置和分散情况的关键信息
说明:该图利用数据中的5个统计量(最小值,下四分位数,中位数,上四分位数,最大值)
来描述数据
格式:plt.boxplot(x,notch,labels,meanline)
说明:x 表示用于绘制箱线图的数据
notch 表示中间箱体是否有缺口
sym 指定异常点的形状
lagels 指定标签
meanline 表示是否显示均值线
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = 'SimHei'## 设置中文显示
plt.rcParams['axes.unicode_minus'] = False
data = np.load('F:/曹晓龙课程/课程/数据分析/第3章/任务程序/data/国民经济核算季度数据.npz')
name = data['columns']## 提取其中的columns数组,视为数据的标签
values = data['values']## 提取其中的values数组,数据的存在位置
plt.figure(figsize=(6,6))## 将画布设定为正方形,则绘制的饼图是正圆
label= ['第一产业','第二产业','第三产业']## 定义标签
gdp = (list(values[:,3]),list(values[:,4]),list(values[:,5]))
plt.figure(figsize=(6,4))
plt.boxplot(gdp,notch=True,labels = label, meanline=True)
plt.title('2000-2017各产业国民生产总值箱线图')
plt.savefig('F:/曹晓龙课程/课程/数据分析/第3章/2000-2017各产业国民生产总值箱线图.png')
plt.show()
作业:
绘制国民生产总值构成分布直方图
# 代码 3-15
import numpy as np
import matplotlib.pyplot as plt
data = np.load('F:/曹晓龙课程/课程/数据分析/第3章/任务程序/data/国民经济核算季度数据.npz')
name = data['columns'] ## 提取其中的columns数组,视为数据的标签
values = data['values']## 提取其中的values数组,数据的存在位置
plt.rcParams['font.sans-serif'] = 'SimHei' ## 设置中文显示
plt.rcParams['axes.unicode_minus'] = False
label1 = ['第一产业','第二产业','第三产业']## 刻度标签1
label2 = ['农业','工业','建筑','批发','交通',
'餐饮','金融','房地产','其他']## 刻度标签2
p = plt.figure(figsize=(12,12))
## 子图1
ax1 = p.add_subplot(2,2,1)
plt.bar(range(3),values[0,3:6],width = 0.5)## 绘制散点图
plt.xlabel('产业')## 添加横轴标签
plt.ylabel('生产总值(亿元)')## 添加y轴名称
plt.xticks(range(3),label1)
plt.title('2000年第一季度国民生产总值产业构成分布直方图')
## 子图2
ax2 = p.add_subplot(2,2,2)
plt.bar(range(3),values[-1,3:6],width = 0.5)## 绘制散点图
plt.xlabel('产业')## 添加横轴标签
plt.ylabel('生产总值(亿元)')## 添加y轴名称
plt.xticks(range(3),label1)
plt.title('2017年第一季度国民生产总值产业构成分布直方图')
## 子图3
ax3 = p.add_subplot(2,2,3)
plt.bar(range(9),values[0,6:],width = 0.5)## 绘制散点图
plt.xlabel('行业')## 添加横轴标签
plt.ylabel('生产总值(亿元)')## 添加y轴名称
plt.xticks(range(9),label2)
plt.title('2000年第一季度国民生产总值行业构成分布直方图')## 添加图表标题
## 子图4
ax4 = p.add_subplot(2,2,4)
plt.bar(range(9),values[-1,6:],width = 0.5)## 绘制散点图
plt.xlabel('行业')## 添加横轴标签
plt.ylabel('生产总值(亿元)')## 添加y轴名称
plt.xticks(range(9),label2)
plt.title('2017年第一季度国民生产总值行业构成分布直方图')## 添加图表标题
## 保存并显示图形
plt.savefig('F:/曹晓龙课程/课程/数据分析/第3章/国民生产总值构成分布直方图.png')
plt.show()
# 代码 3-16
label1 = ['第一产业','第二产业','第三产业']## 标签1
label2 = ['农业','工业','建筑','批发','交通',
'餐饮','金融','房地产','其他']## 标签2
explode1 = [0.01,0.01,0.01]
explode2 = [0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01]
p = plt.figure(figsize=(12,12))
## 子图1
ax1 = p.add_subplot(2,2,1)
plt.pie(values[0,3:6],explode=explode1,labels=label1,
autopct='%1.1f%%')## 绘制散点图
plt.title('2000年第一季度国民生产总值产业构成分布饼图')
## 子图2
ax2 = p.add_subplot(2,2,2)
plt.pie(values[-1,3:6],explode=explode1,labels=label1,
autopct='%1.1f%%')## 绘制散点图
plt.title('2017年第一季度国民生产总值产业构成分布饼图')
## 子图3
ax3 = p.add_subplot(2,2,3)
plt.pie(values[0,6:],explode=explode2,labels=label2,
autopct='%1.1f%%')## 绘制散点图
plt.title('2000年第一季度国民生产总值行业构成分布饼图')## 添加图表标题
## 子图4
ax4 = p.add_subplot(2,2,4)
plt.pie(values[-1,6:],explode=explode2,labels=label2,
autopct='%1.1f%%')## 绘制散点图
plt.title('2017年第一季度国民生产总值行业构成分布饼图')## 添加图表标题
## 保存并显示图形
plt.savefig('F:/曹晓龙课程/课程/数据分析/第3章/国民生产总值构成分布饼图.png')
plt.show()
# 代码 3-17
label1 = ['第一产业','第二产业','第三产业']## 标签1
label2 = ['农业','工业','建筑','批发','交通',
'餐饮','金融','房地产','其他']## 标签2
gdp1 = (list(values[:,3]),list(values[:,4]),list(values[:,5]))
gdp2 = ([list(values[:,i]) for i in range(6,15)])
p = plt.figure(figsize=(8,8))
## 子图1
ax1 = p.add_subplot(2,1,1)
## 绘制散点图
plt.boxplot(gdp,notch=True,labels = label1, meanline=True)
plt.title('2000-2017各产业国民生产总值箱线图')
plt.ylabel('生产总值(亿元)')## 添加y轴名称
## 子图2
ax2 = p.add_subplot(2,1,2)
## 绘制散点图
plt.boxplot(gdp2,notch=True,labels = label2, meanline=True)
plt.title('2000-2017各行业国民生产总值箱线图')
plt.xlabel('行业')## 添加横轴标签
plt.ylabel('生产总值(亿元)')## 添加y轴名称
## 保存并显示图形
plt.savefig('F:/曹晓龙课程/课程/数据分析/第3章/国民生产总值分散情况箱线图.png')
plt.show()
作业实训1:
# 代码 3-15
import numpy as np
import matplotlib.pyplot as plt
data = np.load('F:/曹晓龙课程/课程/数据分析/第3章/实训数据/populations.npz')
arr1 = np.array(data)
print(arr1)
name = data['feature_names'] ## 提取其中的columns数组,视为数据的标签
values = data['data']## 提取其中的values数组,数据的存在位置
values1 = values.T
plt.rcParams['font.sans-serif'] = 'SimHei' ## 设置中文显示
plt.rcParams['axes.unicode_minus'] = False
print(name)
print(values1)
label1 = values1[0,:20]## 刻度标签1
p = plt.figure(figsize=(12,12))
x = np.arange(0,40,2)+1
print(x)
## 子图1
ax1 = p.add_subplot(2,2,1)
#plt.scatter(values[:20,0],values[:20,1],marker = 'D',c='red')## 绘制散点图
#plt.scatter(values[:20,0],values[:20,2],marker = 'H',c='blue')## 绘制散点图
#plt.scatter(values[:20,0],values[:20,3],marker = 'o',c='yellow')## 绘制散点图
#plt.scatter(values[:20,0],values[:20,4],marker = 's',color = 'c')## 绘制散点图
#plt.scatter(values[:20,0],values[:20,5],marker = '.',color = 'k')## 绘制散点图
plt.bar(x,values1[2,:20],width = 0.5)
plt.bar(x+0.5,values1[3,:20],width = 0.5)
plt.xlabel('时间')## 添加横轴标签
plt.ylabel('人口')## 添加y轴名称
plt.xticks(range(0,40,2),label1,rotation=45)
plt.legend(['男','女'])
plt.title('2000年第一季度国民生产总值产业构成分布直方图')
plt.show()
第4章 pandas统计分析基础
统计分析:运用统计方法,将定量与定性结合,进行的研究活动叫统计分析
注意:处理对数值型特征的数据进行集中趋势,离散趋势和峰度与偏度的统计外,还包含了多个特征比较计算等知识
4.1 读写不同数据源的数据
说明:数据读取是进行数据预处理、建模与分析的前提;pandas常见的数据源有3种:数据库,文本文件,和excel文件。基本可以完成80%的工作
4.1.1 读写数据库数据
说明:除了使用pandas库外,还要使用sqlalchemy库中的链接类
1.数据库数据的读取有三个函数
read_sql: 既能读取,还能查询
read_sql_table :只能读取,不能查询
read_sql_query :只能查询,不能读取
格式1:pd.read_sql_table(表名,con,schema,columns)
格式2:pd.read_sql_query(sql语句,con)
格式3:pd.read_sql(sql语句,con,
参数说明:columns 接收list,表示读取数据的列名
coerce_float 接收bool,将decimal类型转换为float类型
index_col 接收int,表示设定的列作为行名
导入sql脚本文件到数据库中
进入到sql -- 进入到数据库 -- source *.sql
#建立数据库的链接,并创建链接对象
from sqlalchemy import create_engine
import pymysql
engine = create_engine('mysql+pymysql://root:123@localhost:3306/test?charset=utf8')
con = pymysql.connect('localhost','root','123','test')
print(engine)
#查看数据库中的表
import pandas as pd
## 使用read_sql_query查看tesdb中的数据表数目
formlist = pd.read_sql_query('show tables', con = engine)
print('testdb数据库数据表清单为:','\n',formlist)
#读取表
## 使用read_sql_table读取订单详情表
detail1 = pd.read_sql_table('meal_order_detail1',con = engine)
print('使用read_sql_table读取订单详情表的长度为:',len(detail1))
#使用read_sql读取表
## 使用read_sql读取订单详情表
detail2 = pd.read_sql('select * from meal_order_detail2',
con = engine)
print('使用read_sql函数+sql语句读取的订单详情表长度为:',len(detail2))
detail3 = pd.read_sql('meal_order_detail2',con = engine)
print('使用read_sql函数+表格名称读取的订单详情表长度为:',
len(detail3))
2.数据库数据存储
格式:DataFrame.to_sql(表名,con,if_exists,dtype)
if_exists: fail(不写)
replace(替换)
append(追加)
dtype:接收dict,代表写入的数据类型(列名为key,数据格式为values)
# 代码 4-3
## 使用to_sql存储orderData
detail1.to_sql('test1',con = engine,index = False,
if_exists = 'replace')
## 使用read_sql读取test表
formlist1 = pd.read_sql_query('show tables',con = engine)
print('新增一个表格后testdb数据库数据表清单为:','\n',formlist1)
4.1.2 读写文本文件
文本文件:是一种典型的顺序文件
csv文件:是一种用分隔符分隔的文件,是以纯文本的形式存储表格数据,广泛应用于程序之间转移表格数据。大量程序都支持csv格式,因此可以作为大多数程序的输入输出格式
1.文本文件读取
格式1:pd.read_table(路径,sep,header=‘infer’,names,encoding = utf-8)
格式2:pd.read_csv(路径,sep,header,names,encoding=utf-8)
说明:
sep:csv默认为逗号, table默认为tab
header:int,表示将某行数据作为列名,infer表示自动识别
names:array,接收的数组名
dtype:dict,表示数据的类型
nrows:int 表示读取几行
####正常读取
# 代码 4-4
## 使用read_table读取订单信息表
order = pd.read_table('../data/meal_order_info.csv',
sep = ',',encoding = 'gbk')
print('使用read_table读取的订单信息表的长度为:',len(order))
## 使用read_csv读取订单信息表
order1 = pd.read_csv('../data/meal_order_info.csv',
encoding = 'gbk')
print('使用read_csv读取的订单信息表的长度为:',len(order1))
####以;分隔的时候读取
# 代码 4-5
## 使用read_table读取菜品订单信息表,sep = ';'
order2 = pd.read_table('../data/meal_order_info.csv',
sep = ';',encoding = 'gbk')
print('分隔符为;时订单信息表为:\n',order2)
####以header设置为None时候的读取
## 使用read_csv读取菜品订单信息表,header=None
order3 = pd.read_csv('../data/meal_order_info.csv',
sep = ',',header = None,encoding = 'gbk')
print('订单信息表为:','\n',order3)
####读取格式为utf-8时候的读取
## 使用gbk解析菜品订单信息表
order4 = pd.read_csv('../data/meal_order_info.csv',
sep = ',',encoding = 'utf-8')
2.文本文件存储
语法格式:DataFrame.to_csv(路径,sep,clolumns,header,mode,encoding)
说明:sep 分隔符
columns list --列名
header bool --是否将列名写出
mode string --w
encoding string --字符串
# 代码 4-6
import os
print('订单信息表写入文本文件前目录内文件列表为:\n',
os.listdir('../tmp'))
## 将order以csv格式存储
order.to_csv('../tmp/orderInfo.csv',sep = ';',index = False)
print('订单信息表写入文本文件后目录内文件列表为:\n',
os.listdir('../tmp'))
4.1.3 读写excel文件
1.excel文件读取
pd.read_excel(路径,sheetname=0,header=0,names = None,dtype)
说明:sheetname excel表内数据的分表位置
names
# 代码 4-7
user = pd.read_excel('../data/users.xlsx')## 读取user.xlsx文件
print('客户信息表长度为:',len(user))
2.excel文件存储
DataFrame.to_excel(路径,sheet_name=‘None’,mode='w')
# 代码 4-8
print('客户信息表写入excel文件前目录内文件列表为:\n',
os.listdir('../tmp'))
user.to_excel('../tmp/userInfo.xlsx')
print('客户信息表写入excel文件后目录内文件列表为:\n',
os.listdir('../tmp'))
########作业代码
# 代码 4-9
## 导入SQLAlchemy库的creat_engine函数
from sqlalchemy import create_engine
import pandas as pd
## 创建一个mysql连接器,用户名为root,密码为1234
## 地址为127.0.0.1,数据库名称为testdb
engine = create_engine('mysql+pymysql://root:[email protected]:\
3306/testdb?charset=utf8')
## 使用read_sql_table读取订单详情表格
order1 = pd.read_sql_table('meal_order_detail1',con = engine)
print('订单详情表1的长度为:',len(order1))
order2 = pd.read_sql_table('meal_order_detail2',con = engine)
print('订单详情表2的长度为:',len(order2))
order3 = pd.read_sql_table('meal_order_detail3',con = engine)
print('订单详情表3的长度为:',len(order3))
# 代码 4-10
## 使用read_table读取订单信息表
orderInfo = pd.read_table('../data/meal_order_info.csv',
sep = ',',encoding = 'gbk')
print('订单信息表的长度为:',len(orderInfo))
# 代码 4-11
## 读取user.xlsx文件
userInfo = pd.read_excel('../data/users.xlsx',
sheetname = 'users1')
print('客户信息表的长度为:',len(userInfo))
4.2 掌握DataFrame的常用操作
说明:DataFrame是pandas对象,完成读取后,数据以DataFrame数据结构存储在内存中。
但不能直接做分析,我们要用DataFrame的属性和方法对数据的分布,大小等基本情况做一个了解。这样我们才能够进行量身定制的统计分析
补充知识点:
dataframe转化成array
df=df.values
array转化成dataframe
import pandas as pd
df = pd.DataFrame(df)
4.2.1 查看DataFrame的常用属性
1.DataFrame的基本属性有
values 元素
index 索引
columns 列名
dtypes 类型
detail.size
detail.ndim
detail.shape
detail.T
4.2.2 查改增删DataFrame数据
DataFrame作为一种二维数据表结构,能够像数据库一样实现增删改查操作
1.查看访问DataFrame中的数据
DataFrame的单列数据为一个Series,DataFrame是一个带有标签的二维数组,
每个标签相当于每一列的列名,只要以字典的方式访问列名,就可以实现当列数据的访问
访问方法1:以字典的形式访问单列数据
order_id = detail['order_detail']
print(order_id.shape)
访问方法2:以访问属性的方式访问 --不建议使用,以免与pd的方法名重名
dishes_name = detail.dishes_name
print(dishes_name)
访问方法3:单列多行数据的访问
dishes_name = detail['dishes_name'][:5]
print(dishes_name)
访问方法4:多列多行数据的访问
disheDish = detail[['order_id','dishes_name']][:5]
print(disheDish)
访问方法5:访问多行数据
order5 = detail[:][1:6]
print(order5)
访问方法6:head和tail
detail.head(n) ---默认为5
detail.tail(n) ---默认为5
访问方法7:loc,iloc访问
loc是针对DataFrame索引名称的切片方法,如果传入的不是索引名称,将会报错
DataFrame.loc[行索引名称或条件,列索引名称]
DataFrame.iloc[行索引位置,列索引位置]
例如1:
dishes_name = detail.loc[:,'dishes_name'] --dishes_name的所有行
dishes_name = detail.iloc[:,3] --dishes_name的所有行
例如2:
dishesDish1 = detail.loc[:,['order_id','dishes_name'] --order_id和dishes_name的所有行
dishesDish1 = detail.iloc[:,[1,3] --order_id和dishes_name的所有行
例如3:
detail.loc[3,['order_id','dishes_name']]
detail.iloc[3,[1,3]]
例如4:
detail.loc[2:6,['order_id','dishes_name']]
detail.iloc[2:7,[1,3]]
行索引为区间时loc为前后闭区间,iloc为前后开区间
例如5:loc传入表达式,结果返回满足表达式的值
print(detail3.loc[detail3['order_id'] == 431,'dishes_name'])
print(detail3.iloc[(detail3['order_id'] == 431).values,5])
说明:loc灵活多变,代码可读性高;
iloc代码简单,单可读性不好 ;;自己选择
访问方法8:切片方法之ix --不建议使用
ix既可以使用索引名称,也可以使用索引;但发生冲突后,以索引名称优先
2.更改DataFrame中的数据
原理:就是将这一部分数据提取出来,重新赋予新的值
注意:更改是对原数据的更改,所以要注意确认命令和备份数据
detail3.loc[detail3['order_id'] == 431,'order_id'] = '45800'
3.为DataFrame增添数据
添加一列:就是新建一个列索引,然后对该索引下的数据进行赋值
例如:
detail['payment'] = detail['counts']*detail['amount']
detail['现金支付'] = '支付宝支付'
补充知识点
from pandas import *
from random import *
df = DataFrame(columns=('lib', 'qty1', 'qty2')) # 生成空的pandas表
for i in range(6): # 插入一行
df.loc[i] = [randint(-1, 1) for n in range(3)]
df.loc[6] = [2,1,3]
print(df)
4.删除某列或某行数据
格式:
DataFrame.drop(labels,axis=0,inplace=None)
说明:
labels:代表删除的行列标签
axis :代表轴向 0横
inplace :bool 是否对原数据生效
# 代码 4-30
print('删除pay_way前deatil的列索引为:','\n',detail.columns)
detail.drop(labels = 'pay_way',axis = 1,inplace = True)
print('删除pay_way后detail的列索引为:','\n',detail.columns)
# 代码 4-31
print('删除1-10行前detail的长度为:',len(detail))
detail.drop(labels = range(1,11),axis = 0,inplace = True)
print('删除1-10行后detail的列索引为:',len(detail))
4.2.3 描述分析DataFrame数据
说明:描述性分析是用来概括的表述事物的整体状况。以及事物间的关联,类属关系的统计方法
几个统计值可以简捷的表示一组数据的集中趋势和离散程度
1.数值型特征的描述性统计
numpy的统计性函数
np.min --最小值
np.mean --均值
np.median --中位数
np.var --方差
np.max --最大值
np.ptp --极差
np.std --标准差
np.cov --协方差
# 代码 4-32
import numpy as np
print('订单详情表中amount(价格)的平均值为:', np.mean(detail['amounts']))
2.pandas也有这样的方法
DataFrame.mean()
count 非空值个数
mode 众数
quantile 四分位数
kurt 样本峰度
skew 样本偏度
# 代码 4-33
print('订单详情表中amount(价格)的平均值为:', detail['amounts'].mean())
3.pandas提供的函数--描述统计
describe函数,一次统计所有数值型特征的非空值数目,均值,四分位等
例如:
# 代码 4-34
print('订单详情表counts和amounts两列的描述性统计为:\n',
detail[['counts','amounts']].describe())
2.类别特征的描述性统计
1)pandas库中实现频数统计的方法value_counts
# 代码 4-35
print('订单详情表dishes_name频数统计结果前10为:\n',
detail['dishes_name'].value_counts()[0:10])
2)转换类型为category类型,方法astype方法将目标特征的数据类型转换为category类型
注意:category类型是对非数值的数据进行统计比较方便
# 代码 4-36
detail['dishes_name'] = detail['dishes_name'].astype('category')
print('订单信息表dishes_name列转变数据类型后为:',detail['dishes_name'].dtypes)
describe处理支持数值数据,还可以对非数值数据做描述性统计
非空元素个数,类别个数,数目最多的类别,最多类别的个数
print('订单信息表dishes_name的描述统计结果为:\n',
detail['dishes_name'].describe())
###############################################################################
####################### 任务实现 #######################
###############################################################################
#查看餐饮数据基本信息,维度,形状,元素
# 代码 4-38
from sqlalchemy import create_engine
import pandas as pd
engine = create_engine('mysql+pymysql://root:[email protected]:\
3306/testdb?charset=utf8')
detail = pd.read_sql_table('meal_order_detail1',
con = engine)
order = pd.read_table('../data/meal_order_info.csv',
sep = ',',encoding = 'gbk')
user = pd.read_excel('../data/users.xlsx')
print('订单详情表的维度为:', detail.ndim)
print('订单信息表的维度为:', order.ndim)
print('客户信息表的维度为:', user.ndim)
print('订单详情表的形状为:', detail.shape)
print('订单信息表的形状为:', order.shape)
print('客户信息表的形状为:', user.shape)
print('订单详情表的元素个数为:', detail.size)
print('订单信息表的元素个数为:', order.size)
print('客户信息表的元素个数为:', user.size)
#餐饮菜品的销售信息统计
# 代码 4-39
print('订单详情表counts和amounts两列的描述性统计为:\n',
detail.loc[:, ['counts','amounts']].describe())
detail['order_id'] = detail['order_id'].astype('category')
detail['dishes_name'] = detail['dishes_name'].astype('category')
print('''订单信息表order_id(订单编号)与dishes_name(菜品名称)
的描述性统计结果为:''', '\n',
detail[['order_id','dishes_name']].describe())
#分析以上结果
# 代码 4-40
## 定义一个函数去除全为空值的列和标准差为0的列
def dropNullStd(data):
beforelen = data.shape[1]
colisNull = data.describe().loc['count'] == 0
for i in range(len(colisNull)):
if colisNull[i]:
data.drop(colisNull.index[i],axis = 1,inplace =True)
stdisZero = data.describe().loc['std'] == 0
for i in range(len(stdisZero)):
if stdisZero[i]:
data.drop(stdisZero.index[i],axis = 1,inplace =True)
afterlen = data.shape[1]
print('去除的列的数目为:',beforelen-afterlen)
print('去除后数据的形状为:',data.shape)
dropNullStd(detail)
##使用dropNullStd函数对订单信息表操作
dropNullStd(order)
##使用dropNullStd函数对客户信息表操作
dropNullStd(user)
4.3 转换与处理时间序列数据
pandas继承了numpy库的时间模块,可以实现时间的快速转换
4.3.1 转换字符串时间为标准时间
3个常用时间的相关类
1.Timestamp -最基础的时间类
2.Period -表示单个时间跨度
3.Timedelta -表示不同单位时间
4.DatetimeIndex 1索引
5.PeriodtimeIndex 2索引
6.TimedeltaIndex 3索引
1)函数1 to_datetime
作用:将字符串转换为Timestamp
# 代码 4-41
import pandas as pd
order = pd.read_table('../data/meal_order_info.csv',
sep = ',',encoding = 'gbk')
print('进行转换前订单信息表lock_time的类型为:',
order['lock_time'].dtypes)
order['lock_time'] = pd.to_datetime(order['lock_time'])
print('进行转换后订单信息表lock_time的类型为:',
order['lock_time'].dtypes)
时间区间:1677.9.21 2262.4.11
# 代码 4-42
print('最小时间为:', pd.Timestamp.min)
print('最大时间为:', pd.Timestamp.max)
4.3.2 提取时间序列数据信息
year month day date quarter(季度) weekday_name(星期名) week(第几周)
is_leap_year(是否为闰年)
####转换为有索引的格式
# 代码 4-43
dateIndex = pd.DatetimeIndex(order['lock_time'])
print('转换为DatetimeIndex后数据的类型为:\n',type(dateIndex))
periodIndex = pd.PeriodIndex(order['lock_time'],freq = 'S')
print('转换为DatetimeIndex后数据的类型为:\n',type(periodIndex))
####提取Timestamp类中的数据
# 代码 4-44
year1 = [i.year for i in order['lock_time']]
print('lock_time中的年份数据前5个为:',year1[:5])
month1 = [i.month for i in order['lock_time']]
print('lock_time中的月份数据前5个为:',month1[:5])
day1 = [i.day for i in order['lock_time']]
print('lock_time中的日期数据前5个为:',day1[:5])
weekday1 = [i.weekday_name for i in order['lock_time']]
print('lock_time中的星期名称数据前5个为:',weekday1[:5])
#提取索引类中的数据
# 代码 4-45
print('dateIndex中的星期名称数据前5个为:\n',
dateIndex.weekday_name[:5])
print('periodIndex中的星期标号数据前5个为:',
periodIndex.weekday[:5])
注意:没有weekday_name属性
4.3.3 加减时间数据
Timedelta类是时间类中的异类
加减单位的书写
weeks
days
hours
# 代码 4-46
## 将lock_time数据向后平移一天
time1 = order['lock_time']+pd.Timedelta(days = 1) #单位为1
print('lock_time在加上一天前前5行数据为:\n',order['lock_time'][:5])
print('lock_time在加上一天前前5行数据为:\n',time1[:5])
# 代码 4-47
timeDelta = order['lock_time'] - pd.to_datetime('2017-1-1')
print('lock_time减去2017年1月1日0点0时0分后的数据:\n',
timeDelta[:5])
print('lock_time减去time1后的数据类型为:',timeDelta.dtypes)
###############################################################################
####################### 任务实现 #######################
###############################################################################
# 代码 4-48
import pandas as pd
order = pd.read_table('../data/meal_order_info.csv',
sep = ',',encoding = 'gbk')
order['use_start_time'] = pd.to_datetime(order['use_start_time'])
order['lock_time'] = pd.to_datetime(order['lock_time'])
print('进行转换后订单信息表use_start_time和lock_time的类型为:\n',
order[['use_start_time','lock_time']].dtypes)
# 代码 4-49
year = [i.year for i in order['lock_time']]## 提取年份信息
month = [i.month for i in order['lock_time']]## 提取月份信息
day = [i.day for i in order['lock_time']]## 提取日期信息
week = [i.week for i in order['lock_time']]## 提取周信息
weekday = [i.weekday() for i in order['lock_time']]##提取星期信息
## 提取星期名称信息
weekname = [i.weekday_name for i in order['lock_time']]
print('订单详情表中的前5条数据的年份信息为:',year[:5])
print('订单详情表中的前5条数据的月份信息为:',month[:5])
print('订单详情表中的前5条数据的日期信息为:',day[:5])
print('订单详情表中的前5条数据的周信息为:',week[:5])
print('订单详情表中的前5条数据的星期信息为:',weekday[:5])
print('订单详情表中的前5条数据的星期名称信息为:',weekname[:5])
# 代码 4-50 计算时间差
timemin = order['lock_time'].min()
timemax = order['lock_time'].max()
print('订单最早的时间为:',timemin)
print('订单最晚的时间为:',timemax)
print('订单持续的时间为:',timemax-timemin)
chekTime = order['lock_time'] - order['use_start_time']
print('平均点餐时间为:',chekTime.mean())
print('最小点餐时间为:',chekTime.min())
print('最大点餐时间为:',chekTime.max())
4.4 使用分组聚合进行组内计算
说明:依据某个或某几个字段对数据集进行分组,并对各组应用一个函数,无论是聚合还是转换,都是数据分析的常用操作。
注意:pandas提供了一个groupby方法,配合agg或spply方法,能够实现分组聚合操作
分组聚合的含义:先分组再对每一组进行聚合
4.4.1 使用groupby方法拆分数据 --分组功能,能根据索引或字段对数据进行分组
Df.groupby(by,axis,as_idex,sort)
说明:
by 接收list,str,dict,np 用来确定进行分组的依据
axis 轴向 默认对列操作,即0
as_index bool 表示聚合后的聚合标签是否以DF索引形式输出
sort bool 表示是否对分组依据,分组标签进行排序
# 代码 4-51
import pandas as pd
import numpy as np
from sqlalchemy import create_engine
detail = pd.read_csv(r'C:\Users\peter\Desktop\pd\meal_order_detail1.csv',sep=',')
detailGroup = detail[['order_id','counts',
'amounts']].groupby(by = 'order_id')
print('分组后的订单详情表为:',detailGroup)
说明:这里会生成一个对象GroupBy对象,不能直接查看,被放在了内存中。
GroupBy对象常用的描述性统计方法及说明
count 分组数目,包括缺失值
head 每组的前几个值
max 最大值
mean 均值
median 中位数
cumcount 对每组的组员进行标记
size 每组大小
min std sum
# 代码 4-52
print('订单详情表分组后前5组每组的均值为:\n',
detailGroup.mean().head())
print('订单详情表分组后前5组每组的标准差为:\n',
detailGroup.std().head())
print('订单详情表分组后前5组每组的大小为:','\n',
detailGroup.size().head())
4.4.2 使用agg方法聚合数据
agg支持对每个分组应用某函数,包括python的内置函数或自定义函数
命令格式:
DF.agg(func,axis)
说明:
func 接收list dict function 表示应用于每行或每列的函数
####计算菜品销量与售价的和与均值 --应用于每列的是np函数
# 代码 4-53
print('订单详情表的菜品销量与售价的和与均值为:\n',
detail[['counts','amounts']].agg([np.sum,np.mean]))
特点:一个函数应用于所有列
####计算菜品销量与售价的和与均值 --应用于每列的是np函数用字典形式写出
# 代码 4-54
print('订单详情表的菜品销量总和与售价的均值为:\n',
detail.agg({'counts':np.sum,'amounts':np.mean}))
特点:一个函数针对一列
# 代码 4-55 某个字段要多个统计量,有的要一个统计量
print('菜品订单详情表的菜品销量总和与售价的总和与均值为:\n',
detail.agg({'counts':np.sum,'amounts':[np.mean,np.sum]}))
特点:把要多个统计量的函数写成列表形式
# 代码 4-56 自定义函数的使用
##自定义函数求两倍的和
def DoubleSum(data):
s = data.sum()*2
return s
print('菜品订单详情表的菜品销量两倍总和为:','\n',
detail.agg({'counts':DoubleSum},axis = 0))
注意:np.mean np.std等这些函数在agg中直接可以用,但在自定义函数中,计算的是单个序列,则无法得出想要的结果;如果是多列数据同时计算,则不会出现该问题,例如以下的例子
# 代码 4-57
##自定义函数求两倍的和
def DoubleSum1(data):
s = np.sum(data)*2
return s
print('订单详情表的菜品销量两倍总和为:\n',
detail.agg({'counts':DoubleSum1},axis = 0).head())
print('订单详情表的菜品销量与售价的和的两倍为:\n',
detail[['counts','amounts']].agg(DoubleSum1))
#对分组中的每一组进行的聚合操作
# 代码 4-58
print('订单详情表分组后前3组每组的均值为:\n',
detailGroup.agg(np.mean).head(3))
print('订单详情表分组后前3组每组的标准差为:\n',
detailGroup.agg(np.std).head(3))
# 代码 4-59
print('订单详情分组前3组每组菜品总数和售价均值为:\n',
detailGroup.agg({'counts':np.sum,
'amounts':np.mean}).head(3))
4.4.3 使用apply方法聚合数据
说明:与agg相比,apply方法传入的函数只能作用于整个DF或series,而无法完成不同字段应用不同函数的操作
命令格式:Df.apply(func,axis)
# 代码 4-60
print('订单详情表的菜品销量与售价的均值为:\n',
detail[['counts','amounts']].apply(np.mean))
# 代码 4-61
print('订单详情表分组后前3组每组的均值为:','\n', detailGroup.apply(np.mean).head(3))
print('订单详情表分组后前3组每组的标准差为:','\n', detailGroup.apply(np.std).head(3))
# 代码 4-59
print('订单详情分组前3组每组菜品总数和售价均值为:\n', --此操作是不能进行的
detailGroup.apply({'counts':np.sum,
'amounts':np.mean}).head(3))
4.4.4 使用transform方法聚合数据
作用:对整个DF的所有元素进行操作
命令格式:transform(ufunc)
# 代码 4-62
print('订单详情表的菜品销量与售价的两倍为:\n',
detail[['counts','amounts']].transform(
lambda x:x*2).head(4))
transform方法还能够对DF分组后的对象GroupBy进行离差标准化操作
# 代码 4-63
print('订单详情表分组后实现组内离差标准化后前五行为:\n',
detailGroup.transform(lambda x:(x.mean()
-x.min())/(x.max()-x.min())).head())
说明:为NaN值,表示最大值和最小值相同
作业:
###############################################################################
####################### 任务实现 #######################
###############################################################################
# 代码 4-64
import pandas as pd
import numpy as np
from sqlalchemy import create_engine
engine = create_engine('mysql+pymysql://root:[email protected]:\
3306/testdb?charset=utf8')
detail = pd.read_sql_table('meal_order_detail1',con = engine)
detail['place_order_time'] = pd.to_datetime(
detail['place_order_time'])
detail['date'] = [i.date() for i in detail['place_order_time']]
detailGroup = detail[['date','counts','amounts']].groupby(by='date')
print('订单详情表前5组每组的数目为:\n',detailGroup.size().head())
# 代码 4-65
dayMean = detailGroup.agg({'amounts':np.mean})
print('订单详情表前五组每日菜品均价为:\n',dayMean.head())
dayMedian = detailGroup.agg({'amounts':np.median})
print('订单详情表前五组每日菜品售价中位数为:\n',dayMedian.head())
# 代码 4-66
daySaleSum = detailGroup.apply(np.sum)['counts']
print('订单详情表前五组每日菜品售出数目为:\n',daySaleSum.head())
4.5 创建透视表与交叉表
说明:数据透视表是数据分析的常见的工具之一,根据一个或多个键值对数据进行聚合;
根据行/列的分组键将数据划分到各个区域;
4.5.1 使用pivot_table函数创建透视表
命令格式:
pd.pivot_table(data,values,index,columns,aggfunc='mean',fill_value)
说明:
data:创建透视表的数据
values: 接收string,用于指定要聚合的数据字段名,默认为全部数据
index: 接收string或list,表示行分组键
columns:接收string或list,表示列分组键
aggfunc:表示聚合函数,默认的是mean
margins:接收bool,表示汇总功能的开关
dropna :接收bool,表示是否删除全为NaN的列
fill_value:将NAN的值进行替换
import pandas as pd
import numpy as np
from sqlalchemy import create_engine
engine = create_engine('mysql+pymysql://root:1234@\
127.0.0.1:3306/testdb?charset=utf8')
detail = pd.read_sql_table('meal_order_detail1',
con = engine)
detailPivot = pd.pivot_table(detail[[
'order_id','counts','amounts']],
index = 'order_id')
print('以order_id作为分组键创建的订单透视表为:\n',
detailPivot.head())
注意:默认的aggfunc为mean
#指定aggfunc
# 代码 4-68
detailPivot1 = pd.pivot_table(detail[[
'order_id','counts','amounts']],
index = 'order_id',aggfunc = np.sum)
print('以order_id作为分组键创建的订单销量与售价总和透视表为:\n',
detailPivot1.head())
######创建分组的键可以有多个
# 代码 4-69
detailPivot2 = pd.pivot_table(detail[[
'order_id','dishes_name',
'counts','amounts']],
index = ['order_id','dishes_name'],
aggfunc = np.sum)
print('以order_id和dishes_name作为分组键创建的订单\
销量与售价总和透视表为:\n',detailPivot2.head())
#######通过指定columns参数进行列分组
# 代码 4-70
detailPivot2 = pd.pivot_table(detail[[
'order_id','dishes_name','counts','amounts']],
index = 'order_id',
columns = 'dishes_name',
aggfunc = np.sum)
print('以order_id和dishes_name作为行列分组键创建的\
透视表前5行4列为:\n',detailPivot2.iloc[:5,:4])
#########通过设置values参数,指定要聚合的列
# 代码 4-71
detailPivot4 = pd.pivot_table(detail[[
'order_id','dishes_name','counts','amounts']],
index = 'order_id',
values = 'counts',
aggfunc = np.sum)
print('以order_id作为行分组键counts作为值创建的\
透视表前5行为:\n',detailPivot4.head())
#######当有NaN值时,可以指定fill_value参数进行缺失值替换
# 代码 4-72
detailPivot5 = pd.pivot_table(detail[[
'order_id','dishes_name','counts','amounts']],
index = 'order_id',
columns = 'dishes_name',
aggfunc = np.sum,fill_value = 0)
print('空值填0后以order_id和dishes_name为行列分组键\
创建透视表前5行4列为:\n',detailPivot5.iloc[:5,:4])
#######通过设置margins来查看汇总数据
# 代码 4-73
detailPivot6 = pd.pivot_table(detail[[
'order_id','dishes_name','counts','amounts']],
index = 'order_id',columns = 'dishes_name',
aggfunc = np.sum,fill_value = 0,
margins = True)
print('添加margins后以order_id和dishes_name为分组键\
的透视表前5行后4列为:\n',detailPivot6.iloc[:5,-4:])
4.5.2 使用crosstab函数创建交叉表
交叉表是一种特殊的透视表,注意用于计算分组频率
命令格式:
pd.crosstab(index,columns,values,rownames,colnames,aggfunc,margins,dropna,normailze)
index 行索引键
columns 列索引键
values 聚合数据
rownames 行分组键名
colnames 列分组键名
aggfunc 聚合函数
normalize 是否对值进行标准化
margins 汇总值
dropna 删除全为nan的列
# 代码 4-74
detailCross = pd.crosstab(
index=detail['order_id'],
columns=detail['dishes_name'],
values = detail['counts'],aggfunc = np.sum)
print('以order_id和dishes_name为分组键\
counts为值的透视表前5行5列为:\n',detailCross.iloc[:5,:5])
作业:
###############################################################################
####################### 任务实现 #######################
###############################################################################
# 代码 4-75
import pandas as pd
import numpy as np
from sqlalchemy import create_engine
engine = create_engine('mysql+pymysql://root:1234@\
127.0.0.1:3306/testdb?charset=utf8')
detail = pd.read_sql_table('meal_order_detail1',con = engine)
detail['place_order_time'] = pd.to_datetime(
detail['place_order_time'])
detail['date'] = [i.date() for i in detail['place_order_time']]
PivotDetail = pd.pivot_table(detail[[
'date','dishes_name','counts','amounts']],
index ='date',aggfunc = np.sum,
margins = True)
print('订单详情表单日菜品成交总额与总数透视表前5行5列为:\n',
PivotDetail.head())
# 代码 4-76
CrossDetail = pd.crosstab(
index=detail['date'],columns=detail['dishes_name'],
values = detail['amounts'],
aggfunc = np.sum,margins = True)
print('订单详情表单日单个菜品成交总额交叉表后5行5列为:\n',
CrossDetail.iloc[-5:,-5:])
#############################总的作业####################
第5章 使用pandas进行数据预处理
说明:如何对数据进行预处理,提高数据质量,是数据分析工作中常见的问题
预处理技术:数据合并,数据清洗,数据标准化以及数据转换
5.1 合并数据
通过堆叠合并和主键合并,可以将关联的数据信息合并在一张表中
5.1.1 堆叠合并数据
说明:堆叠就是把两个表拼在一起
1.横向堆叠
说明:将两个表在x轴向拼接在一起,
函数语法:
pd.concat(objs,axis = 1,join)
说明:objs 合并对象
axis = 1 concat做行对齐
join = inner,返回索引重叠部分
join = outer,返回索引的并集部分,不足的地方用NaN补齐
import numpy as np
import pandas as pd
from sqlalchemy import create_engine
conn = create_engine('mysql+pymysql://root:1234@\
127.0.0.1:3306/testdb?charset=utf8')
detail1 = pd.read_sql('meal_order_detail1',conn)
df1 = detail1.iloc[:,:10] ##取出detail1的前10列数据
df2 = detail1.iloc[:,10:] ##取出detail1的后9列数据
print('合并df1的大小为%s,df2的大小为%s。'%(df1.shape,df2.shape))
print('外连接合并后的数据框大小为:',pd.concat([df1,df2],
axis=1,join='inner').shape)
print('内连接合并后的数据框大小为:',pd.concat([df1,df2],
axis=1,join='outer').shape)
2.纵向堆叠
说明:将两个表在y轴向拼接在一起,
函数语法:
pd.concat(objs,axis = 0,join)
# 代码 5-2
df3 = detail1.iloc[:1500,:] ##取出detail1前1500行数据
df4 = detail1.iloc[1500:,:] ##取出detail1的1500后的数据
print('合并df3的大小为%s,df4的大小为%s。'%(df3.shape,df4.shape))
print('内连接纵向合并后的数据框大小为:',pd.concat([df3,df4],
axis=1,join='inner').shape)
print('外连接纵向合并后的数据框大小为:',pd.concat([df3,df4],
axis=1,join='outer').shape)
函数语法:
pd.DF.append(other)
说明:参加堆叠的两个表的表结构必须相同
# 代码 5-3
print('堆叠前df3的大小为%s,df4的大小为%s。'%(df3.shape,df4.shape))
print('append纵向堆叠后的数据框大小为:',df3.append(df4).shape)
5.1.2 主键合并数据
说明:通过一个或多个键,将两个数据集的行连接起来
结果集的列数 = 两个数据集列数的和,减去链接键的数量
语法格式1:
pd.merge(left,right,how,on,left_on,right_on,left_index,right_index,sort,suffixes)
说明:
left 表1
right 表2
how 连接方式inner outer left right
on 合并的主键
sort 对结果排序
left_index 作为连接主键
right_index
left_on 作为合并主键
# 代码 5-4
order = pd.read_csv('../data/meal_order_info.csv',
sep=',',encoding='gb18030') ##读取订单信息表
##info_id转换为字符串格式,为合并做准备
order['info_id'] = order['info_id'].astype('str')
## 订单详情表和订单信息表都有订单编号
##在订单详情表中为order_id,在订单信息表中为info_id
order_detail = pd.merge(detail1,order,
left_on='order_id',right_on = 'info_id')
print('detail1订单详情表的原始形状为:',detail1.shape)
print('order订单信息表的原始形状为:',order.shape)
print('订单详情表和订单信息表主键合并后的形状为:',order_detail.shape)
5.1.3 重叠合并数据
说明:将两张数据内容几乎一致的表进行合并
语法:pd.DF.combine_first(other)
# 代码 5-6
##建立两个字典,除了ID外,别的特征互补
dict1 = {'ID':[1,2,3,4,5,6,7,8,9],
'System':['win10','win10',np.nan,'win10',
np.nan,np.nan,'win7','win7','win8'],
'cpu':['i7','i5',np.nan,'i7',np.nan,np.nan,'i5','i5','i3']}
dict2 = {'ID':[1,2,3,4,5,6,7,8,9],
'System':[np.nan,np.nan,'win7',np.nan,
'win8','win7',np.nan,np.nan,np.nan],
'cpu':[np.nan,np.nan,'i3',np.nan,'i7',
'i5',np.nan,np.nan,np.nan]}
## 转换两个字典为DataFrame
df5 = pd.DataFrame(dict1)
df6 = pd.DataFrame(dict2)
print('经过重叠合并后的数据为:\n',df5.combine_first(df6))
###############################################################################
####################### 任务实现 #######################
###############################################################################
# 代码 5-7
import numpy as np
import pandas as pd
from sqlalchemy import create_engine
## 创建数据库连接
conn = create_engine('mysql+pymysql://root:1234@\
127.0.0.1:3306/testdb?charset=utf8')
## 读取数据
detail1 = pd.read_sql('meal_order_detail1',conn)
detail2 = pd.read_sql('meal_order_detail2',conn)
detail3 = pd.read_sql('meal_order_detail3',conn)
## 纵向堆叠三张表
detail = detail1.append(detail2)
detail = detail.append(detail3)
print('三张订单详情表合并后的形状为:', detail.shape)
# 代码 5-8
order = pd.read_csv('../data/meal_order_info.csv',
sep=',',encoding='gb18030') ##读取订单信息表
user = pd.read_excel('../data/users_info.xlsx') ##读取用户信息表
## 数据类型转换,存储部分数据
order['info_id'] = order['info_id'].astype('str')
order['emp_id'] = order['emp_id'].astype('str')
user['USER_ID'] = user['USER_ID'].astype('str')
data = pd.merge(detail,order,left_on=['order_id','emp_id'],
right_on = ['info_id','emp_id'])
data = pd.merge(data,user,left_on='emp_id',
right_on = 'USER_ID',how = 'inner')
print('三张表数据主键合并后的大小为:',data.shape)
5.2 清洗数据
说明:数据重复会导致数据的方差变小,数据分布发生较大变化;
缺失会导致样本信息减少,增加分析难度,会导致数据分析的结果产生偏差
异常值会产生伪‘回归'
5.2.1 检测与处理重复值
# 代码 5-9
import pandas as pd
detail = pd.read_csv('../data/detail.csv',
index_col=0,encoding = 'gbk')
1.记录重复
##方法一
##定义去重函数
def delRep(list1):
list2=[]
for i in list1:
if i not in list2:
list2.append(i)
return list2
## 去重
dishes=list(detail['dishes_name']) ##将dishes_name从数据框中提取出来
print('去重前菜品总数为:',len(dishes))
dish = delRep(dishes) ##使用自定义的去重函数去重
print('方法一去重后菜品总数为:',len(dish))
# 代码 5-10
##方法二
print('去重前菜品总数为:',len(dishes))
dish_set = set(dishes) ##利用set的特性去重
print('方法二去重后菜品总数为:',len(dish_set))
注意:使用list方法会拖慢数据分析的整体进度
使用set的最大问题是,会改变数据的排列顺序
因此,pandas提供了一个名为drop_duplicates的去重方法
该方法,值对DF和series类型有效
语法格式:
pd.DataFrame(Series).drop_duplicates(subset,keep,inplace)
subset:接收string ,表示去重的列 ,默认表示全部列
keep:first 保留第1个,last保留最后一个,False只要有重复都不保留
inplace:是否对原表进行操作
# 代码 5-11
##对dishes_name去重
dishes_name = detail['dishes_name'].drop_duplicates()
print('drop_duplicates方法去重之后菜品总数为:',len(dishes_name))
# 代码 5-12
print('去重之前订单详情表的形状为:', detail.shape)
shapeDet = detail.drop_duplicates(subset = ['order_id',
'emp_id']).shape
print('依照订单编号,会员编号去重之后订单详情表大小为:', shapeDet)
2.特征重复
说明:可以利用特征间的相似度将两个相似度为1的特征去除1个
在pandas中的方法是corr。使用该方法计算相似度是,默认是pearson法,kendall
df1 = pd.DataFrame([[1,2,3],[4,6,7]],columns=[0,0,0],index=[1,1])
df2 = pd.DataFrame({'第一列':[1,2,3,4],'第二列':[4,3,2,1]},index=[1,2,3,4])
corrdet = df2[['第一列','第二列']].corr(method = 'pearson')
print(corrdet)
df2.drop(labels = '第二列',axis=1,inplace = True)
# 代码 5-13
## 求取销量和售价的相似度
corrDet = detail[['counts','amounts']].corr(method='kendall')
print('销量和售价的kendall相似度为:\n',corrDet)
# 代码 5-14
corrDet1 = detail[['dishes_name','counts',
'amounts']].corr(method='pearson')
print('菜品名称,销量和售价的pearson相似度为:\n',corrDet1)
注意:corr只能对数值型数据产生相似度的判断,但对类别型特征就不能来计算相似度
# 代码 5-15
##定义求取特征是否完全相同的矩阵的函数
def FeatureEquals(df):
dfEquals=pd.DataFrame([],columns=df.columns,index=df.columns)
for i in df.columns:
for j in df.columns:
dfEquals.loc[i,j]=df.loc[:,i].equals(df.loc[:,j])
return dfEquals
## 应用上述函数
detEquals=FeatureEquals(detail)
print('detail的特征相等矩阵的前5行5列为:\n',detEquals.iloc[:5,:5])
# 代码 5-16
##遍历所有数据
lenDet = detEquals.shape[0]
dupCol = []
for k in range(lenDet):
for l in range(k+1,lenDet):
if detEquals.iloc[k,l] & (detEquals.columns[l] not in dupCol):
dupCol.append(detEquals.columns[l])
##进行去重操作
print('需要删除的列为:',dupCol)
detail.drop(dupCol,axis=1,inplace=True)
print('删除多余列后detail的特征数目为:',detail.shape[1])
5.2.2 检测与处理缺失值
说明:数据中的某个或某些特征的值是不完整的,这些值为缺失值
pd中识别缺失值的方法isnull 和识别非缺失值的方法notnull
结合sum和isnull,notnull可以检测数据中缺失值的分布
1.删除法
说明:将含有缺失值的特征或记录删除;分为删除观测记录和删除特征
属于通过减少样本量来换取信息完整度的一种方法
命令格式:
DF.dropna(axis,how,inplace)
how: any只要有缺失值就删除,all所有都是缺失值才删除
print('去除缺失的列前detail的形状为:', detail.shape)
print('去除缺失的列后detail的形状为:',
detail.dropna(axis = 1,how ='any').shape)
2.替换法
DF.fillna(value ,axis)
说明:用一个特定的值替换缺失值
数值型,一般用均值,中位数等替换
类别型,一般采用众数
# 代码 5-19
detail = detail.fillna(-99)
print('detail每个特征缺失的数目为:\n',detail.isnull().sum())
3.插值法
线性插值:通过已知的值求出线性方程,通过就线性方程得到缺失值
多项式插值:通过已知值拟合一个多项式,
样条插值:
# 代码 5-20
## 线性插值
import numpy as np
from scipy.interpolate import interp1d
x=np.array([1,2,3,4,5,8,9,10]) ##创建自变量x
y1=np.array([2,8,18,32,50,128,162,200]) ##创建因变量y1
y2=np.array([3,5,7,9,11,17,19,21]) ##创建因变量y2
LinearInsValue1 = interp1d(x,y1,kind='linear') ##线性插值拟合x,y1
LinearInsValue2 = interp1d(x,y2,kind='linear') ##线性插值拟合x,y2
print('当x为6、7时,使用线性插值y1为:',LinearInsValue1([6,7]))
print('当x为6、7时,使用线性插值y2为:',LinearInsValue2([6,7]))
## 拉格朗日插值
from scipy.interpolate import lagrange
LargeInsValue1 = lagrange(x,y1) ##拉格朗日插值拟合x,y1
LargeInsValue2 = lagrange(x,y2) ##拉格朗日插值拟合x,y2
print('当x为6,7时,使用拉格朗日插值y1为:',LargeInsValue1([6,7]))
print('当x为6,7时,使用拉格朗日插值y2为:',LargeInsValue2([6,7]))
##样条插值
from scipy.interpolate import spline
##样条插值拟合x,y1
SplineInsValue1 = spline(x,y1,xnew=np.array([6,7]))
##样条插值拟合x,y2
SplineInsValue2 = spline(x,y2,xnew=np.array([6,7]))
print('当x为6,7时,使用样条插值y1为:',SplineInsValue1)
print('当x为6,7时,使用样条插值y2为:',SplineInsValue2)
5.2.3 检测与处理异常值
说明:异常值是指数据中个别值的数值明显偏离其余的数值,有时也称为利群点。
检测异常值就是检测数据中是否有输入错误以及是否含有不合理的数据
常用的异常值检测法:
1.拉依达准则 3肉
原理:先假设一组检测数据只含有随机误差,对原始数据进行计算处理得到标准差
然后按一定的概率确定一个区间,认为误差超过这个区间的就属于异常
用途:一般用于正态分布数据
2.箱线图分析
异常值:小于QL-1.5IQR或大于QU+1.5IQR的值
QL:下四分位 有四分之一的数据取值比QL小
QU:上四分位 有四分之一的数据取值比QU大
IQR:四分位间距 包含全部观察值的一般
# 代码 5-22
import matplotlib.pyplot as plt
plt.figure(figsize=(10,8))
p = plt.boxplot(detail['counts'].values,notch=True) ##画出箱线图
outlier1 = p['fliers'][0].get_ydata() ##fliers为异常值的标签
#plt.savefig('../tmp/菜品异常数据识别.png')
plt.show()
print('销售量数据异常值个数为:',len(outlier1))
print('销售量数据异常值的最大值为:',max(outlier1))
print('销售量数据异常值的最小值为:',min(outlier1))
###############################################################################
####################### 任务实现 #######################
###############################################################################
# 代码 5-23
import pandas as pd
detail = pd.read_csv('../data/detail.csv',
index_col=0,encoding = 'gbk')
print('进行去重操作前订单详情表的形状为:',detail.shape)
##样本去重
detail.drop_duplicates(inplace = True)
##特征去重
def FeatureEquals(df):
##定义求取特征是否完全相同的矩阵的函数
dfEquals=pd.DataFrame([],columns=df.columns,index=df.columns)
for i in df.columns:
for j in df.columns:
dfEquals.loc[i,j]=df.loc[:,i].equals(df.loc[:,j])
return dfEquals
detEquals=FeatureEquals(detail)## 应用上述函数
##遍历所有数据
lenDet = detEquals.shape[0]
dupCol = []
for k in range(lenDet):
for l in range(k+1,lenDet):
if detEquals.iloc[k,l] & (detEquals.columns[l] not in dupCol):
dupCol.append(detEquals.columns[l])
##删除重复列
detail.drop(dupCol,axis=1,inplace=True)
print('进行去重操作后订单详情表的形状为:',detail.shape)
# 代码 5-24
##统计各个特征的缺失率
naRate = (detail.isnull().sum()/ \
detail.shape[0]*100).astype('str')+'%'
print('detail每个特征缺失的率为:\n',naRate)
##删除全部均为缺失的列
detail.dropna(axis = 1,how = 'all',inplace = True)
print('经过缺失值处理后订单详情表各特征缺失值的数目为:\n',
detail.isnull().sum())
# 代码 5-25
##定义异常值识别与处理函数
def outRange(Ser1):
QL = Ser1.quantile(0.25)
QU = Ser1.quantile(0.75)
IQR = QU-QL
Ser1.loc[Ser1>(QU+1.5*IQR)] = QU
Ser1.loc[Ser1<(QL-1.5*IQR)] = QL
return Ser1
## 处理销售量和售价的异常值
detail['counts'] = outRange(detail['counts'])
detail['amounts'] = outRange(detail['amounts'])
##查看处理后的销售量和售价的最小值,最大值
print('销售量最小值为:', detail['counts'].min())
print('销售量最大值为:', detail['counts'].max())
print('售价最小值为:', detail['amounts'].min())
print('售价最大值为:', detail['amounts'].max())
5.3 标准化数据
说明:不同特征间往往具有不同的量纲,由此造成的数值间的差异很大。
在设计空间距离计算或梯度下降法的情况时,不对其进行处理会影响到数据分析结果的准确性。
为了消除特征之间量纲和取值范围差异可能造成的影响,需要对数据进行标准化处理。
5.3.1 离差标准化数据
说明:是对原始数据的一种线性变换,结果是将原始数据的数值映射到0-1的区间
公式 x1 = (x-min)/(max-min)
结果:离差标准化保留了原始数据值之间的联系,是消除量纲和数据取值范围影响最简单的方法
# 代码 5-26
import pandas as pd
import numpy as np
detail = pd.read_csv('../data/detail.csv',
index_col=0,encoding = 'gbk')
## 自定义离差标准化函数
def MinMaxScale(data):
data=(data-data.min())/(data.max()-data.min())
return data
##对菜品订单表售价和销量做离差标准化
data1=MinMaxScale(detail['counts'])
data2=MinMaxScale(detail ['amounts'])
data3=pd.concat([data1,data2],axis=1)
print('离差标准化之前销量和售价数据为:\n',
detail[['counts','amounts']].head())
print('离差标准化之后销量和售价数据为:\n',data3.head())
缺点:将来如果出现超出目前极差范围的值的化,系统就会出错
5.3.2 标准差标准化数据
说明:零均值标准化;经过该方法处理的数据均值为0,标准差为1
x1 = x-原始数据均值/原始数据标准差
# 代码 5-27
##自定义标准差标准化函数
def StandardScaler(data):
data=(data-data.mean())/data.std()
return data
##对菜品订单表售价和销量做标准化
data4=StandardScaler(detail['counts'])
data5=StandardScaler(detail['amounts'])
data6=pd.concat([data4,data5],axis=1)
print('标准差标准化之前销量和售价数据为:\n',
detail[['counts','amounts']].head())
print('标准差标准化之后销量和售价数据为:\n',data6.head())
结果:存在负值
5.3.3 小数定标标准化数据
说明:通过移动数据的小数位数,将数据映射到【-1,1】 移动的小数位数取决于数据绝对值的最大值
公式:x1 = x/10的n次方
# 代码 5-28
##自定义小数定标差标准化函数
def DecimalScaler(data):
data=data/10**np.ceil(np.log10(data.abs().max()))
return data
##对菜品订单表售价和销量做标准化
data7=DecimalScaler(detail['counts'])
data8=DecimalScaler(detail['amounts'])
data9=pd.concat([data7,data8],axis=1)
print('小数定标标准化之前的销量和售价数据:\n',
detail[['counts','amounts']].head())
print('小数定标标准化之后的销量和售价数据:\n',data9.head())
离差标准化:简单,便于理解
标准差标准化:数据分布的影响较小
小数定标标准化:使用范围广
5.4 转换数据
说明:即使对数据进行了清洗,合并和标准化,也不能直接拿来建模。我们需要对数据做一些合理的转换
5.4.1 哑变量处理类别型数据
说明:数据分析模型中,很大一部分需要模型输入的是数值型;
但实际的数据,不是都是数值型,因此需要对非数值的特征进行哑变量处理才可以放入模型之中
语法格式:
pd.get_dummies(data,prefix,prefix_sep='_')
data:表示需要哑变量处理的数据
prefix:表示哑变量处理后列名的前缀
prefix_sep:表示前缀的连接符
dummy_na :表示是否为nan值添加一列。
注意:经过哑变量处理之后,数据变成了m个二元特征,并且这些特征互斥,每次只有一个激活,这使得数据变得稀疏。也就加快了模型的运行速度
5.4.2 离散化连续型数据
说明:某些模型,特别是某些分类算法(ID3,Apriori) 要求数据是离散的,此时就需要将连续性特征变成离散型特征即(连续特征离散化)
原理:就是将连续的一组数据,划分成几个离散的区间,然后将这些连续的数据落入到区间内
这里就设计到两个任务:1.确定分类 2.如果将连续型数据映射到分类中
常用的离散方法有
1.等宽法
说明:将数值的区域划分成相同宽度的值;区间的个数,有数据本身的特点决定
语法:
pd.cut(x,bins,right,labels)
x:表示离散化的数据
bins:表示离散化的类别数据 (list,int)
right:bool 右侧是否为闭区间 默认为True
labels :list 离散化后各个类别的名称
# 代码 5-31
price = pd.cut(detail['amounts'],5)
print('离散化后5条记录售价分布为:\n' ,price.value_counts())
确定:等宽法对数据分布具有较高的要求,若分布不均匀,就会让有些区间数据很多
2.等频法
原理:可以通过定义将相同数量的值放进每个区间
# 代码 5-32
##自定义等频法离散化函数
def SameRateCut(data,k):
w=data.quantile(np.arange(0,1+1.0/k,1.0/k))
data=pd.cut(data,w)
return data
result=SameRateCut(detail['amounts'],5).value_counts() ##菜品售价等频法离散化
print('菜品数据等频法离散化后各个类别数目分布状况为:','\n',result)
缺点:有可能将1个值,放入了多个区间
第6章 使用scikit-learn构建模型
6.1 使用sklearn转换器处理数据
提供了Model_selection模型选择模块,preprocessing数据预处理模块和decompisition特征分析模块
通过以上三个模块能够实现数据预处理与模型构建前的数据标准化,二值化,数据集分割,交叉验证和PCA降维等
6.1.1 加载datasets模块中的数据集
sklearn库的datasets模块集成了部分数据分析的经典数据集;
datasets模块常用数据集的加载函数与解释
使用sklearn进行数据预处理会用到sklearn提供的统一结构--转换器Transformer
数据集加载函数 数据集任务类型
load_boston 回归
fetch_california_housing 回归
load_digits 分类
load_breast_cancer 分类,聚类
load_iris 分类,聚类
load_wine 分类
##导入库--数据集
from sklearn.datasets import load_breast_cancer
cancer = load_breast_cancer()
print(len(cancer))
print(type(cancer))
##查看库的信息
print(cancer.data) #数据
print(cancer.target) #标签
print(cancer.feature_names) #特征名称
print(cancer.DESCR) #描述信息
6.1.2 将数据集划分为训练集和测试集
方法1:
在数据分析过程中,为了保证模型在实际系统中能够起到预期作用,一般需要将样本分为独立的3部分:训练集(train set),验证集(validation set)和测试集(test set).
训练集:用来估计模型
验证集:用于确定网络结构或者控制模型复杂程度的参数。
测试集:用来检验最优模型的性能
训练集5 验证集和测试集各2.5
方法2:
当数据总量较少 ,常用的方法是留少部分用做测试集,然后对其余N个样本采用k折交叉验证法。
基本步骤:就是把数据分成k份,用k-1份作为训练集,用1份作为验证集。计算预测误差平均和,最后把k次预测误差平均和的均值作为选择最优模型结构的依据
注意:sklearn的model_selection模块提供了train_test_split函数,能够对数据集进行拆分
语法格式如下:
sklearn.model_selection.train_test_split(1或n个数据集,test_size,train_size,random_state,shuffle,stratify)
1到n个数据集: 分类回归(传入数据和标签) 聚类(传入数据)
test_size和train_size:两个只传入1个(0-1)
random_size:随机种子编号
例如:
from sklearn.model_selection import train_test_split as tts
data_train,data_test,target_train,target_test = \
tts(cancer_data,cancer_target,test_size=0.25,random_state=42)
print(data_train.shape)
print(data_test.shape)
6.1.3 使用sklearn转换器进行数据预处理与降维
为帮助用户实现大量的特征处理相关操作,sklearn把相关的功能封装为转换器
转换器包括3个方法:fit,transform,fit_transform
使用sklearn转换器能够实现对传入的Numpy数组进行标准化处理,归一化处理,二值化处理和PCA降维
在数据分析过程中,数据分为训练集和测试集,需要将训练集的操作规则、权重系数应用到测集中。pandas比较麻烦。sklearn就比较简单
例如:对iris数据进行离差标准化
import numpy as np
from sklearn.preprocessing import MinMaxScaler
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split as tts
iris = load_iris()
iris_data = iris['data']
iris_target = iris['target']
data_train,data_test,target_train,target_test = \
tts(iris_data,iris_target,test_size=0.25,random_state=42)
scaler = MinMaxScaler().fit(data_train)
print(scaler)
#训练集应用规则
iris_trainScaler = scaler.transform(data_train)
print(np.max(iris_trainScaler))
print(np.min(iris_trainScaler))
print(np.modein(iris_trainScaler))
#测试集应用规则
iris_testScaler = scaler.transform(data_test)
print(np.max(iris_testScaler))
print(np.min(iris_testScaler))
预处理函数与其作用
from sklearn.preprocessing import Normalizer
1.StandardScaler 对特征进行标准差标准化
2.Normalizer 对特征进行归一化
3.Binarizer 对定量特征进行二值化处理
4.OneHotEncoder 对定性特征进行独热编码处理
5.FunctionTransformer 对特征进行自定义函数变换
from sklearn.decomposition import PCA
6.PCA降维算法
6.2 构建并评价聚类模型
1.聚类分析是在没有给定划分类别的情况下,根据数据相似度进行样本分组的一种方法.
2.聚类模型可以将无类标记的数据聚集多个簇,视为一类,是一种非监督的学习算法.
3.在商业上,聚类可以帮助市场分析人员从消费者数据库中区分出不同的消费群体,并且
概括出每一类消费者的消费模式或消费习惯.
4.聚类分析也可以作为数据分析算法中其他分析算法的一个预处理步骤
(异常值识别,连续型特征离散化)
6.2.1 使用sklearn估计器构建聚类模型
聚类是一组未被标记的样本,聚类根据数据自身的距离或相似度将他们划分为若干组
原则:组内距离最小化,组间距离最大化
sklearn提供的聚类算法模块cluster的聚类算法及其适用范围
k-Means
聚类算法实现需要sklearn估计器(Estimator).sklearn估计器有fit和predict两个方法
fit方法主要用于训练算法
predict用于预测有监督学习的测试集标签
例如:
from sklearn.datasets import load_iris
from sklearn.preprocessing import MinMaxScaler
from sklearn.cluster import KMeans
iris = load_iris()
iris_data = iris['data']
iris_target = iris['target']
iris_names = iris['feature_names']
scale = MinMaxScaler().fit(iris_data) #训练规则
iris_dataScale = scale.transform(iris_data) #应用规则
kmeans = KMeans(n_clusters = 3,random_state = 123).fit(iris_dataScale) #构建并训练模型
print(kmeans)
result = kmeans.predict([[6,2,7,1.5]])
print(result)
import pandas as pd
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt
#用tsne进行数据降维,降成2维
tsne = TSNE(n_components = 2,init = 'random',random_state = 177).fit(iris_data)
df = pd.DataFrame(tsne.embedding_) #将原始数据转换为DataFrame
df['labels'] = kmeans.labels_ #将聚类结果存储进df数据表
df1 = df[df['labels']==0]
df2 = df[df['labels']==1]
df3 = df[df['labels']==2]
fig = plt.figure(figsize =(8,6))
plt.plot(df1[0],df1[1],'bo',df2[0],df2[1],'r*',df3[0],df3[1],'gD')
print('aaa')
plt.savefig('./aa.png')
plt.show()
6.2.2 评价聚类模型
聚类评价的标准是组内的对象相互之间是相似的,而不同组中的对象是不同的。
即组内的相似性越大,组间差别越大,聚类效果越好
sklearn的metrics模块提供的聚类模型评价指标如表6-9所示。
ARI评价法(兰德系数) adjusted_rand_score 1.0
AMI评价法(互信息) adjusted_mutual_info_score 1.0
V-measure评分 completeness_score 1.0
FMI评价法 fowlkes_mallows_score 1.0
轮廓系数评价法 silhouette_score 畸形程度最大
Calinski_Harabasz指数评价法 calinski_harabaz_score 相较最大
注意:前4种需要真实值的配合才能够评价聚类算法的优劣,后两种则不需要真实值的配合
例如:
#FMI评价法判定建立的K-Means聚类模型
from sklearn.metrics import fowlkes_mallows_score
for i in range(2,7):
kmeans = KMeans(n_clusters = i,random_state = 123).fit(iris_data)
score = fowlkes_mallows_score(iris_target,kmeans.labels_)
print('%d的评价分值:%f'%(i,score))
from sklearn.metrics import silhouette_score
import matplotlib.pyplot as plt
silhouettteScore = []
for i in range(2,15):
kmeans = KMeans(n_clusters = i,random_state = 123).fit(iris_data)
score = silhouette_score(iris_data,kmeans.labels_)
silhouettteScore.append(score)
plt.figure(figsize=(8,6))
plt.plot(range(2,15),silhouettteScore,linewidth=1.5,linestyle='-')
plt.show()
from sklearn.metrics import calinski_harabaz_score
for i in range(2,7):
kmeans = KMeans(n_clusters = i,random_state = 123).fit(iris_data)
score = calinski_harabaz_score(iris_data,kmeans.labels_)
print('%d类calinski_harabaz指数为:%f'%(i,score))
#任务实现
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
seeds = pd.read_csv(r'C:\Users\peter\Desktop\seeds_dataset.txt',sep='\t')
print(seeds.shape)
seeds_data = seeds.iloc[:,:7].values
seeds_target = seeds.iloc[:,7:].values
seeds_names = seeds.columns[:7]
stdScale = StandardScaler().fit(seeds_data)
seeds_dataScale = stdScale.transform(seeds_data)
kmeans = KMeans(n_clusters = 3,random_state = 42).fit(seeds_data)
print(kmeans)
results = kmeans.predict([[14.88 , 14.57 , 0.8811, 5.554 , 3.333 , 1.018 , 4.956 ]]) #测试模型
results
6.3 构建并评价分类模型
分类是指构造一个分类模型,输入样本的特征值,输出对应的类别,将每个样本映射到预先定义好的类别。
用途:分类模型建立在已有类标记的数据集上,属于有监督学习。
例如:行为分析,物品识别,图形检测等
6.3.1 使用sklearn估计器构建分类模型
sklearn库常用的分类算法
模块 函数名 算法名称
linear_model LogisticRegression 逻辑斯蒂回归
svm SVC 支持向量机
neighbors KNeighborsClassifier K最近邻分类
naive_bayes GaussianNB 高斯朴素贝叶斯
tree DecisionTreeClasifier 分类决策树
ensemble RandomForestClassfier 随机森林分类
ensemble GradientBoostingClassifer 梯度提升分类树
使用sklearn估计器构建SVM模型
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
cancer = load_breast_cancer()
cancer_data = cancer['data']
cancer_target = cancer['target']
cancer_names = cancer['feature_names']
#划分训练集和测试集
cancer_data_train,cancer_data_test,cancer_target_train,cancer_target_test = \
train_test_split(cancer_data,cancer_target,test_size = 0.2,random_state=22)
#数据标准化
stdScaler = StandardScaler().fit(cancer_data_train) #训练规则
cancer_testStd = stdScaler.transform(cancer_data_test) #应用规则到测试集
cancer_trainStd = stdScaler.transform(cancer_data_train) #应用规则到训练集
#建立模型
svm = SVC().fit(cancer_trainStd,cancer_target_train)
print(svm)
#预测训练集结果
cancer_target_pred = svm.predict(cancer_testStd)
print(cancer_target_pred[:20])
#求出预测和真实一样的数目
true = np.sum(cancer_target_pred == cancer_target_test)
print('对',true)
print('错误',cancer_target_test.shape[0]-true)
print('准确率',true/cancer_target_test.shape[0])
6.3.2 评价分类模型
分类模型对测试集进行预测而得出的准确率并不能很好反映模型的性能,为了有效判断一个预测
模型的性能表现,需要结合真实值计算机出准确率、召回率、F1值和Cohen'sKappa系数等指标来衡量
方法名称 最佳值 sklearn函数
Precision(精确率) 1.0 metrics.precision_score
Recall(召回率) 1.0 metrics.recall_score
F1值 1.0 metrics.f1_score
Cohen's Kappa系数 1.0 metrics.cohen_kappa_score
ROC曲线 最靠近y轴 metrics.roc_curve
metrics模块还提供了一个能够输出分类模型评价报告的函数classfication_report
###单个评价模型好坏
# 代码 6-19
from sklearn.metrics import accuracy_score,precision_score, \
recall_score,f1_score,cohen_kappa_score
print('使用SVM预测breast_cancer数据的准确率为:',
accuracy_score(cancer_target_test,cancer_target_pred))
print('使用SVM预测breast_cancer数据的精确率为:',
precision_score(cancer_target_test,cancer_target_pred))
print('使用SVM预测breast_cancer数据的召回率为:',
recall_score(cancer_target_test,cancer_target_pred))
print('使用SVM预测breast_cancer数据的F1值为:',
f1_score(cancer_target_test,cancer_target_pred))
print('使用SVM预测breast_cancer数据的Cohen’s Kappa系数为:',
cohen_kappa_score(cancer_target_test,cancer_target_pred))
###用报告评价模型好坏
# 代码 6-20
from sklearn.metrics import classification_report
print('使用SVM预测iris数据的分类报告为:','\n',
classification_report(cancer_target_test,
cancer_target_pred))
###用图形展示模型好坏
# 代码 6-21
from sklearn.metrics import roc_curve
import matplotlib.pyplot as plt
## 求出ROC曲线的x轴和y轴
fpr, tpr, thresholds = \
roc_curve(cancer_target_test,cancer_target_pred)
plt.figure(figsize=(10,6))
plt.xlim(0,1) ##设定x轴的范围
plt.ylim(0.0,1.1) ## 设定y轴的范围
plt.xlabel('False Postive Rate')
plt.ylabel('True Postive Rate')
plt.plot(fpr,tpr,linewidth=2, linestyle="-",color='red')
plt.show()
6.4 构建并评价回归模型
回归算法的实现过程与分类算法类似,原理相差不大。
主要区别:分类算法的标签是离散的,回归算法的标签是连续的
应用:交通,物流,社交网络和金融领取都能发挥巨大作用
6.4.1 使用sklearn估计器构建线性回归模型
在回归模型中,自变量与因变量具有相关关系,自变量的值是已知的,因变量是要预测的。
回归算法的实现步骤和分类算法基本相同,分为学习和预测两个步骤。
学习是通过训练样本数据来拟合回归方程的
预测则是利用学习过程中拟合出的回归方程,将测试数据放入方程中求出预测值。
1)常用的回归模型:
1.线性回归 :因变量与自变量是线性关系
对一个或多个自变量和因变量之间的线性关系进行建模,可用最小二乘法估计法
求解模型系数
2.非线性回归:因变量与自变量不是线性关系
3.Logistic回归:因变量一般有1和0(是与否)两种取值
4.岭回归:参与建模的自变量之间具有多重共线性
5.主成分回归:参与建模的自变量之间具有多重共线性
2)sklearn库内部常用回归算法
模块名称 函数名称 算法名称
linear_model LinearRegression 线性回归
svm SVR 支持向量回归
neighbors KNeighborsRegressor 最近岭回归
tree DecisionTreeRegressor 回归决策树
ensemble RandomForestRegressor 随机森林回归
ensemble GradientBoostingRegressor 梯度提升回归树
# 代码 6-24
##加载所需函数
from sklearn.linear_model import LinearRegression
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
## 加载boston数据
boston = load_boston()
X = boston['data']
y = boston['target']
names = boston['feature_names']
## 将数据划分为训练集测试集
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size = 0.2,random_state=125)
## 建立线性回归模型
clf = LinearRegression().fit(X_train,y_train)
print('建立的LinearRegression模型为:','\n',clf)
## 预测训练集结果
y_pred = clf.predict(X_test)
print('预测前20个结果为:','\n',y_pred[:20])
#回归结果可视化
import matplotlib.pyplot as plt
from matplotlib import rcParams
rcParams['font.sans-serif'] = 'SimHei'
fig = plt.figure(figsize=(10,6)) ##设定空白画布,并制定大小
##用不同的颜色表示不同数据
plt.plot(range(y_test.shape[0]),y_test,color="blue", linewidth=1.5, linestyle="-")
plt.plot(range(y_test.shape[0]),y_pred,color="red", linewidth=1.5, linestyle="-.")
plt.legend(['真实值','预测值'])
#plt.savefig('../tmp/聚类结果.png')
plt.show() ##显示图片
6.4.2 评价回归模型
回归模型的性能评价不同于分类模型,虽然都是对真实值进行评价,但由于回归模型的
预测结果和真实值都是连续的,所以不能够求取分类模型的评价指标
回归模型拥有一套独立的评价指标
1)回归模型评价指标
方法名称 最优值 函数
平均绝对误差 0 metrics.mean_absolute_error
均方误差 0 metrics.mean_squared_error
中值绝对误差 0 metrics.median_absolute_error
可解释方差值 1 metrics.explained_variance_score
R方值 1 metrics.r2_score
# 代码 6-26
from sklearn.metrics import explained_variance_score,\
mean_absolute_error,\
mean_squared_error,\
median_absolute_error,r2_score
print('Boston数据线性回归模型的平均绝对误差为:',
mean_absolute_error(y_test,y_pred))
print('Boston数据线性回归模型的均方误差为:',
mean_squared_error(y_test,y_pred))
print('Boston数据线性回归模型的中值绝对误差为:',
median_absolute_error(y_test,y_pred))
print('Boston数据线性回归模型的可解释方差值为:',
explained_variance_score(y_test,y_pred))
print('Boston数据线性回归模型的R方值为:',
r2_score(y_test,y_pred))
#评价结果如下:
Boston数据线性回归模型的平均绝对误差为: 3.3775517360082032
Boston数据线性回归模型的均方误差为: 31.15051739031563
Boston数据线性回归模型的中值绝对误差为: 1.7788996425420773
Boston数据线性回归模型的可解释方差值为: 0.710547565009666
Boston数据线性回归模型的R方值为: 0.7068961686076838
#结论:从结果来开线性回归模型拟合效果一般,还有较大的改进余地
第7章 航空公司客户价值分析
客户关系管理(Customer relationship management,CRM)成为企业的核心问题。
客户关系管理就是客户分群:有价值客户和无价值客户。
针对不同价值的客户,制订优化的个性化服务方案。
客户分群越来越成为客户关系管理中的关键问题之一。
7.1 了解航空公司现状与客户价值分析
通过建立合理的客户价值评估模型,对客户进行分群、分析及比较不同客户群的客户价值,
并制定相应的营销策略,对不同的客户群提供个性化的服务
7.1.1 了解航空公司现状
结合目前航空公司的数据情况,可以实现以下目标:
1.借助航空公司客户数据,对客户进行分群
2.对不同的客户类别进行特征分析,比较不同类别客户的客户价值
3.对不同价值的客户类别提供个性化服务,制定相应的营销策略
7.1.2 认识客户价值分析
以客户为中心的业务模式的问题在于:只有一部分客户能为企业带来利润。
追求利润最大化是企业生存和发展的宗旨之一。所以企业不可能也不应该和所有
的客户都保持同样的关系。
客户营销实施的经验中提炼如下经验:
1.80%的收入来自20%的客户
2.20%的客户,其利润为100%
3.90%的收入都来自现有客户
4.5%--30%的客户在客户金字塔中具有升级潜力
5.大部分的营销预算经验被用在非现有客户上
6.客户升级2%,收入增加10%,利润增加50%
注意:本章使用客户价值RFM模型进行分析
7.1.3 熟悉航空客户价值分析的步骤与流程
1.抽取公司2012年4月1日到2014年3月31日的数据
2.对抽取的数据进行数据清洗、特征构建和标准化等操作
3.基于RFM模型,使用K-Means算法进行客户分群
4.针对模型结果得到不同价值的客户,采用不同的营销手段,提供定制化的服务
业务系统--数据抽取--数据预处理--分析与建模--结果反馈
7.2 预处理航空公司客户数据
说明:数据存在少量的缺失值和异常值,需要清洗后才能用于分析
数据特征过多,不便于直接分析,需要对特征进行筛选
7.2.1 处理数据缺失值与异常值
票价为空值,票价最小值为0,折扣率最小值为0,
票价为空:不存在乘机记录
票价为0:0折机票,积分兑换
由于数据不是很多,所有用丢弃数据进行处理。
7.2.2 构建航空客户价值分析关键特征
1.RFM模型介绍
R:指最近一次消费时间与截至时间的间隔
标准:间隔越短,客户价值越好。如果分析报告显示距离最近一次消费时间
很近的客户在增加,则表示该公司是个稳步上升的公司
F:指顾客在某段时间内所消费的次数
标准:购买次数越高,顾客质量越高
增加客户购买的次数,意味着从竞争对手处抢得市场占有率。商家需要做的是
通过各种营销方式去不断地刺激顾客消费,提高购买频率
M:值顾客在某段时间内所消费的金额
2.RFM模型结果解读
RFM特征值为155,为最差客户
RFM特征值为555,为最优客户
3.航空公司价值分析的LRFMC模型
L:客户关系长度
会员入会时间距离观测窗口结束的月数
R:消费时间间隔
客户最近一次乘坐公司飞机,距离观测窗口结束的月数
F:消费频率
客户在观测窗口内,乘坐公司飞机的次数
M:飞行里程
客户在观测窗口内累计的飞行里程
C:折扣系数的平均值
客户在观测窗口内乘坐舱位,所对应的折扣系数的平均值
FFP_DATE LOAD_TIME FLIGHT_COUNT AVG_DISCOUNT SEG_KM_SUM LAST_TO_END
入会时间 结束时间 飞行次数 平均折扣系数 飞行千米数 乘机时长
以上6个特征与LRFMC特征相关
L = LOAD_TIME - FFP_DATE
R = LAST_TO_END
F = FLIGHT_COUNT
M = SEG_KM_SUM
C = AVG_DISCOUNT
7.2.3 标准化LRFMC模型的5个特征
L R F M C
MIN 12.23 0.03 2 368 0.14
MAX 114.63 24.37 213 580717 1.50
为了消除数量级数据带来的影响,需要对数据做标准化处理
# -*- coding: utf-8 -*-
###############################################################################
####################### 任务实现 ########################
###############################################################################
# 代码 7-1
import numpy as np
import pandas as pd
airline_data = pd.read_csv(r"C:\Users\peter\Desktop\air_data.csv",sep=',',
encoding="gb18030") #导入航空数据
print('原始数据的形状为:',airline_data.shape)
## 去除票价为空的记录
exp1 = airline_data["SUM_YR_1"].notnull()
exp2 = airline_data["SUM_YR_2"].notnull()
exp = exp1 & exp2
airline_notnull = airline_data.loc[exp,:]
print('删除缺失记录后数据的形状为:',airline_notnull.shape)
#只保留票价非零的,或者平均折扣率不为0且总飞行公里数大于0的记录。
index1 = airline_notnull['SUM_YR_1'] != 0
index2 = airline_notnull['SUM_YR_2'] != 0
index3 = (airline_notnull['SEG_KM_SUM']> 0) & \
(airline_notnull['avg_discount'] != 0)
airline = airline_notnull[(index1 | index2) & index3]
print('删除异常记录后数据的形状为:',airline.shape)
# 代码 7-2
## 选取需求特征
airline_selection = airline[["FFP_DATE","LOAD_TIME",
"FLIGHT_COUNT","LAST_TO_END",
"avg_discount","SEG_KM_SUM"]]
## 构建L特征
L = pd.to_datetime(airline_selection["LOAD_TIME"]) - \
pd.to_datetime(airline_selection["FFP_DATE"])
L = L.astype("str").str.split().str[0]
L = L.astype("int")/30
## 合并特征
airline_features = pd.concat([L,
airline_selection.iloc[:,2:]],axis = 1)
print('构建的LRFMC特征前5行为:\n',airline_features.head())
# 代码 7-3
from sklearn.preprocessing import StandardScaler
data = StandardScaler().fit_transform(airline_features)
#np.savez(r'C:\Users\peter\Desktop\airline_scale.npz',data)
print('标准化后LRFMC五个特征为:\n',data[:5,:])
7.3 使用k-means算法进行客户分群
K-Means算法是一种最常用的聚类算法
下来用该算法进行航空公司用户分群,最终得到不同特征的客户群
并分析不同客户群的特征,制定相对应的策略
7.3.1 了解k-means聚类算法
1.基本概念
k-means聚类算法是一种基于质心的划分方法,给定聚类个数k,以及包含n个
数据对象的数据库,输出满足误差平方和最小标准的k个聚类
步骤如下:
1.从n个样本数据中,随机选取k个对象作为初始的聚类的中心
2.分别计算每个样本到各个聚类质心的距离,将样本划分到聚类中心
3.所有样本分配完后,重新计算k个聚类中心
4.与前一次的聚类做比较,一样进行5.否则进行2
5.当质心不发生变化时,停止并输出聚类结果
1.优点:简单
2.缺点:过分依赖初始值的选择
2.数据类型
k-means聚类算法是在数值类型数据的基础上进行研究的。
3.k-means函数语法与参数
7.3.2 分析聚类结果
# 代码 7-4
import numpy as np
import pandas as pd
from sklearn.cluster import KMeans #导入kmeans算法
airline_scale = np.load(r'C:\Users\peter\Desktop\airline_scale.npz')['arr_0']
k = 5 ## 确定聚类中心数
#构建模型
kmeans_model = KMeans(n_clusters = k,n_jobs=4,random_state=123)
fit_kmeans = kmeans_model.fit(airline_scale) #模型训练
kmeans_model.cluster_centers_ #查看聚类中心
kmeans_model.labels_ #查看样本的类别标签
#统计不同类别样本的数目
r1 = pd.Series(kmeans_model.labels_).value_counts()
print('最终每个类别的数目为:\n',r1)
7.3.3 模型应用
1.会员的升级与保级
2.首次兑换
3.交叉销售13909180719