1. 数据分析思维与业务流程
1.1 数据分析概述
1.1.1 预测未来 - 数据分析在总统大选中的预测作用
传统抽样,随机抽人,但是可能抽样的人群大部分是某个特定群体的,导致结果不准,而定额抽样法可以避免,样本更分散
但是 1948 年的总统预测却错了,当时预测杜威会打败杜鲁门获胜,实际上却是杜鲁门获胜。因为杜威是共和党人,共和党人的选民大部分是高知和富裕的人,而调查人员又偏好去富裕、环境好的地方采样,所以导致预测失败。
于是,定额抽样法再次优化为分层多阶抽样
1.1.2-1.1.3 优化现状-数据分析对化妆品销售的优化作用…
加载数据
数据处理:将矩阵转置,要让列是不同的影响因素,行是不同月份。这样比较好处理
corr:获得特征和特征之间的线性关系(y=kx+b,y 和 x 之间的关系),一般值是-1~1,0 为不相关,1 为正相关(x↑y↑),-1 为负相关(x↑y↓)
我们只关心总销量和其他影响因素的关系
公司报表喜欢将结论放前面
1.1.4-1.1.5 总结规律-数据分析师在招聘市场上的需求分.…
从后端平台下载数据,存到 excel,通过 python 读入
使用工具进行汇总…
柱状图是 excel 生成的,通过 sql 导出 excel
1.1.6 数据分析师职业规划&课程体系
1.2 实战-某线下连锁水果店销售数
1.2.1 水果店营收背景
1.2.2 问题确认与指标拆解
1.2.3 水果店利润问题解决流程
1.2.4 利用分组分析找到亏损店铺做营销优化
实操主要关注指定方案、目标评估、实验、分析实验效果等步骤,其中目标评估需要和领域专家合作
操作
1.2.5 分组分析实验验证与结论
计算毛利额:方案前日均毛利*(1 + 增幅)^3
数据可视化
1.2.6 运用对比分析、矩阵关联、超势分析解决水果…
2. MYSQL 数据分析实战
3. 互联网公司必备-BI 商业智能工具
3.1 Tableau 数据可视化
3.1.1 引言 BI 可视化明星——Tableau
01–问题先行
演示
为什么学 Tableau
Tableau 可视化成果展示
- 其他 BI(fineBI、quickBI 等国产 BI)都是碰瓷 Tableau 和 PowerBi 的,不建议专门学
02–课程亮点&学完收获
03–课程大纲
3.1.2 任务一 出发去探索 Tableau 吧
01–Tableau 家族产品初探索
02–Tableau Desktop 工作区
工作表
我 2021 版的破解需要在仪表盘打开工作表才能看到图
仪表板
故事
03–Tableau Desktop 文件管理
3.1 Tableau 工作簿 / 打包工作簿(.twb / .twbx)
3.2 Tableau 数据源(.tds / .tdsx)
3.3 Tableau 数据提取(.hyper)
总结
3.1.3 任务二 连接数据,基础且必须
01–认识 Tableau 数据–数据角色
度量和维度
离散和连续
蓝色字段和绿色字段
02–认识 Tableau 数据–字段类型
1.2.1 Tableau 中的数据类型图标
03–认识 Tableau 数据–字段类型转换
在 Tableau 中,我们可以在“数据源”页面或工作表“数据”窗格页面中更改字段的数据类型。
数据源页
工作表“数据”窗格
04–认识 Tableau 数据–字段简单处理
1.4.1 数据解释器
1.4.2 列拆分
- 数据源页
- 工作表“数据”窗格
1.4.3 转置
1.4.4 隐藏
1.4.5 重命名
05–支持导入的数据类型丰富多样
2.1 本地文件数据
- 2.1.1 Excel 文件
- 2.1.2 文本文件( csv / txt )
2.2 服务器数据
06–轻松实现数据融合–数据连接
3.1 数据连接
3.1.1 连接方式
3.1.2
英雄榜
07–轻松实现数据融合–数据合并[3]
3.2.1 数据合并方式
- 手动合并
- 通配符搜索
08–轻松实现数据融合–数据混合关系
4. 大数据查询利器 Hive
5. 数据分析必学编程语言-Python
6. 数据分析必备理论基础-统计学知识
1 统计学基本原理:描述统计、总体推断
任务一:描述统计
统计学的本质和目的
统计学基本概念:变量测量尺度
定距的数据,比如温度,为 0 是有意义的(没有绝对 0 点),而定比的数据,为 0 是没意义的;定比的数据可以乘除
统计学基本概念:平均值
统计学基本概念:中位数和众数
均值和中值、众数衡量集中趋势,可以描述一个群体的共性
统计学基本概念:极差和标准差
离散趋势(应用更多,代表了数据包含的信息量)
任务二:总体推断
7. 数据分析项目实战-指标体系与 ABTest
8. 数据挖掘算法与实战
第八阶段模块一
1–任务一: KNN 算法
01–前言:机器学习理论基础
1.1 常用机器学习算法体系
- 1.1.1 有监督学习
- 1.1.2 无监督学习
- 1.1.3 半监督学习
- 1.1.4 强化学习
- 1.1.5 输入/输出空间、特征空间
- 1.1.6 过拟合与欠拟合
02–算法原理与实现步骤
03–算法优缺点及算法变种
04–python 实现
导入相关包
#全部行都能输出 from IPython.core.interactiveshell import InteractiveShell InteractiveShell.ast_node_interactivity = "all" import numpy as np import pandas as pd import matplotlib.pyplot as plt # 解决坐标轴刻度负号乱码 plt.rcParams['axes.unicode_minus'] = False # 解决中文乱码问题 plt.rcParams['font.sans-serif'] = ['Simhei'] plt.style.use('ggplot') # plt.figure(figsize=(2,3),dpi=720)
构建已经分类好的原始数据集
首先随机设置十个样本点表示十杯酒,这里取了部分样本。为了方便验证,这里使用 Python 的字典 dict 构建数据集,然后再将其转化成 DataFrame 格式。
rowdata = {'颜色深度': [14.13,13.2,13.16,14.27,13.24,12.07,12.43,11.79,12.37,12.04], '酒精浓度': [5.64,4.28,5.68,4.80,4.22,2.76,3.94,3.1,2.12,2.6], '品种': [0,0,0,0,0,1,1,1,1,1]} # 0 代表 “黑皮诺”,1 代表 “赤霞珠” wine_data = pd.DataFrame(rowdata) wine_data
X = np.array(wine_data.iloc[:, 0:2]) # 我们把特征(酒的属性)放在X y = np.array(wine_data.iloc[:, -1]) # 把标签(酒的类别)放在Y # 探索数据,假如我们给出新数据[12.03,4.1] ,你能猜出这杯红酒是什么类别么? new_data = np.array([12.03, 4.1]) plt.scatter(X[y == 1, 0], X[y == 1, 1], color='red', label='赤霞珠') # 画出标签y为1的、关于“赤霞珠”的散点 plt.scatter(X[y == 0, 0], X[y == 0, 1], color='purple', label='黑皮诺') # 画出标签y为0的、关于“黑皮诺”的散点 plt.scatter(new_data[0], new_data[1], color='yellow') # 新数据点 print(new_data) plt.xlabel('酒精浓度') plt.ylabel('颜色深度') plt.legend(loc='lower right') plt.savefig('葡萄酒样本.png')
计算已知类别数据集中的点与当前点之间的距离
我们使用欧式距离公式,计算新数据点 new_data 与现存的 X 数据集每一个点的距离:
from math import sqrt distance = [sqrt(np.sum((x-new_data)**2)) for x in X ] distance
将距离升序排列,然后选取距离最小的 k 个点
sort_dist = np.argsort(distance) sort_dist
array([6, 7, 1, 4, 5, 9, 2, 8, 3, 0], dtype=int64)
6、7、4 为最近的 3 个“数据点”的索引值,那么这些索引值对应的原数据的标签是什么?
k = 3 topK = [y[i] for i in sort_dist[:k]] topK # [1,1,0]
确定前 k 个点所在类别的计数
pd.Series(topK).value_counts().index[0] # 1
将上述过程封装成一个函数
def KNN(new_data,dataSet,k): ''' 函数功能:KNN分类器 参数说明: new_data: 需要预测分类的数据集 dataSet: 已知分类标签的数据集 k: k-近邻算法参数,选择距离最小的k个点 return: result: 分类结果 ''' from math import sqrt from collections import Counter import numpy as np import pandas as pd result = [] distance = [sqrt(np.sum((x-new_data)**2)) for x in np.array(dataSet.iloc[:,0:2])] sort_dist = np.argsort(distance) topK = [dataSet.iloc[:,-1][i] for i in sort_dist[:k]] result.append(pd.Series(topK).value_counts().index[0]) return result
# 测试函数的运行结果 new_data=np.array([12.03,4.1]) k = 3 KNN(new_data,wine_data,k) # [1]
05–python 实现总结及可视化
# 全部行都能输出
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 解决坐标轴刻度负号乱码
plt.rcParams['axes.unicode_minus'] = False
# 解决中文乱码问题
plt.rcParams['font.sans-serif'] = ['Simhei']
plt.style.use('ggplot')
# plt.figure(figsize=(2,3),dpi=720)
rowdata = {'颜色深度': [14.13, 13.2, 13.16, 14.27, 13.24, 12.07, 12.43, 11.79, 12.37, 12.04],
'酒精浓度': [5.64, 4.28, 5.68, 4.80, 4.22, 2.76, 3.94, 3.1, 2.12, 2.6],
'品种': [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]}
# 0 代表 “黑皮诺”,1 代表 “赤霞珠”
wine_data = pd.DataFrame(rowdata)
print(wine_data)
X = np.array(wine_data.iloc[:, 0:2]) # 我们把特征(酒的属性)放在X
y = np.array(wine_data.iloc[:, -1]) # 把标签(酒的类别)放在Y
# 探索数据,假如我们给出新数据[12.03,4.1] ,你能猜出这杯红酒是什么类别么?
new_data = np.array([12.03, 4.1])
plt.scatter(X[y == 1, 0], X[y == 1, 1], color='red', label='赤霞珠') # 画出标签y为1的、关于“赤霞珠”的散点
plt.scatter(X[y == 0, 0], X[y == 0, 1], color='purple', label='黑皮诺') # 画出标签y为0的、关于“黑皮诺”的散点
plt.scatter(new_data[0], new_data[1], color='yellow') # 新数据点
print(new_data)
plt.xlabel('酒精浓度')
plt.ylabel('颜色深度')
plt.legend(loc='lower right')
plt.savefig('葡萄酒样本.png')
plt.show()
from math import sqrt
distance = [sqrt(np.sum((x - new_data) ** 2)) for x in X]
print(distance)
# 从近到远排序后的原数据点
sort_dist = np.argsort(distance)
print('sort_dist:\n', sort_dist)
k = 3
# 找出离新数据最近的3个点
topK = [y[i] for i in sort_dist[:k]]
print(topK) # [1,1,0]
# Pandas Series 类似表格中的一个列(column),类似于一维数组,可以保存任何数据类型
# 找出其中数量最多的值
print(pd.Series(topK).value_counts().index[0]) # 1
def KNN(new_data, dataSet, k):
'''
函数功能:KNN分类器
参数说明:
new_data: 需要预测分类的数据集
dataSet: 已知分类标签的数据集
k: k-近邻算法参数,选择距离最小的k个点
return:
result: 分类结果
'''
from math import sqrt
from collections import Counter
import numpy as np
import pandas as pd
result = []
distance = [sqrt(np.sum((x - new_data) ** 2)) for x in
np.array(dataSet.iloc[:, 0:len(dataSet.columns) - 2])]
sort_dist = np.argsort(distance)
topK = [dataSet.iloc[:, -1][i] for i in sort_dist[:k]]
result.append(pd.Series(topK).value_counts().index[0])
return result
# 测试函数的运行结果
new_data = np.array([12.03, 4.1])
k = 3
print(KNN(new_data, wine_data, k)) # [1]
06–使用 sklearn 实现
案例一:红酒
from sklearn.neighbors import KNeighborsClassifier # 0 代表 “黑皮诺”,1 代表 “赤霞珠” clf = KNeighborsClassifier(n_neighbors = 3) clf = clf.fit(wine_data.iloc[:,0:2], wine_data.iloc[:,-1]) result = clf.predict([[12.8,4.1]]) # 返回预测的标签 result # array([0])
# 对模型进行一个评估,接口score返回预测的准确率 score = clf.score([[12.8,4.1]],[0]) score # 1.0
clf.predict_proba([[12.8,4.1]]) # array([[0.66666667, 0.33333333]]) #输出数据[12.8,4.1]为标签0的概率(0.666...),以及标签为1的概率(0.333...)
.py
from sklearn.neighbors import KNeighborsClassifier import pandas as pd import numpy as np rowdata = {'颜色深度': [14.13, 13.2, 13.16, 14.27, 13.24, 12.07, 12.43, 11.79, 12.37, 12.04], '酒精浓度': [5.64, 4.28, 5.68, 4.80, 4.22, 2.76, 3.94, 3.1, 2.12, 2.6], '品种': [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]} # 0 代表 “黑皮诺”,1 代表 “赤霞珠” wine_data = pd.DataFrame(rowdata) clf = KNeighborsClassifier(n_neighbors=3) # n_neighbors默认5 # 拟合(训练) clf = clf.fit(wine_data.iloc[:, 0:2], wine_data.iloc[:, -1]) # 预测 res = clf.predict([[12.8, 4.1]]) print(res) # [0] # 对模型进行一个评估,接口score返回预测的准确率 score = clf.score([[12.8, 4.1]], [0]) print(score) # 1.0 proba = clf.predict_proba([[12.8, 4.1]]) print(proba) # array([[0.66666667, 0.33333333]]) # 输出数据[12.8,4.1]为标签0的概率(0.666...),以及标签为1的概率(0.333...) # 生成10个随机点 # numpy.random.normal(loc=0.0, scale=1.0, size=None) # 从正态(高斯)分布中抽取随机样本。 # loc: 分布的均值(中心) # scale: 分布的标准差(宽度) # size: 输出值的维度 a = np.random.normal(11, 2, (10, 1)) b = np.random.normal(5, 1, (10, 1)) # print(a, b) # 拼接(列) new_data = np.concatenate([a, b], axis=1) print(new_data) # 预测 print(clf.predict(new_data)) # 设实际的红酒类型 y_new = np.array([1, 0, 1, 0, 0, 1, 1, 0, 0, 1]) score = clf.score(new_data, y_new) print(score) proba = clf.predict_proba(new_data) print(proba) # 左列是标签为0的概率,右列是标签为1的概率
案例二:乳腺癌
from sklearn.neighbors import KNeighborsClassifier from sklearn.datasets import load_breast_cancer from sklearn.model_selection import train_test_split import pandas as pd import numpy as np # 读取数据集 data = load_breast_cancer() # DateFrame格式显示 X = data.data y = data.target name = ['平均半径','平均纹理','平均周长','平均面积', '平均光滑度','平均紧凑度','平均凹度', '平均凹点','平均对称','平均分形维数', '半径误差','纹理误差','周长误差','面积误差', '平滑度误差','紧凑度误差','凹度误差', '凹点误差','对称误差', '分形维数误差','最差半径','最差纹理', '最差的边界','最差的区域','最差的平滑度', '最差的紧凑性','最差的凹陷','最差的凹点', '最差的对称性','最差的分形维数','患病否'] data=np.concatenate((X,y.reshape(-1,1)),axis=1) table=pd.DataFrame(data=data,columns=name) table.head() # 划分训练集和测试集 #30%数据作为训练集 Xtrain,Xtest,Ytrain,Ytest = train_test_split(X,y,test_size=0.2,random_state=420) # 建立模型&评估模型 clf = KNeighborsClassifier(n_neighbors=4) # 建立分类器 clf = clf.fit(Xtrain,Ytrain) score = clf.score(Xtest,Ytest) score # 0.9210526315789473 #查找点的K邻居。返回每个点的邻居的与之的距离和索引值。 clf.kneighbors(Xtest[[20,30],:],return_distance=True) ''' (array([[35.70015941, 42.02374599, 81.82147557, 83.06271326], [11.81126721, 14.5871725 , 17.4734004 , 18.94892695]]), array([[112, 221, 303, 263], [268, 162, 42, 134]], dtype=int64)) '''
from sklearn.neighbors import KNeighborsClassifier from sklearn.datasets import load_breast_cancer from sklearn.model_selection import train_test_split import pandas as pd import numpy as np # 读取数据集 data = load_breast_cancer() # DateFrame格式显示 X = data.data y = data.target name = ['平均半径', '平均纹理', '平均周长', '平均面积', '平均光滑度', '平均紧凑度', '平均凹度', '平均凹点', '平均对称', '平均分形维数', '半径误差', '纹理误差', '周长误差', '面积误差', '平滑度误差', '紧凑度误差', '凹度误差', '凹点误差', '对称误差', '分形维数误差', '最差半径', '最差纹理', '最差的边界', '最差的区域', '最差的平滑度', '最差的紧凑性', '最差的凹陷', '最差的凹点', '最差的对称性', '最差的分形维数', '患病否'] # y.reshape(-1,1) -> -1自动推导,1则是1列,作为目标列 # axis=1,按列拼接 data = np.concatenate((X, y.reshape(-1, 1)), axis=1) table = pd.DataFrame(data=data, columns=name) print('head:\n', table.head()) # 划分训练集和测试集 #30%数据作为训练集 # random_state类似于随机种子 Xtrain, Xtest, Ytrain, Ytest = train_test_split(X, y, test_size=0.2, random_state=420) # 建立模型&评估模型 clf = KNeighborsClassifier(n_neighbors=4) # 建立分类器 clf = clf.fit(Xtrain, Ytrain) score = clf.score(Xtest, Ytest) print('score:\n', score) # 0.9210526315789473 # 查找点的K邻居。返回 每个点的邻居 的 与之的距离和索引值。 res = clf.kneighbors(Xtest[[20, 30], :], return_distance=True) print('res:\n', res) ''' (array([[35.70015941, 42.02374599, 81.82147557, 83.06271326], [11.81126721, 14.5871725 , 17.4734004 , 18.94892695]]), array([[112, 221, 303, 263], [268, 162, 42, 134]], dtype=int64)) '''
08–绘制学习曲线
2.1.6.1 学习曲线
那我们怎样选择一个最佳的 k 呢?在这里我们要使用机器学习中的神器:参数学习曲线。参数学习曲线是一条以不同的参数取值为横坐标,不同参数取值下的模型结果为纵坐标的曲线,我们往往选择模型表现最佳点的参数取值作为这个参数的取值。
# 更换不同的n_neighbors参数的取值,观察结果的变化 clf = KNeighborsClassifier(n_neighbors=7) clf = clf.fit(Xtrain,Ytrain) score = clf.score(Xtest,Ytest) score # 0.9385964912280702
绘制学习曲线:
import matplotlib.pyplot as plt score = [] # 得分列表 krange = range(1, 20) for i in krange: # 使用不同的n_neighbors参数值 clf = KNeighborsClassifier(n_neighbors=i) # 训练 clf = clf.fit(Xtrain, Ytrain) # 记录得分 score.append(clf.score(Xtest, Ytest)) plt.plot(krange, score) plt.xticks(range(1, 20)) # x轴设置为1~20 plt.show()
究竟上图中 k 为多少的时候分数越高?
score.index(max(score))+1 # 8
但是这个时候会有个问题,如果随机划分的数据集变化的的话,得分最高的 k 值也会发生变化:
Xtrain,Xtest,Ytrain,Ytest = train_test_split(X,y,test_size=0.2,random_state=421) score = [] krange = range(1,20) for i in krange: clf = KNeighborsClassifier(n_neighbors=i) clf = clf.fit(Xtrain,Ytrain) score.append(clf.score(Xtest,Ytest)) plt.plot(krange,score) plt.show()
09–交叉验证
2.1.7.1 泛化能力
2.1.7.2 K 折交叉验证
2.1.7.3 带交叉验证的学习曲线
from sklearn.model_selection import cross_val_score as CVS Xtrain,Xtest,Ytrain,Ytest = train_test_split(X,y,test_size=0.2,random_state=420) clf = KNeighborsClassifier(n_neighbors=8) cvresult = CVS(clf,Xtrain,Ytrain,cv=6) #训练集对折6次,一共6个预测率输出 # array([0.92207792, 0.90789474, 0.97368421, 0.94736842, 0.93333333, 0.92 ]) cvresult #每次交叉验证运行时估算器得分的数组 # 均值:查看模型的平均效果 cvresult.mean() # 方差:查看模型是否稳定 cvresult.var() score = [] var = [] krange=range(1,20) # 设置不同的k值,从1到19都看看 for i in krange: clf = KNeighborsClassifier(n_neighbors=i) cvresult = CVS(clf,Xtrain,Ytrain,cv=5) score.append(cvresult.mean()) # 每次交叉验证返回的得分数组,再求数组均值 var.append(cvresult.var()) plt.plot(krange,score,color='k') plt.plot(krange,np.array(score)+np.array(var)*2,c='red',linestyle='--') plt.plot(krange,np.array(score)-np.array(var)*2,c='red',linestyle='--')
11–归一化
2.1.8.1 距离类模型归一化的要求
2.1.8.2 先分数据集,再做归一化
2.1.8.3 通过 python 实现
data = [[-1,2],[-0.5,6],[0,10],[1,18]] data=pd.DataFrame(data) (data-np.min(data,axis=0))/(np.max(data,axis=0)-np.min(data,axis=0))
2.1.8.4 通过 sklearn 实现
from sklearn.preprocessing import MinMaxScaler as mms Xtrain,Xtest,Ytrain,Ytest=train_test_split(X,y,test_size=0.2,random_state=420) #归一化 MMS_01=mms().fit(Xtrain) #求训练集最大/小值 MMS_02=mms().fit(Xtest) #求测试集最大/小值 #转换 X_train=MMS_01.transform(Xtrain) X_test =MMS_02.transform(Xtest) score=[] var=[] for i in range(1,20): clf=KNeighborsClassifier(n_neighbors=i) cvresult=CVS(clf,X_train,Ytrain,cv=5) # 交叉验证的每次得分 score.append(cvresult.mean()) var.append(cvresult.var()) plt.plot(krange,score,color="k") plt.plot(krange,np.array(score)+np.array(var)*2,c="red",linestyle="--") plt.plot(krange,np.array(score)-np.array(var)*2,c="red",linestyle="--") plt.show() score.index(max(score))+1 # 8
clf=KNeighborsClassifier(n_neighbors=6,weights='distance').fit(X_train,Ytrain) score=clf.score(X_test,Ytest) score # 0.956140350877193
12–距离的惩罚
在样本很不均匀时可以使用,样本均匀时效果不是很明显
for i in range(1, 20):
clf = KNeighborsClassifier(n_neighbors=i, weights='distance')
cvresult = CVS(clf, X_train, Ytrain, cv=5) # 交叉验证的每次得分
score.append(cvresult.mean())
var.append(cvresult.var())
plt.plot(krange, score, color="k")
plt.plot(krange, np.array(score) + np.array(var) * 2, c="red", linestyle="--")
plt.plot(krange, np.array(score) - np.array(var) * 2, c="red", linestyle="--")
plt.show()
score.index(max(score))+1
print(score) # 6
clf=KNeighborsClassifier(n_neighbors=6,weights='distance').fit(X_train,Ytrain)
score=clf.score(X_test,Ytest)
score # 0.9473684210526315
2–任务二: 决策树
01–算法概述
- 2.2.1 决策树模型
- 2.2.1.1 决策树基本流程
- 2.2.1.2 决策与条件概率分布
- 2.2.1.3 学习算法
- 2.2.1.1 决策树基本流程
02–特征选择-信息熵
香农熵的计算
import numpy as np p=1/2 -((p*np.log2(p))+(p*np.log2(p)))
香农熵的代码实现
row_data = {'是否陪伴': [0, 0, 0, 1, 1], '是否玩游戏': [1, 1, 0, 1, 1], '渣男': ['是', '是', '不是', '不是', '不是']} dataSet = pd.DataFrame(row_data) dataSet
def calEnt(dataSet): n = dataSet.shape[0] # 数据集总行数 # [[不是, 3], [是, 2]] iset = dataSet.iloc[:, -1].value_counts() # 标签的所有类别 p = iset / n # 每一类标签所占比 ent = (-p * np.log2(p)).sum() # 计算信息熵 return ent # 计算全体数据的信息熵——根据标签列去进行计算 # 0.9709505944546686 calEnt(dataSet)
03–特征选择-信息增益
04–划分数据集
- 数据集最佳切分函数
import numpy as np
import pandas as pd
row_data = {'是否陪伴': [0, 0, 0, 1, 1],
'是否玩游戏': [1, 1, 0, 1, 1],
'渣男': ['是', '是', '不是', '不是', '不是']}
dataSet = pd.DataFrame(row_data)
# 定义信息熵
def calEnt(dataSet):
n = dataSet.shape[0] # 数据集总行数
iset = dataSet.iloc[:, -1].value_counts() # 统计标签的所有类别
p = iset / n # 统计每一类标签所占比
ent = (-p * np.log2(p)).sum() # 计算信息熵
return ent
# 选择最优的列进行切分
def bestSplit(dataSet):
baseEnt = calEnt(dataSet) # 计算原始熵
bestGain = 0 # 初始化信息增益
axis = -1 # 初始化最佳切分列,标签列
for i in range(dataSet.shape[1] - 1): # 对特征的每一列进行循环
levels = dataSet.iloc[:, i].value_counts().index # 提取出当前列的所有取值
ents = 0 # 初始化子节点的信息熵
for j in levels: # 对当前列的每一个取值进行循环
childSet = dataSet[dataSet.iloc[:, i] == j] # 某一个子节点的dataframe
ent = calEnt(childSet) # 计算某一个子节点的信息熵
ents += (childSet.shape[0] / dataSet.shape[0]) * ent # 计算当前列的信息熵
print('第{}列的信息熵为{}'.format(i, ents))
infoGain = baseEnt - ents # 计算当前列的信息增益
print('第{}列的信息增益为{}\n'.format(i, infoGain))
if (infoGain > bestGain):
bestGain = infoGain # 选择最大信息增益
axis = i # 最大信息增益所在列的索引
print("第{}列为最优切分列".format(axis))
return axis
print(bestSplit(dataSet))
- 按照给定列切分数据集
def mySplit(dataSet, axis, value):
"""
函数功能:按照给定的列划分数据集
参数说明:
dataSet:原始数据集
axis:指定的列索引
value:指定的属性值
return:redataSet:按照指定列索引和属性值切分后的数据集
"""
col = dataSet.columns[axis]
redataSet = dataSet.loc[dataSet[col] == value, :].drop(col, axis=1)
return redataSet
# 验证函数:以axis=0,value=1为例
print(mySplit(dataSet, 0, 1))
05–决策树生成(算法解析)
- ID3 算法
row_data = {'是否陪伴': [0, 0, 0, 1, 1],
'是否玩游戏': [1, 1, 0, 1, 1],
'渣男': ['是', '是', '不是', '不是', '不是']}
dataSet = pd.DataFrame(row_data)
def createTree(dataSet):
"""
函数功能:基于最大信息增益切分数据集,递归构建决策树
参数说明:
dataSet:原始数据集(最有一列是标签)
return:myTree:字典形式的树
"""
featlist = list(dataSet.columns) # 提取出数据集所有的列
# print(featlist) # ['是否陪伴', '是否玩游戏', '渣男']
# 最后一列 -> [所有出现的取值:该取值的数量]
classlist = dataSet.iloc[:, -1].value_counts() # 获取最后一列类标签
# 每个分支下的所有实例都具有相同的分类 || 程序遍历完所有划分数据集的属性
# 判断最多标签数目是否等于数据集行数,或者数据集是否只有一列
if classlist[0] == dataSet.shape[0] or dataSet.shape[1] == 1:
return classlist.index[0] # 如果是,返回类标签
axis = bestSplit(dataSet) # 确定出当前最佳切分列的索引
bestfeat = featlist[axis] # 获取该索引对应的特征
myTree = {bestfeat: {}} # 采用字典嵌套的方式存储树信息
del featlist[axis] # 删除当前特征
valuelist = set(dataSet.iloc[:, axis]) # 提取最佳切分列所有属性值
for value in valuelist: # 对每一个属性值递归建树
# mySplit([[1,1],[2,1],[0,0]],1,1) -> [1,2]
# mySplit(数据集,第i列,value) 提取dataset中,第i列中,和value相等的值,组成新dataset
myTree[bestfeat][value] = createTree(mySplit(dataSet, axis, value))
return myTree
#查看运行结果
myTree = createTree(dataSet)
# {'是否陪伴': {0: {'是否玩游戏': {0: '不是', 1: '是'}}, 1: '不是'}}
print(myTree)
- C4.5 算法
06–拟合度优化(CART 算法)
- 剪枝
- CART 算法
- 测试集和验证集
07–使用 sklearn 生成决策树
参数 CRITERION
初步建模
import pandas as pd import numpy as np import matplotlib.pyplot as plt # %matplotlib inline from sklearn import tree from sklearn.datasets import load_wine from sklearn.model_selection import train_test_split plt.rcParams['font.sans-serif'] = ['Simhei'] plt.rcParams['axes.unicode_minus'] = False
探索数据
wine = load_wine() print('wine.data.shape:\n', wine.data.shape) print('wine.target:\n', wine.target) # 将data(特征)和target(结果),按列拼接 wine_pd = pd.concat([pd.DataFrame(wine.data), pd.DataFrame(wine.target)], axis=1).head() # wine.feature_names.append("result") wine.feature_names = ['酒精', '苹果酸', '灰', '灰的碱性', '镁', '总酚', '类黄酮', '非黄烷类酚类', '花青素', '颜色强度', '色调', 'od280/od315 稀释葡萄酒', '脯氨酸', 'result'] wine_pd.columns = wine.feature_names print('wine_pd:\n', wine_pd) print('wine_pd.info:\n',wine_pd.info()) # 划分数据集 # random_state: 随机种子 Xtrain, Xtest, Ytrain, ytest = train_test_split(wine.data, wine.target, test_size=0.3, random_state=420) print('xtrain.shape:\n', Xtrain.shape) print('xtest.shape:\n', Xtest.shape)
建立模型
# 建立模型 clf = tree.DecisionTreeClassifier(criterion="gini") # 使用基尼系数计算不纯度(熵越高,不纯度越高,决策树要让不纯度降低) clf = clf.fit(Xtrain, Ytrain) # 0.9444444444444444 print(clf.score(Xtest, ytest)) # 返回预测的准确度
画出一棵树
同时,我们可以利用 Graphviz 模块导出决策树模型,第一次使用 Graphviz 之前需要对其进行安装(官网下安装包,然后安装并配置环境变量), 若是使用从 pip 进行的 Python 包管理,则可直接在命令⾏界⾯中利用下述指令进行安装: pip install graphviz
import matplotlib.pyplot as plt feature_name = ['酒精', '苹果酸', '灰', '灰的碱性', '镁', '总酚', '类黄酮', '非黄烷类酚类', '花青素', '颜色强度', '色调', 'od280/od315 稀释葡萄酒', '脯氨酸'] import graphviz print(graphviz.__version__) dot_data = tree.export_graphviz(clf, out_file=None, feature_names=feature_name, class_names=["琴酒", "雪莉", "贝尔摩德"], filled=True, rounded=True) graph = graphviz.Source(dot_data, filename='决策树.pdf') graph
08–探索决策树属性(pdf 生成)
pdf 生成
dot_data = tree.export_graphviz(clf, out_file=None, # 将该py文件设置为utf-8格式 # 然后设置字体为仿宋,就可以解决pdf中文乱码 fontname="FangSong", feature_names=feature_name, class_names=["琴酒", "雪莉", "贝尔摩德"], filled=True, rounded=True) graph = graphviz.Source(dot_data) print(graph) graph.render('wine')
探索决策树属性
clf.feature_importances
clf.feature_importances_ [*zip(feature_name,clf.feature_importances_)]
clf.apply
clf.tree_.node_count
clf.tree_.feature
09–防止过拟合(剪枝参数)
random_state
splitter
剪枝参数
max_depth
min_samples_leaf
min_samples_split
max_features
min_impurity_decrease
确认最优的剪枝参数
test = [] # 如果多个参数都要调整,就需要多层for循环,怎么办? -> 网络搜索 for i in range(10): clf = tree.DecisionTreeClassifier(max_depth=i + 1, # 最大深度 criterion="entropy", random_state=30, # min_samples_leaf=5, # 子节点包含样本最小个数(父节点) # min_samples_split=20 , splitter="random") clf = clf.fit(Xtrain, Ytrain) score = clf.score(Xtest, ytest) # 记录下不同 max_depth 下模型在测试集分数 test.append(score) plt.plot(range(1, 11), test, color="red", label="学习曲线") plt.ylabel("socre") plt.xlabel("max_depth") plt.legend() plt.show()
10–分类模型评估指标(class_weight)
- class_weight
import numpy as np
import matplotlib.pyplot as plt
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_blobs # 聚类产生数据集的方法
class_1 = 1000 # 类别1,1000个
class_2 = 100 # 类别2,100个
centers = [[0, 0], [2.0, 2.0]] # 两个类别的中心点
clusters_std = [2.5, 0.5] # 两个类别的方差
X, y = make_blobs(n_samples=[class_1, class_2],
centers=centers,
cluster_std=clusters_std,
random_state=420,
shuffle=False)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap='rainbow', s=10)
plt.show()
# 划分数据集
Xtrain, Xtest, Ytrain, Ytest = train_test_split(X, y, test_size=0.2, random_state=420)
# 不设定class_weight
clf_1 = DecisionTreeClassifier()
clf_1.fit(Xtrain, Ytrain)
# 设定class_weight
clf_2 = DecisionTreeClassifier(class_weight='balanced')
clf_2.fit(Xtrain, Ytrain)
# 0.8954545454545455
print('clf1.score:\n', clf_1.score(Xtest, Ytest))
# 0.9045454545454545
print('clf2.score:\n', clf_2.score(Xtest, Ytest))
11–分类模型评估指标(混淆矩阵)
# PART2 混淆矩阵
from sklearn import metrics
# 样本平衡前
predict = metrics.confusion_matrix(Ytest, clf_1.predict(Xtest))
print('predict:\n', predict)
# 样本平衡后
predict = metrics.confusion_matrix(Ytest, clf_2.predict(Xtest))
print('predict:\n', predict)
# 精准率 -> 精确度是” 将多数类判错后所需付出成本的衡量’’,越高越好
# 精确度越低,意味着 01 比重很大,则代表你的模型对多数类 0 误判率越高,误伤了过多的多数类。
pScore = metrics.precision_score(Ytest, clf_1.predict(Xtest))
print('pScore:\n', pScore) # 0.6363636363636364
pScore = metrics.precision_score(Ytest, clf_2.predict(Xtest))
print('pScore:\n', pScore) # 0.6538461538461539
# 召回率 -> 召回率越高,代表我们尽量捕捉出了越多的少数类
rScore = metrics.recall_score(Ytest, clf_1.predict(Xtest))
print('rScore:\n', rScore) # 0.4827586206896552
rScore = metrics.recall_score(Ytest, clf_2.predict(Xtest))
print('rScore:\n', rScore) # 0.5862068965517241
# F值 -> 取值0~1,越高越好
# 为了同时兼顾精确度和召回率,用两者的调和平均数作为考量两者平衡的综合性指标,称之为F1 measure
f1Score = metrics.f1_score(Ytest, clf_1.predict(Xtest))
print('f1Score:\n', f1Score) # 0.56
f1Score = metrics.f1_score(Ytest, clf_2.predict(Xtest))
print('f1Score:\n', f1Score) # 0.6296296296296295
总结
3–任务三: 线性回归
01–基础原理(python 实现)
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 解决报错
'''
MatplotlibDeprecationWarning: Support for FigureCanvases without a required_interactive_framework
attribute was deprecated in Matplotlib 3.6 and will be removed two minor releases later.
'''
plt.switch_backend('TkAgg')
# plt.switch_backend('WebAgg')
# plt.switch_backend('QtAgg')
# 随机种子
np.random.seed(420)
# 生成横坐标
x = np.random.rand(50) * 10 # 50个点 -> 取值范围[0,10]
print('x:\n', x[:10])
# y = 2x-5
y = 2 * x - 5
# 添加扰动项
y += np.random.randn(50) # 生成50个正态分布下的随机数
print('y:\n', y[:10])
plt.plot(x, y, 'o')
plt.show()
from sklearn.linear_model import LinearRegression
# 实例化
model = LinearRegression(fit_intercept=True)
# 扩展维度,sklearn不接受1维的数据
# Reshape your data either using array.reshape(-1, 1)
# if your data has a single feature or array.reshape(1, -1) if it contains a single sample.
x = x.reshape(-1, 1)
# 训练模型
model.fit(x, y)
# coef_: 斜率
print('coef:\n', model.coef_) # [1.93715154]
# intercept_: 截距(y=kx+b中的b)
print('intercept_:\n', model.intercept_) # -4.8841609114156785
# 绘制拟合好的直线
# 生成绘制直线的横坐标
xfit = np.linspace(0, 10, 100) # 从0到10, 生成100个
print('xfit:\n', xfit[:10])
xfit = xfit.reshape(-1, 1)
# 预测
yfit = model.predict(xfit)
print('yfit:\n', yfit[:10])
# 画出点的直线
plt.plot(xfit,yfit)
# 画出原来训练集的点
plt.plot(x,y,'o')
plt.show()
多元线性回归 Python 实现
利用矩阵乘法编写回归算法
多元线性回归的执行函数编写并不复杂,主要涉及大量的矩阵运算,需要借助 Numpy 中的矩阵数据格式来完成。首先执行标准化导入import numpy as np import pandas as pd import matplotlib.pyplot as plt
回顾可能用到的矩阵运算相关知识:
矩阵创建
a = np.array([[1, 2], [3, 4]]) m = np.mat(a) # NumPy中创建矩阵需要使⽤mat函数,该函数需要输⼊⼆维数组 print('matrix:\n', m)
矩阵运算
当然,定义矩阵对象主要是为了能够执行矩阵运算,Numpy 中有个 linalg 库专门给矩阵对象提供计算方法,下面简答单回归常用矩阵运算# 矩阵转置 print('m.T:\n', m.T) # 矩阵乘法 print('m * m:\n', m * m) # 计算矩阵行列式 print('np.linalg.det(m):\n', np.linalg.det(m)) # 求逆矩阵 print('m.I:\n', m.I)
然后编写线性回归函数,同理,我们假设输入数据集为 DataFrame,且最后一列为标签值。
# 线性回归函数 def standRegres(dataSet): xMat = np.mat(dataSet.iloc[:, :-1].values) # 提取特征 yMat = np.mat(dataSet.iloc[:, -1].values).T # 提取标签 xTx = xMat.T * xMat if np.linalg.det(xTx) == 0: print('This matrix is singular,cannot do inverse') # 行列式为0,则该矩阵为奇异矩阵,无法求解逆矩阵 return ws = xTx.I * (xMat.T * yMat) return ws
这里需要提前判断 xTx 是否是满秩矩阵。若不满秩,则无法对其进行求逆矩阵的操作。定义完函数后,即可测试运行效果,此处我们建立线性随机数进行多元线性回归方程拟合。这里需要注意的是,当使用矩阵分解来求解多元线性回归时,必须添加一列全为 1 的列,用于表征线性方程截距
rng = np.random.RandomState(1) # 设置随机种子 x = 5 * rng.rand(100) # 100个[0,5)的随机数 y = 2 * x - 5 + rng.randn(100) # 真实规律的标签取值 X = pd.DataFrame(x) Y = pd.DataFrame(y) ex = pd.DataFrame(np.ones([100, 1])) # 添加一列权威1的列,表示截距 data = pd.concat([ex, X, Y], axis=1)
数据满足基本的建模要求,然后执行函数运算:
ws = standRegres(data) print('ws', ws)
返回结果即为各列特征权重,其中数据集第一列值均为 1,因此返回结果的第一个分量表示截距。然后可用可视化图形展示模型拟合效果
yhat = data.iloc[:,:-1].values*ws # 预测标签值 plt.plot(data.iloc[:,1],data.iloc[:,2],'o') #原始数据点 plt.plot(data.iloc[:,1],yhat) # 拟合直线
回顾算法评估指标
y = data.iloc[:, -1].values
yhat = yhat.flatten()
SSE = np.power(yhat - y, 2).sum()
print('SSE:\n', SSE)
def sseCal(dataSet, regres):
n = dataSet.shape[0]
y = dataSet.iloc[:, -1].values
ws = regres(dataSet)
yhat = dataSet.iloc[:, :-1].values * ws
yhat = yhat.flatten()
SSE = np.power(yhat - y, 2).sum()
return SSE
SSE = sseCal(data, standRegres)
print('SSE:\n', SSE)
sse = sseCal(data, standRegres)
y = data.iloc[:, -1].values
sst = np.power(y - y.mean(), 2).sum()
print(1 - sse / sst)
def rSquare(dataSet, regres):
sse = sseCal(dataSet, regres)
y = dataSet.iloc[:, -1].values
sst = np.power(y - y.mean(), 2).sum()
return 1 - sse / sst
res = rSquare(data, standRegres)
print('rSquare:\n', res)
02–房价预测(sklearn 实现)
一般线性回归通过看 MSE(平均残差)和 R^2(判定系数)来判断拟合程度
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.datasets import fetch_california_housing # 加利福尼亚房价数据集
import pandas as pd
# 下载数据
housevalue = fetch_california_housing()
# 特征解释
# MedInc:该街区住户的收入中位数
# HouseAge:该街区房屋使用年代的中位数
# AveRooms:该街区平均的房间数目
# AveBedrms:该街区平均的卧室数目
# Population:街区人口
# AveOccup:平均入住率
# Latitude:街区的纬度
# Longitude:街区的经度
print('feature_names:\n', housevalue.feature_names)
# 将数据转成DataFrame
X = pd.DataFrame(housevalue.data, columns=housevalue.feature_names)
print('x:\n', X[:5])
y = housevalue.target
print('y:\n', y[:5])
# 拆分数据集
Xtrain, Xtest, Ytrain, Ytest = train_test_split(X, y, test_size=0.3, random_state=420)
# 线性回归建模
model = LinearRegression()
# 拟合(训练)
model.fit(Xtrain, Ytrain)
# 模型评估
# MSE均方误差 -> 越小越好
from sklearn.metrics import mean_squared_error
# 对训练集做预测
y_pred = model.predict(Xtrain)
# 真实值和预测值对比
mse = mean_squared_error(Ytrain, y_pred)
# 0.52185226625331
print('mse:\n', mse)
# 对测试集做预测
y_test_pred = model.predict(Xtest)
# 真实值和预测值对比
mse = mean_squared_error(Ytest, y_test_pred)
# 0.5309012639324568
print('mse:\n', mse)
03–模型评估(sklearn 实现)
# 交叉验证,使用MSE指标
# neg_mean_squared_error -> 负的均方误差
cvs = cross_val_score(model, Xtrain, Ytrain, cv=10, scoring='neg_mean_squared_error')
print('cross_val_score(MSE):\n', cvs)
print('cross_val_score(MSE).mean():\n', cvs.mean()) # -0.5251459182173356
# MAE绝对均值误差(和MSE差不多,选一个用就行)
from sklearn.metrics import mean_absolute_error
mae = mean_absolute_error(Ytrain, y_pred)
# 0.5309427617356033
print('mae:\n', mae)
# 交叉验证,使用MAE指标
# neg_mean_absolute_error -> 负的绝对均方误差
cvs = cross_val_score(model, Xtrain, Ytrain, cv=10, scoring='neg_mean_absolute_error')
print('cross_val_score(MAE):\n', cvs)
print('cross_val_score(MAE).mean():\n', cvs.mean()) # -0.531393157638884
# R^2 -> 方差,衡量数据集包含多少信息量 -> 越接近1拟合效果越好
from sklearn.metrics import r2_score
r2Score = r2_score(Ytrain, y_pred)
print('r2Score:\n', r2Score) # 0.6067440341875014
r2Score = r2_score(Ytest, y_test_pred)
print('r2Score:\n', r2Score) # 0.6043668160178819
# 默认score就是用r2
score = model.score(Xtrain, Ytrain)
print('score:\n', score) # 0.6067440341875014
score = model.score(Xtest, Ytest)
print('score:\n', score) # 0.6043668160178819
# 交叉验证(R2)
cvs = cross_val_score(model, Xtrain, Ytrain, cv=10, scoring='r2')
print('cross_val_score(R2):\n', cvs)
print('cross_val_score(R2).mean():\n', cvs.mean()) # 0.6039238235546336
# 查看模型系数(训练计算出的w)
print('coef_:\n', model.coef_)
# 截距b
print('intercept_:\n', model.intercept_) # -36.256893229203854
zipXCoef = list(zip(X.columns, model.coef_))
print('zipXCoef:\n', zipXCoef)
04–拟合图像(sklearn 实现)
# 数据集标准化(归一化)后再训练
from sklearn.preprocessing import StandardScaler
std = StandardScaler()
# 训练集标准化
X_train_std = std.fit_transform(Xtrain)
print('X_train_std:\n', X_train_std[:5])
model2 = LinearRegression()
model2.fit(X_train_std, Ytrain)
score = model2.score(X_train_std, Ytrain)
print('score:\n', score) # 0.6067440341875014
# 绘制拟合图像
# 因为是无序的,所以点是乱的
plt.scatter(range(len(Ytest)), Ytest, s=2)
plt.show()
# 排序后
plt.scatter(range(len(Ytest)), sorted(Ytest), s=2)
plt.show()
# 预测值和真实值如何匹配
print('Ytest:\n', Ytest[:5])
print('y_test_pred:\n', y_test_pred[:5])
# 将测试值排序得到索引序列
Ytest_ids = np.argsort(Ytest)
print('Ytest_ids:\n', Ytest_ids[:5])
# 可以用id访问
print('Ytest:\n', Ytest[2477]) # 0.14999
# 预测值和真实值关联
print(y_test_pred[np.argsort(Ytest)][:5])
# 排序好的数据进行绘图
plt.scatter(range(len(Ytest)), sorted(Ytest), s=2, label='True')
plt.scatter(range(len(Ytest)), y_test_pred[np.argsort(Ytest)], s=2, c='r', label='True', alpha=0.3)
plt.show()
05–多重共线性(sklearn 实现)
import matplotlib.pyplot as plt
plt.switch_backend('TkAgg')
from sklearn.linear_model import LinearRegression
from sklearn.datasets import fetch_california_housing # 加利福尼亚房价数据集
import pandas as pd
# 下载数据
housevalue = fetch_california_housing()
# 特征解释
# MedInc:该街区住户的收入中位数
# HouseAge:该街区房屋使用年代的中位数
# AveRooms:该街区平均的房间数目
# AveBedrms:该街区平均的卧室数目
# Population:街区人口
# AveOccup:平均入住率
# Latitude:街区的纬度
# Longitude:街区的经度
print('feature_names:\n', housevalue.feature_names)
# 将数据转成DataFrame
X = pd.DataFrame(housevalue.data, columns=housevalue.feature_names)
print('x:\n', X[:5])
X.columns = [
'该街区住户的收入中位数', '该街区房屋使用年代的中位数', '该街区平均的房间数目',
'该街区平均的卧室数目', '街区人口', '平均入住率', '街区的纬度', '街区的经度'
]
print('x:\n', X[:5])
y = housevalue.target
print('y:\n', y[:5])
import sklearn
from sklearn.preprocessing import PolynomialFeatures
print(sklearn.__version__) # 1.2.2
# degree:度数,决定多项式的次数
poly = PolynomialFeatures(degree=2)
poly.fit(X, y)
p_features = poly.get_feature_names_out(X.columns)
# print('get_feature_names:\n', poly.get_feature_names(X.columns)) # 可能是旧版或新版的api?
print('get_feature_names_out:\n', p_features) # 通过多项式构造列
X_ = poly.transform(X) # 多项式变化后
# print('X:\n', X_[:5])
model = LinearRegression()
model.fit(X_, y) # 用转换后的数据进行训练
print('coef:\n', model.coef_)
print('zip:\n', [*zip(p_features, model.coef_)])
coeff = pd.DataFrame([p_features, model.coef_.tolist()]).T
print('coeff:\n', coeff)
# 变换前的模型的拟合效果
poly = PolynomialFeatures(degree=2)
poly.fit(X, y)
X_ = poly.transform(X)
model = LinearRegression()
model.fit(X, y)
# 0.606232685199805
print('score:\n', model.score(X, y))
model_poly = LinearRegression()
model.fit(X_, y)
# 0.6832976293317492
print('score:\n', model.score(X_, y))
- 岭回归和 lasso
import numpy as np
import pandas as pd
# 线性回归函数
def standRegres(dataSet):
xMat = np.mat(dataSet.iloc[:, :-1].values) # 提取特征
yMat = np.mat(dataSet.iloc[:, -1].values).T # 提取标签
xTx = xMat.T * xMat
if np.linalg.det(xTx) == 0:
print('This matrix is singular,cannot do inverse') # 行列式为0,则该矩阵为奇异矩阵,无法求解逆矩阵
return
ws = xTx.I * (xMat.T * yMat)
return ws
def sseCal(dataSet, regres):
n = dataSet.shape[0]
y = dataSet.iloc[:, -1].values
ws = regres(dataSet)
yhat = dataSet.iloc[:, :-1].values * ws
yhat = yhat.flatten()
SSE = np.power(yhat - y, 2).sum()
return SSE
def rSquare(dataSet, regres):
sse = sseCal(dataSet, regres)
y = dataSet.iloc[:, -1].values
sst = np.power(y - y.mean(), 2).sum()
return 1 - sse / sst
def ridgeRegres(dataSet, lam=0.2):
xMat = np.mat(dataSet.iloc[:, :-1].values)
yMat = np.mat(dataSet.iloc[:, -1].values).T
xTx = xMat.T * xMat
denom = xTx + np.eye(xMat.shape[1]) * lam
ws = denom.I * (xMat.T * yMat)
return ws
aba = pd.read_csv('abalone.csv', header=None)
print('aba.head():\n', aba.head())
aba.iloc[:, 0] = 1
print('aba.head():\n', aba.head())
rws = ridgeRegres(aba)
print('rws:\n', rws)
standRegres(aba)
rSquare(aba, ridgeRegres)
rSquare(aba, standRegres)
from sklearn.linear_model import Ridge
ridge = Ridge(alpha=0.2)
ridge.fit(aba.iloc[:, :-1], aba.iloc[:, -1])
print('ridge.coef_:\n', ridge.coef_) # 查看系数
print('ridge.intercept_:\n', ridge.intercept_) # 查看截距
from sklearn.linear_model import RidgeCV
Ridge_ = RidgeCV(alphas=np.arange(1, 1001, 100),
scoring="r2",
store_cv_values=True # ,cv=5
)
Ridge_.fit(aba.iloc[:, :-1], aba.iloc[:, -1])
# ⽆关交叉验证的岭回归结果
Ridge_.score(aba.iloc[:, :-1], aba.iloc[:, -1])
# 调⽤所有交叉验证的结果
print('Ridge_.cv_values_.shape:\n', Ridge_.cv_values_.shape)
# 进⾏平均后可以查看每个正则化系数取值下的交叉验证结果
Ridge_.cv_values_.mean(axis=0)
# 查看被选择出来的最佳正则化系数
print('Ridge_.alpha_:\n', Ridge_.alpha_)
4–任务四: 逻辑回归
01–基础原理
02–sklearn 实现
- 逻辑回归的 Scikit-Learn 实现
# 导入数据(乳腺癌)
import numpy as np
import pandas as pd
from sklearn.datasets import load_breast_cancer
import matplotlib.pyplot as plt
X = load_breast_cancer().data
Y = load_breast_cancer().target
x_pd = pd.DataFrame(X) # 可以考虑去量纲(标准化)
print('x:\n', x_pd[:3])
# 建模
from sklearn.linear_model import LogisticRegression as LR # 逻辑回归
from sklearn.model_selection import train_test_split
# LR(
# penalty='l2', # l2正则化---岭回归 l1正则化---lasso 默认l2
# *,
# dual=False,
# tol=0.0001,
# C=1.0, # C越小表示惩罚力度越大,C越大惩罚力度越小
# fit_intercept=True,
# intercept_scaling=1,
# class_weight=None,
# random_state=None,
# solver='lbfgs', # 梯度下降的方式
# max_iter=100, # 梯度下降会有迭代次数
# multi_class='auto',
# verbose=0,
# warm_start=False,
# n_jobs=None,
# l1_ratio=None,
# )
# liblinear -> 坐标下降法
model_l1 = LR(penalty='l1', solver='liblinear', C=0.5, max_iter=1000)
model_l1.fit(X, Y)
print('score:\n', model_l1.score(X, Y)) # 0.9578207381370826
model_l2 = LR(penalty='l2', solver='liblinear', C=0.5, max_iter=1000)
model_l2.fit(X, Y)
print('score:\n', model_l2.score(X, Y)) # 0.9560632688927944
# 剩下10个 -> l1正则化可以对特征进行筛选(重要的参数),防止过拟合
# 模型太复杂会把噪声学习进去(过拟合),当然,太简单会欠拟合
print('model_l1.coef_', model_l1.coef_)
print('model_l2.coef_', model_l2.coef_)
# 对每一行进行预测,每行预测结果加起来都为1
pred = model_l2.predict_proba(X) # 0 1
print('predict_proba\n', pred)
print('predict_proba.sum:\n', pred.sum(axis=1)[:5])
03–绘制学习曲线 2
# 绘制学习曲线
Xtrain, Xtest, Ytrain, Ytest = train_test_split(X, Y, test_size=0.3, random_state=420)
# 查看C在L1和L2下训练集和测试集的表现
l1 = []
l2 = []
l1test = []
l2test = []
# 在0.05到1之间均匀地取20个数
for i in np.linspace(0.05, 1, 19):
# 实例化模型
lrl1 = LR(penalty='l1', solver='liblinear', C=i, max_iter=1000)
lrl1.fit(Xtrain, Ytrain)
lrl2 = LR(penalty='l2', solver='liblinear', C=i, max_iter=1000)
lrl2.fit(Xtrain, Ytrain)
# 记录训练集分数
l1.append(lrl1.score(Xtrain, Ytrain))
l2.append(lrl2.score(Xtrain, Ytrain))
# 记录测试分数
l1test.append(lrl1.score(Xtest, Ytest))
l2test.append(lrl2.score(Xtest, Ytest))
# 画图
plt.switch_backend('TkAgg')
graph = [l1, l2, l1test, l2test]
color = ['green', 'black', 'lightgreen', 'gray']
label = ['L1', 'L2', 'L1test', 'L2test']
plt.figure(figsize=(6, 6))
for i in range(len(graph)):
plt.plot(np.linspace(0.05, 1, 19), graph[i], color[i], label=label[i])
plt.legend(loc=4) # 图例位置在哪?4表示右下角
plt.show()
04–利用网格搜索确定最优参数
- 算法优化参数:solver
- 梯度下降:重要参数 max_iter
- 分类方式选参数
# 网格搜索-确认最优参数
from sklearn.model_selection import GridSearchCV # 网络搜索
'''
在机器学习领域中,不同评价指标(即特征向量中的不同特征就是所述的不同评价指标)往往具有不同的量纲和量纲单位,
这样的情况会影响到数据分析的结果,为了消除指标之间的量纲影响,需要进行数据标准化处理,以解决数据指标之间的可比性。
'''
from sklearn.preprocessing import StandardScaler # 标准化
data = pd.DataFrame(X, columns=load_breast_cancer().feature_names)
print('data:\n', data.head())
data['label'] = Y
# 划分数据集
Xtrain, Xtest, Ytrain, Ytest = train_test_split(X, Y, test_size=0.3, random_state=420)
# 对训练集和测试集做标准化--去量纲
Xstd = StandardScaler().fit(Xtrain)
Xtrain_std = Xstd.transform(Xtrain)
Xtest_std = Xstd.transform(Xtest)
# print('Xtrain_std:\n', Xtrain_std[:3])
# 在l2范式下,判断C和solver最优值
p = {
'C': list(np.linspace(0.05, 1, 19)),
'solver': ['liblinear', 'sag', 'newton-cg', 'lbfgs']
}
model = LR(penalty='l2', max_iter=10000)
'''
cv: 交叉验证参数,默认None,使用三折交叉验证。指定fold数量,默认为3,也可以是yield训练/测试数据的生成器。
'''
GS = GridSearchCV(model, p, cv=5)
GS.fit(Xtrain, Ytrain)
# 0.9673417721518988
print('GS.best_score_:\n', GS.best_score_)
# {'C': 0.3138888888888889, 'solver': 'newton-cg'}
print('GS.best_params_:\n', GS.best_params_)
# 注意: 除了liblinear以外的三种需要导数计算的solver不能使用l1正则化
# 将最优参数用于实例化模型,查看训练集和测试集下的分数
model = LR(penalty='l2', max_iter=10000, C=GS.best_params_['C'], solver=GS.best_params_['solver'])
model.fit(Xtrain, Ytrain)
# 0.9673366834170855
print('train score:\n', model.score(Xtrain, Ytrain))
# 0.9239766081871345
print('test score:\n', model.score(Xtest, Ytest))
第八阶段模块二
k-means
01–基础原理-拉勾教育
- 无监督算法
- k-means
python 实现
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
plt.switch_backend('TkAgg')
# %matplotlib inline
# 导入数据集
iris = pd.read_csv('iris.txt', header=None)
print('iris:\n', iris[:3])
# print(len(iris.columns))
# iris = iris.iloc[:, :len(iris.columns) - 1]
# print('iris:\n', iris[:3])
# 计算距离
def distEclud(arrA, arrB):
# d = a-b
d = arrA - arrB
# sum(d^2)
dist = np.sum(np.power(d, 2), axis=1)
return dist
# 自动生成随机质心
def randCent(dataSet, k):
n = dataSet.shape[1]
# 取每一列的最大最小值
data_max = dataSet.iloc[:,:n-1].max()
data_min = dataSet.iloc[:,:n-1].min()
# 均匀分布抽样
# numpy.random.uniform(low,high,size)
# 从一个均匀分布[low,high)中随机采样,注意定义域是左闭右开
# size: 输出样本数目,为int或元组(tuple)类型,
# 例如,size=(m,n,k), 则输出 m * n * k 个样本,缺省时输出1个值。
data_cent = np.random.uniform(data_min, data_max, (k, n-1))
return data_cent # 质心
# 随机生成3个质心
iris_cent = randCent(iris, 3)
### ERROR
def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent): # iris为150*5
m, n = dataSet.shape # m是行数(数据量),n是列数iris为150*5
# 下面生成的centroids,即第一个容器,后面用来存储最新更新的质心
centroids = createCent(dataSet, k) # centroids为3*4,用三个长度为4的一维数组记载3个质心
# 第一次centroids是随机生成的
# 这段生成的result_set,即第二个容器
# result_set结构: [数据集, 该行到最近质心的距离, 本次迭代中最近质心编号,上次迭代中最近质心编号]
clusterAssment = np.zeros((m, 3)) # clusterAssment为150*3的数组
clusterAssment[:, 0] = np.inf # np.inf为无穷大
clusterAssment[:, 1: 3] = -1 # 此时clusterAssment为150*3
result_set = pd.concat([dataSet, pd.DataFrame(clusterAssment)],
axis=1, ignore_index=True) # result_set为150*8
clusterChanged = True
while clusterChanged:
clusterChanged = False
for i in range(m): # 遍历result_set中每一行,一共m行
# 小心,下面的n为5,而resulit_set的列数已经变成8
dist = distMeas(dataSet.iloc[i, :n-1].values , centroids) # 第i行与三个质心的距离,dist为3*1
result_set.iloc[i, n] = dist.min() # result_set[i,n]记录该行与3个质心的最小距离
result_set.iloc[i, n + 1] = np.where(dist == dist.min())[0] # result_set[i,n]记录最近质心的索引
clusterChanged = not (result_set.iloc[:, -1] == result_set.iloc[:, -2]).all()
# 只要result_set最后两列不完全相等,意味着本次for循环结束时,m行所有的新质心与上次while循环留下的不完全一样
# 后果:clusterChanged为True,while继续循环
# clusterChanged为True,则需要运行下面的if语句代码块,重置第一个容器centroids和第二个容器result_set
if clusterChanged:
cent_df = result_set.groupby(n + 1).mean() # 按照列索引为n+1(质心索引)(第6列)进行分组求均值
# 即:按照最新的簇分类,计算最新3个质心的位置
centroids = cent_df.iloc[:, :n - 1].values # 重置centroids,用最新质心位置,替换上次的。3*4
result_set.iloc[:, -1] = result_set.iloc[:, -2] # result_set最后一列,本次的簇分类编码,替换掉上次的
return centroids, result_set
iris_cent, iris_result = kMeans(iris, 3)
print(iris_result.head())
sklearn 实现
from sklearn.datasets import make_blobs
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
plt.switch_backend('TkAgg')
# 自己创建数据集
X, y = make_blobs(n_samples=500, n_features=2, centers=4, random_state=1)
plt.scatter(X[:, 0], X[:, 1], marker='o') # 点的形状 ,s=8 #点的大小
# 查看分布
color = ["red", "pink", "orange", "gray"]
for i in range(4):
plt.scatter(X[y == i, 0], X[y == i, 1],
marker='o', # 点的形状
s=8, # 点的大小
c=color[i])
plt.show()
from sklearn.cluster import KMeans
cluster = KMeans(n_clusters=3, random_state=0)
cluster.fit(X)
y_pred = cluster.labels_
print('y_pred:\n', y_pred) # 该属性使用得比较多
fit_pre = KMeans(n_clusters=3, random_state=0).fit_predict(X)
print((cluster.predict(X) == fit_pre).sum())
print((fit_pre == cluster.labels_).sum())
# 当我们数据量非常大的时候,为了提高模型学习效率,我们可以使用部分数据来帮助我们确认质心
# 剩下的数据的聚类结果,使用 predict 来调用
cluster_smallsub = KMeans(n_clusters=3, random_state=0).fit(X[:200])
sample_pred = cluster_smallsub.predict(X)
# 但这样的结果,肯定与直接 fit 全部数据会不一致。
# 有时候,当我们不要求那么精确,或者我们的数据量实在太大,那我们可以使用这样的方法
print(y_pred == sample_pred)
# 查看质心
centroid = cluster.cluster_centers_
print('centroid:\n', centroid)
print('centroid.shape:\n', centroid.shape)
# 查看总距离平方和
inertia = cluster.inertia_
# 1903.5607664611764
print('inertia:\n', inertia)
n_clusters = 4
cluster_ = KMeans(n_clusters=n_clusters, random_state=0).fit(X)
inertia = cluster_.inertia_
# 908.3855684760615
print('inertia:\n', inertia)
n_clusters = 5
cluster_ = KMeans(n_clusters=n_clusters, random_state=0).fit(X)
inertia_ = cluster_.inertia_
# 811.0841324482415
print('inertia:\n', inertia_)
n_clusters = 6
cluster_ = KMeans(n_clusters=n_clusters, random_state=0).fit(X)
inertia_ = cluster_.inertia_
# 733.1538350083081
print('inertia:\n', inertia_)
评估指标: 轮廓系数
from sklearn.datasets import make_blobs
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
plt.switch_backend('TkAgg')
# 自己创建数据集
X, y = make_blobs(n_samples=500, n_features=2, centers=4, random_state=1)
plt.scatter(X[:, 0], X[:, 1], marker='o') # 点的形状 ,s=8 #点的大小
# 查看分布
color = ["red", "pink", "orange", "gray"]
for i in range(4):
plt.scatter(X[y == i, 0], X[y == i, 1],
marker='o', # 点的形状
s=8, # 点的大小
c=color[i])
plt.show()
from sklearn.cluster import KMeans
cluster = KMeans(n_clusters=3, random_state=0)
cluster.fit(X)
y_pred = cluster.labels_
print('y_pred:\n', y_pred) # 该属性使用得比较多
fit_pre = KMeans(n_clusters=3, random_state=0).fit_predict(X)
print((cluster.predict(X) == fit_pre).sum())
print((fit_pre == cluster.labels_).sum())
# 当我们数据量非常大的时候,为了提高模型学习效率,我们可以使用部分数据来帮助我们确认质心
# 剩下的数据的聚类结果,使用 predict 来调用
cluster_smallsub = KMeans(n_clusters=3, random_state=0).fit(X[:200])
sample_pred = cluster_smallsub.predict(X)
# 但这样的结果,肯定与直接 fit 全部数据会不一致。
# 有时候,当我们不要求那么精确,或者我们的数据量实在太大,那我们可以使用这样的方法
print(y_pred == sample_pred)
# 查看质心
centroid = cluster.cluster_centers_
print('centroid:\n', centroid)
print('centroid.shape:\n', centroid.shape)
# 查看总距离平方和
inertia = cluster.inertia_
# 1903.5607664611764
print('inertia:\n', inertia)
n_clusters = 4
cluster_ = KMeans(n_clusters=n_clusters, random_state=0).fit(X)
inertia = cluster_.inertia_
# 908.3855684760615
print('inertia:\n', inertia)
n_clusters = 5
cluster_ = KMeans(n_clusters=n_clusters, random_state=0).fit(X)
inertia_ = cluster_.inertia_
# 811.0841324482415
print('inertia:\n', inertia_)
n_clusters = 6
cluster_ = KMeans(n_clusters=n_clusters, random_state=0).fit(X)
inertia_ = cluster_.inertia_
# 733.1538350083081
print('inertia:\n', inertia_)
# 评估指标: 轮廓系数
from sklearn.metrics import silhouette_score, silhouette_samples
# 计算所有样本的轮廓系数的均值
score = silhouette_score(X, y_pred)
# 0.5882004012129721
print('score:\n', score)
# 每个样本的轮廓系数
samples = silhouette_samples(X, y_pred)
print('samples:\n', samples[:5])
score = []
# 将K值从2到20进行实验
for i in range(2, 20):
cluster = KMeans(n_clusters=i, random_state=0)
cluster.fit(X)
score.append(silhouette_score(X, cluster.labels_))
plt.plot(range(2, 20), score)
# 最高点的x=?画虚线
plt.axvline(pd.DataFrame(score).idxmax()[0] + 2, ls=':')
plt.show()
# 绘制轮廓系数分布图和聚类后的数据分布图来选择最佳n_clusters
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_samples, silhouette_score
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np
for i in range(2, 10, 2): # 6个质心的聚合情况,分别画在6张图
fig, (ax1, ax2) = plt.subplots(1, 2) # 每张图有两幅子图
fig.set_size_inches(18, 7) # 设置大图尺寸
# 给第一幅子图大小做限定
ax1.set_xlim([-0.1, 1])
ax1.set_ylim([0, X.shape[0] + (n_clusters + 1) * 10])
# 生成模型、簇标签、轮廓系数均值,样本轮廓系数
clusterer = KMeans(n_clusters=i, random_state=10).fit(X) # 生产KMeans模型
cluster_labels = clusterer.labels_ # 记录聚合结果的所有簇标签
silhouette_avg = silhouette_score(X, cluster_labels) # 全体样本的轮廓系数
sample_silhouette_values = silhouette_samples(X, cluster_labels) # 记录每个样本的轮廓系数
print("簇数 =", i,
"\n 轮廓系数均值:", silhouette_avg)
y_lower = 10 # 为后面画图设定一个y轴最低范围
for j in range(i):
ith_cluster_silhouette_values = sample_silhouette_values[cluster_labels == j] # 筛选留下簇j类样本的轮廓系数
ith_cluster_silhouette_values.sort() # 对上面的数组结果排序
size_cluster_j = ith_cluster_silhouette_values.shape[0] # size_cluster_i记录第i簇样本个数
# 画图
y_upper = y_lower + size_cluster_j # 第j簇在y轴的范围上限
color = cm.nipy_spectral(float(j) / i) # 第j 簇设定颜色
ax1.fill_betweenx(np.arange(y_lower, y_upper) # 图形直角在y轴上
, ith_cluster_silhouette_values # 簇j全部样本的轮廓系数,高度映射在x轴
, facecolor=color
, alpha=0.5)
ax1.text(-0.05 # 添加簇的编号
, y_lower + 0.5 * size_cluster_j
, str(j));
y_lower = y_upper + 10 # 下一簇的图显示的y轴坐标起点往上挪10个单位
ax1.set_title("不同簇的轮廓图")
ax1.set_xlabel("轮廓系数值")
ax1.set_ylabel("簇类标签")
ax1.axvline(x=silhouette_avg, color="red", linestyle="--") # 全样本的轮廓系数
ax1.set_yticks([])
ax1.set_xticks([-0.1, 0, 0.2, 0.4, 0.6, 0.8, 1])
# 接下来画出子图2的散点图
colors = cm.nipy_spectral(cluster_labels.astype(float) / i)
ax2.scatter(X[:, 0], X[:, 1], marker='o', s=8, c=colors)
centers = clusterer.cluster_centers_ # 返回不同簇的质心坐标
ax2.scatter(centers[:, 0], centers[:, 1], marker='x', c="red", s=200)
ax2.set_title("簇群数据可视化")
ax2.set_xlabel("第一特征的特征空间")
ax2.set_ylabel("第二特征的特征空间")
plt.suptitle(("样本数据的KMeans轮廓分析--簇数为:%d" % i),
fontsize=14, fontweight='bold')
plt.show()