系列文章目录
监督学习:参数方法
【学习笔记】 陈强-机器学习-Python-Ch4 线性回归
【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归
【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv)
【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归
【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析
【学习笔记】 陈强-机器学习-Python-Ch8 朴素贝叶斯
【学习笔记】 陈强-机器学习-Python-Ch9 惩罚回归
【课后题练习】 陈强-机器学习-Python-Ch9 惩罚回归(student-mat.csv)
监督学习:非参数方法
文章目录
- 系列文章目录
- 前言
- 一、K近邻法---非参数法
- 二、KNN法 Python案例
- 三、课后题
- (1)载入数据,考察其形状与前5个观测值
- (2)展示数据的统计特征,并考察响应变量diabetes的分布
- (3)根据diabetes的取值,画变量mass(body mass index)的箱形图
- (4)使用`random_state=0`,通过分层抽样,随机选择200个观测值作为测试集
- (5)将所有特征变量标准化,使得训练集的均值变为0,标准差为1
- (6)进行KNN估计(K=10)
- (7)在测试集中预测,展示混淆矩阵,并计算预测准确率
- (8)针对K=1,...,20,使用for循环,寻找使测试集预测准确率最大的K值
- (9)画图展示K与测试集预测准确率的关系
- (10)画图展示K与测试集预测 错分率的关系
- (11)画图展示1/K与测试集预测 错分率的关系
- (12)在训练集中进行10折交叉验证,选择最优K,并计算测试集预测准确率
前言
本学习笔记 仅为以防自己忘记了,顺便分享给一起学习的网友们参考。如有不同意见/建议,可以友好讨论。
本学习笔记 所有的代码和数据都可以从 陈强老师的个人主页 上下载
参考书目:陈强.机器学习及Python应用. 北京:高等教育出版社, 2021.
数学原理等 详见陈强老师的 PPT
参考了:
网友阡之尘埃的Python机器学习07——K近邻
一、K近邻法—非参数法
最简单的非参数方法(nonparametric approach)就是K近邻法(K Nearest Neighbors,简记KNN)。
现实数据大多比较稀疏,给定X ,可能只有很少y的 观测值,甚至连一个y观测值也没有。可以考虑离X最近的K个邻居。
K近邻估计量:以X最近的K之y观测值的平均作为预测值。
使用KNN法的一个前提是,所有特征变量均为数值型;否则,将无法 KNN 计算欧氏距离。
在实践中,一般可用交叉验证 选择最优的K。
对于分类问题,采取多数票规则(majority vote rule):以 K个近邻中最常见的类别作为预测。
二、KNN法 Python案例
1. 数据:breast_cancer
使用威斯康辛乳腺癌 (Wisconsin breast cancer) 的数据。此数据来自威斯康辛大学麦迪逊分校医院,包含569位病人的观测值,以及与乳腺癌诊断有关的32个变量(有关肿瘤细胞核的各种特征 )。 响应变量diagnosis取值为0=恶性肿瘤 或 1=良性肿瘤 。
import numpy as np
import pandas as pd
from sklearn.datasets import load_breast_cancer
#载入数据
cancer = load_breast_cancer()
#转为数据框
df = pd.DataFrame(cancer.data, columns=cancer.feature_names)
df['diagnosis'] = cancer.target
#用map():响应变量取值 分别映射
d = {0: 'malignant', 1: 'benign'}
df['diagnosis'] = df['diagnosis'].map(d)
df.shape
结果输出: (569, 31)
#查看y的取值分布
df.diagnosis.value_counts(normalize=True)
结果输出:
diagnosis
benign 0.627417
malignant 0.372583
Name: proportion, dtype: float64
#画y(分类)与变量'mean radius'的箱形图
import seaborn as sns
import matplotlib.pyplot as plt
sns.boxplot(x='diagnosis', y='mean radius', data=df)
笔记:seaborn.boxplot()
seaborn.boxplot 是一个用于绘制箱线图的函数,可视化数据分布的统计特性,如中位数、四分位数和异常值。
#基本语法和参数
import seaborn as sns
import matplotlib.pyplot as plt
seaborn.boxplot(
data=None, *, x=None, y=None,
hue=None, #用于指定数据中的类别变量。数据中的列名,用于在图中添加分组。可以为数据添加色彩层次,以表示不同的子类别。
order=None, #设定分类变量的顺序。控制 x 轴分类变量的显示顺序。类型: list 或 None
hue_order=None, #hue的分类顺序。控制hue变量的显示顺序。类型: list 或 None
notch=False, #是否绘制缺口箱线图,缺口箱线图显示中位数的置信区间。默认为 False。
width=0.8, #箱体的宽度,默认 0.8。
palette=None, #设置颜色调色板。
linewidth=None, #箱线图线条的宽度。
fliersize=5, #异常值标记的大小。默认 5。
meanline=False, #是否显示均值线。默认 False
showmeans=False, #是否显示均值。默认 False
showcaps=True, #是否显示箱体的端点线。默认 True,
showbox=True, #是否显示箱体。默认 True
showfliers=True, #是否显示异常值,默认为 True。
showmedians=False, #是否显示中位数线。默认 False
vert=True, #是否垂直显示箱线图,默认为 True。
ax=None, #ax: Matplotlib 的 Axes 对象,可以将图绘制到特定的轴上。
**kwargs) #其他关键字参数,可以传递给底层的 matplotlib 绘图函数。
2. 处理变量
#在加载数据集时同时返回特征数据 (X) 和目标数据 (y)。
X, y = load_breast_cancer(return_X_y=True)
#全样本分组
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
X, y, stratify=y, test_size=100, random_state=1)
#标准化
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit(X_train)
X_train_s = scaler.transform(X_train)
X_test_s = scaler.transform(X_test)
#检验标准化的均值&标准差
print('训练集的均值',np.mean(X_train_s, axis=0)) #应该=0
print('训练集的标准差',np.std(X_train_s, axis=0)) #应该=1
print('测试集的均值',np.mean(X_test_s, axis=0))
print('测试集的标准差',np.std(X_test_s, axis=0))
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/c5d93bae016846a5adbf06c3dccedd56.png3
3. 进行K=5的KNN估计
#进行K=5的KNN估计
from sklearn.neighbors import KNeighborsClassifier #分类的KNN
model = KNeighborsClassifier(n_neighbors=5) #在预测时考虑最近的5个邻居(neighbors)。
model.fit(X_train_s, y_train) #拟合
#预测
pred = model.predict(X_test_s)
#计算混淆矩阵
pd.crosstab(y_test, pred,
rownames=['Actual'],
colnames=['Predicted'])
#用测试数据评估模型:准确率
model.score(X_test_s, y_test)
结果输出:
0.97 预测准确率为97%
笔记:KNeighborsClassifier ()
KNeighborsClassifier 是 Scikit-Learn 中用于 K-最近邻分类的一个类。K-最近邻分类器通过计算测试样本与训练集中所有样本之间的距离,选择距离最近的 k 个训练样本,根据这 k 个邻居的标签来进行预测。常用的距离度量方法包括欧氏距离、曼哈顿距离等。
#基本语法和参数
from sklearn.neighbors import KNeighborsClassifier
KNeighborsClassifier(
n_neighbors=5, #选择的邻居数目,默认为 5。
weights='uniform', #权重函数,默认为 'uniform'。'uniform' 表示所有邻居的权重相同,'distance' 表示距离越近的邻居权重越大。
algorithm='auto', #用于计算最近邻的算法。algorithm: {'auto', 'ball_tree', 'kd_tree', 'brute'}。'auto' 选择最适合的算法,'ball_tree' 使用 Ball Tree,'kd_tree' 使用 KD Tree,'brute' 使用暴力搜索。
p=2, #距离度量的参数,默认为 2。p=1 使用曼哈顿距离,p=2 使用欧氏距离。
metric='minkowski', #距离度量函数,默认为 'minkowski'。可以使用其他度量方法:'euclidean' 或 'manhattan',或传入自定义距离函数。
n_jobs=None) #并行计算的作业数,默认为 None。设置为 -1 使用所有可用的核心进行计算。
K-最近邻分类器适用于:
· 小规模数据集:因为它需要存储所有训练样本,计算开销较大。
· 不需要显式训练的情况:KNN 是一种懒惰学习算法,没有显式的训练过程,只在预测时才进行计算。
优点:
√ 简单易懂,易于实现和解释。
√ 不需要训练过程,适应性强。
缺点:
× 在大数据集上计算成本高,尤其是当 k 较大时。
× 对数据噪声敏感,可能需要额外的预处理步骤来提高性能。
4.手动(for循环)寻找最优的K
#手动寻找最优的K
scores = []
ks = range(1, 51) #定义一个范围对象 ks,包含从 1 到 50 的整数。
for k in ks:
model = KNeighborsClassifier(n_neighbors=k)
model.fit(X_train_s, y_train)
score = model.score(X_test_s, y_test)
scores.append(score)
print('准确率的最大值:',max(scores)) #预测准确率的最大值
index_max = np.argmax(scores) #找“准确率的最大值”的索引位置
print(index_max) #最佳准确率对应的 k 值在 ks 中的索引位置。
print(f'Optimal K: {ks[index_max]}') #最优的K
结果输出: 准确率的最大值: 0.97
2
Optimal K: 3
1) 画出 准确率与K 的关系图
#画出 准确率与K 的关系图
plt.plot(ks, scores, 'o-') #'o-' 表示数据点将以圆圈标记(o),并用实线连接(-)。
plt.xlabel('K')
plt.axvline(ks[index_max], linewidth=1, linestyle='--', color='k')
plt.ylabel('Accuracy')
plt.title('KNN:K v.s. accuracy')
plt.tight_layout()
由上图可知,由多个K值的准确率并列最大值(97%)。
2) 画出 错误率与K 的关系图
#画不同k的错误率
errors = 1 - np.array(scores)
plt.plot(ks, errors, 'o-')
plt.xlabel('K')
plt.axvline(ks[index_max], linewidth=1, linestyle='--', color='k')
plt.ylabel('Error Rate')
plt.title('KNN:k v.s error')
plt.tight_layout()
3) 用1/k度量KNN模型复杂度
#用1/k度量KNN模型复杂度
errors = 1 - np.array(scores)
ks_inverse = 1 / np.array(ks)
plt.plot(ks_inverse, errors, 'o-')
plt.xlabel('1/K')
plt.ylabel('Error Rate')
plt.title('KNN: 1/k v.s errors')
plt.tight_layout()
用1/k作为模型复杂度度量,错误率呈现U型曲线
5.10折交叉验证法选择最优K
#10折交叉验证选择最优超参数K
from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import GridSearchCV
#定义K的网格
param_grid = {'n_neighbors': range(1, 51)}
#定义10折分层随机分组
kfold = StratifiedKFold(n_splits=10, shuffle=True, random_state=1)
#进行交叉验证
model = GridSearchCV(KNeighborsClassifier(), param_grid, cv=kfold)
model.fit(X_train_s, y_train)
#得到 最优参数K
print(model.best_params_)
#准确率
model.score(X_test_s, y_test)
结果输出: {‘n_neighbors’: 12} 最优K=12
0.96 K=12时,测试集的预测准确率96%(< 97%)
三、课后题
UCI Machine Learnig Repository的印第安纳糖尿病数据 PimaIndianasDiabetes.csv,响应变量为diabetes(取值pos或neg,表示是否有糖尿病),其余8个特征变量均为数值型。
(1)载入数据,考察其形状与前5个观测值
import numpy as np
import pandas as pd
#读取CSV文件的路径
csv_path = r'D:\桌面文件\Python\【陈强-机器学习】MLPython-PPT-PDF\MLPython_Data\PimaIndiansDiabetes.csv'
Diabetes = pd.read_csv(csv_path)
print(Diabetes.shape)
Diabetes.head()
结果输出: (768, 9)
(2)展示数据的统计特征,并考察响应变量diabetes的分布
Diabetes.describe()
#查看y的取值分布
print(Diabetes.diabetes.value_counts(normalize=True))
结果输出:
diabetes
neg 0.651042
pos 0.348958
Name: proportion, dtype: float64
(3)根据diabetes的取值,画变量mass(body mass index)的箱形图
#画y(分类)的箱型图
import seaborn as sns
import matplotlib.pyplot as plt
sns.boxplot(x='diabetes', y='mass',
data=Diabetes,
palette="Set2",
notch=True)
(4)使用random_state=0
,通过分层抽样,随机选择200个观测值作为测试集
#特征数据 (X) 和目标数据 (y)。
X = Diabetes.drop('diabetes', axis=1)
y = Diabetes['diabetes']
#全样本分组
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
X, y, stratify=y, test_size=200, random_state=0)
(5)将所有特征变量标准化,使得训练集的均值变为0,标准差为1
#标准化
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit(X_train)
X_train_s = scaler.transform(X_train)
X_test_s = scaler.transform(X_test)
#检验标准化的均值&标准差
print('训练集的均值',np.mean(X_train_s, axis=0))
print('训练集的标准差',np.std(X_train_s, axis=0))
print('测试集的均值',np.mean(X_test_s, axis=0))
print('测试集的标准差',np.std(X_test_s, axis=0))
结果输出: 训练集的均值 [ 2.81464992e-17 -3.12738880e-17 3.42058150e-16 1.00076442e-16
-1.25095552e-17 -1.23531858e-16 7.19299424e-17 -2.25171994e-16]
训练集的标准差 [1. 1. 1. 1. 1. 1. 1. 1.]
测试集的均值 [-0.15863673 -0.02582328 -0.05719617 0.05870488 0.21886311 0.01932983
0.01403775 -0.13609468]
测试集的标准差 [0.94154255 1.03549433 1.03518333 0.87786465 1.05631569 1.10852183
0.91401169 0.93400616]
(6)进行KNN估计(K=10)
#KNN分类
from sklearn.neighbors import KNeighborsClassifier
model = KNeighborsClassifier(n_neighbors=10)
model.fit(X_train_s, y_train)
(7)在测试集中预测,展示混淆矩阵,并计算预测准确率
#预测
pred = model.predict(X_test_s)
#计算混淆矩阵
pd.crosstab(y_test, pred,
rownames=['Actual'],
colnames=['Predicted'])
#测试集准确率
print(model.score(X_test_s, y_test))
结果输出:
0.715
(8)针对K=1,…,20,使用for循环,寻找使测试集预测准确率最大的K值
#手动寻找最优的K
scores = []
ks = range(1, 21)
for k in ks:
model = KNeighborsClassifier(n_neighbors=k)
model.fit(X_train_s, y_train)
score = model.score(X_test_s, y_test)
scores.append(score)
print('准确率的最大值:',max(scores)) #预测准确率的最大值
index_max = np.argmax(scores) #找“准确率的最大值”的索引位置
print(index_max)
print(f'Optimal K: {ks[index_max]}') #最优的K
结果输出: 准确率的最大值: 0.775
16
Optimal K: 17
(9)画图展示K与测试集预测准确率的关系
#画出 准确率与K 的关系图
plt.plot(ks, scores, 'o-')
plt.xlabel('K')
plt.axhline(max(scores), linewidth=1, linestyle='--', color='r')
plt.axvline(ks[index_max], linewidth=1, linestyle='--', color='k')
plt.ylabel('Accuracy')
plt.title('KNN:K v.s. accuracy')
plt.tight_layout()
(10)画图展示K与测试集预测 错分率的关系
#画不同k的错误率
errors = 1 - np.array(scores)
plt.plot(ks, errors, 'o-')
plt.xlabel('K')
plt.axhline(min(errors), linewidth=1, linestyle='--', color='r')
plt.axvline(ks[index_max], linewidth=1, linestyle='--', color='k')
plt.ylabel('Error Rate')
plt.title('KNN:k v.s error')
plt.tight_layout()
(11)画图展示1/K与测试集预测 错分率的关系
#用1/k度量KNN模型复杂度
errors = 1 - np.array(scores)
ks_inverse = 1 / np.array(ks)
plt.plot(ks_inverse, errors, 'o-')
plt.xlabel('1/K')
plt.ylabel('Error Rate')
plt.title('KNN: 1/k v.s errors')
plt.tight_layout()
(12)在训练集中进行10折交叉验证,选择最优K,并计算测试集预测准确率
#10折交叉验证选择最优超参数K
from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import GridSearchCV
param_grid = {'n_neighbors': range(1, 21)}
kfold = StratifiedKFold(n_splits=10, shuffle=True, random_state=1)
model = GridSearchCV(KNeighborsClassifier(), param_grid, cv=kfold)
model.fit(X_train_s, y_train)
#最优K
print(model.best_params_)
#最优K时的准确率
model.score(X_test_s, y_test)
结果输出: {‘n_neighbors’: 17}
0.775