sklearn机器学习概述
使用scikit-learn
的基本步骤通常包括:
- 数据准备:加载数据、数据清洗和特征工程。
- 模型选择:选择一个或多个机器学习模型。
- 模型训练:使用训练数据集训练模型。
- 模型评估:使用测试数据集评估模型性能。
- 模型优化:调整模型参数,进行交叉验证。
- 模型部署:将训练好的模型部署到生产环境中。
KNN算法-分类
KNN算法的核心思想是,一个样本的类别可以由其最近邻的样本决定。在分类问题中,KNN算法会根据训练集中的最近邻样本的类别,通过多数投票的方式来预测新样本的类别
KNN算法的工作原理:
-
距离度量:首先,KNN算法需要一个距离度量来计算样本之间的距离,常见的距离度量包括欧氏距离、曼哈顿距离和闵可夫斯基距离等。
-
寻找最近邻:对于一个新的样本点,KNN算法会在训练集中寻找与其距离最近的K个样本点。
-
多数投票:在分类问题中,KNN算法会根据这K个最近邻样本的类别进行多数投票,即选择出现次数最多的类别作为新样本的预测类别。
-
权重投票:在某些变体中,最近邻的类别可能会根据其距离的远近有不同的权重,距离越近的样本点对预测结果的影响越大。
缺点:
- KNN是一种基于实例的学习算法,它不需要显式的训练阶段。模型的训练实际上就是存储训练数据集。
- KNN属于惰性学习方法,它在训练阶段不进行模型学习,而是将学习推迟到预测阶段。
- 算法的核心是基于距离的度量,通常使用欧氏距离,但也可以使用其他距离度量。
- 在分类问题中,KNN使用多数投票机制来确定新样本的类别。
- K值的选择对算法的性能有重要影响,需要根据具体问题进行调整。
- KNN是一种非参数方法,它不假设数据的分布,也不对数据进行任何参数化的形式化。
- KNN算法易于理解和实现,不需要复杂的数学背景。
- 与其他需要假设数据分布的算法不同,KNN不对数据的分布做出任何假设。
- 由于KNN依赖于距离度量,因此对特征的缩放非常敏感。不同量纲的特征需要进行适当的缩放。
- 虽然KNN通常用于分类问题,但它也可以通过计算最近邻的平均值来用于回归问题。
- 在预测阶段,KNN需要计算待预测样本与所有训练样本之间的距离,这可能导致较高的计算成本。
- KNN需要存储整个训练数据集,这可能导致较高的存储成本。
优点:
- 简单易懂,无需训练阶段。
- 可用于非线性数据。
- 可用于多分类问题。
- 可用于回归问题。
API
from sklearn.neighbors import KNeighborsClassifier
KNeighborsClassifier()
构造函数参数:
n_neighbors
: int, 默认值为5。指定用于kneighbors查询的邻居数量。weights
: {‘uniform’, ‘distance’}, callable或None, 默认为‘uniform’。用于预测的权重函数。‘uniform’表示所有邻居的权重相同,‘distance’表示权重与距离成反比。algorithm
: {‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’}, 默认为‘auto’。用于计算最近邻居的算法。‘ball_tree’和‘kd_tree’分别使用球树和KD树,‘brute’使用暴力搜索。leaf_size
: int, 默认值为30。传递给BallTree或KDTree的叶大小。这会影响构建和查询的速度,以及存储树所需的内存。p
: int, 默认值为2。与metric
参数一起使用,是Minkowski距离中的指数参数。默认情况下,这等同于欧几里得距离。metric
: str或callable, 默认为‘minkowski’。用于计算距离的度量。metric_params
: dict, 默认为None。传递给度量函数的额外关键字参数。n_jobs
: int, 默认为None。并行运行的任务数。None意味着1,除非在全局并行上下文中设置了不同的值。
鸢尾花示例:
# 导入要使用的库
from sklearn.datasets import load_iris
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import StandardScaler
iris = load_iris()
# 查看键
print(iris.keys())
'''
dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename', 'data_module'])
'''
from sklearn.model_selection import train_test_split
#鸢尾花load_iris已经将data和target分好了,直接使用即可
#得到训练集和测试集
x_train,x_test,y_train,y_test = train_test_split(iris.data,iris.target, test_size=0.1,random_state=22)
#创建StandardScaler实例
transfer = StandardScaler()
#使用fit计算均值和标准差
transfer.fit(x_train)
#使用transform将数据标准化
x_train = transfer.transform(x_train)
x_test = transfer.transform(x_test)
#创建KNeighborsClassifier 实例
knn = KNeighborsClassifier(n_neighbors=11)
#使用fit训练模型
knn.fit(x_train,y_train)
#评估模型
print(knn.score(x_test,y_test))
'''
1.0
'''
模型保存与加载
import joblib
#保存模型
joblib.dump(knn, 'knn.pkl')
# 加载模型
estimator = joblib.load("knn.pkl")
#使用模型预测
y_test = estimator.predict([[0.4, 0.2, 0.4, 0.7]])
print(y_test)
模型选择与调优
交叉验证
-
保留交叉验证HoldOut
上面使用的训练集和测试集
x_train,x_test,y_train,y_test -
K-折交叉验证(K-Fold Cross-Validation):
- 将数据集随机分成K个大小相等的子集。
- 进行K次训练和验证,每次选择不同的子集作为验证集,其余K-1个子集合并作为训练集。
- 最终的性能评估通常是基于K次验证结果的平均值。
-
分层K-折交叉验证(Stratified K-Fold Cross-Validation):
- 与K-折交叉验证类似,但确保每个折中各类别的比例与原始数据集中的相同,适用于类别不平衡的数据集。
-
留一交叉验证(Leave-One-Out Cross-Validation, LOOCV):
- 每次只留下一个样本作为验证集,其余所有样本作为训练集。
- 这种方法计算成本较高,但特别适合于小数据集。
-
自助采样(Bootstrap):
- 通过有放回地随机抽样来创建多个训练集和验证集。
- 这种方法不需要预先分割数据集,但可能会导致一些样本在训练过程中从未被使用。
StratifiedKFold
的一些关键参数和用法:
参数:
n_splits
: int, 默认值为5。指定要将数据集分割成多少个子集(折)。shuffle
: bool, 默认值为False。指定在分割之前是否对每个类别的样本进行打乱。random_state
: int, RandomState实例或None, 默认值为None。当shuffle
为True时,random_state
会影响索引的顺序,从而控制每个类别的每个折的随机性。
方法:
get_n_splits(X, y)
: 返回交叉验证器中的分割迭代次数。split(X, y)
: 生成索引以将数据分为训练集和测试集。
from sklearn.datasets import load_wine
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import StandardScaler
#观察wine数据
wine = load_wine()
print(wine.keys())
print(wine.target_names)
print(wine.data.shape)
...
dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names'])
['class_0' 'class_1' 'class_2']
(178, 13)
...
from sklearn.model_selection import StratifiedKFold
x = wine.data
y = wine.target
#StratifiedKFold编写一个迭代器
strat_k_fold = StratifiedKFold(n_splits=10, random_state=7, shuffle=True)
index = strat_k_fold.split(x, y)
#创建一个knn实例
knn = KNeighborsClassifier(n_neighbors=7)
#得到下标进行迭代
for train_index, test_index in index:
# 通过下标得到训练集和测试集
x_train, x_test = x[train_index], x[test_index]
y_train, y_test = y[train_index], y[test_index]
#标准化数据
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(x_train)
X_test_scaled = scaler.transform(x_test)
#训练模型
knn.fit(X_train_scaled, y_train)
#评估模型
score = knn.score(X_test_scaled, y_test)
print(score)
超参数搜索
又叫网格搜索,在模型训练之前设置的参数,用于控制学习过程,如学习率、迭代次数等。
API
from sklearn.model_selection import GridSearchCV
GridSearchCV(estimator, param_grid)
构造函数参数:
estimator
: 要优化的估计器(模型)。param_grid
: 一个字典,键是估计器的参数名,值是对应的参数值列表。GridSearchCV
将遍历所有参数值的组合。
重要参数:
cv
: 交叉验证的折数或交叉验证分割策略,用于评估每个超参数组合的性能。scoring
: 用于评估模型性能的评分函数或指标。n_jobs
: 并行运行的任务数。默认情况下,n_jobs=1
表示串行运行。如果设置为-1
,则使用所有可用的CPU核心。verbose
: 控制日志的详细程度。数字越大,输出的日志越详细。fit_params
: 传递给fit
方法的附加参数。pre_dispatch
: 控制并行运行时的调度行为。
方法:
fit(X, y=None, groups=None, **fit_params)
: 运行网格搜索以优化超参数。score(X, y=None)
: 返回最佳估计器在给定数据上的分数。predict(X)
: 使用最佳估计器对数据进行预测。best_estimator_
: 返回训练后的最佳估计器。best_params_
: 返回最佳估计器的参数。best_score_
: 返回最佳估计器的分数。
from sklearn.datasets import load_breast_cancer
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
#读取乳腺癌数据集
data = load_breast_cancer()
x_train, x_test, y_train, y_test = train_test_split(data['data'], data['target'], random_state=0)
#标准化
tranfer = StandardScaler()
x_train = tranfer.fit_transform(x_train)
x_test = tranfer.transform(x_test)
#创建实例
knn = KNeighborsClassifier()
knn = GridSearchCV(knn, {'n_neighbors': [4,8,10,12]}, cv=5)
knn.fit(x_train, y_train)
#输出最好的分数和对应参数
print(knn.best_score_)
print(knn.best_params_)
'''
0.9648700410396718
{'n_neighbors': 12}
'''
作业
手搓TfidfVectorizer TF-IDF(文本特征词的重要程度特征提取)
要求最后输出和最后一行的数组一样
# re=math.log10(4)
# print(re)
import numpy as np
data = ['世界 你好 我 是 华清 远见 的 张 三', '你好 世界 我 是 李四 世界', '华清 远见 666']
# 作业 实现一个函数
# ['666' '世界' '你好' '华清' '李四' '远见']
# data_=mytool(data)#[[0.8,0.7,0.6,0.5,0.4,0.3],[0.2,0.3,0.4,0.5,0.6,0.7],[0.3,0.4,0.5,0.6,0.7,0.8]]
# 分词并创建词汇表
vocabulary = []
for document in data:
words = document.split()
for word in words:
if len(word) > 1 and word not in vocabulary:
vocabulary.append(word)
# print(vocabulary)
num = []
shape1 = shape2 = 0
for d in data:
shape1 += 1
shape2 = 0
arr = []
for w in vocabulary:
shape2 += 1
count = 0
if w in d:
count += 1
arr.append(w)
num = num + [count]
num = np.array(num)
num = num.reshape(shape1, shape2)
Nt = np.sum(num, axis=0)
Nt += 1
N = np.full_like(Nt, 3)
# 获得IDF
IDF = np.log10(Nt / N)
# print(IDF)
def len_num(data):
len_arr = []
for i in data:
len = 0
itme = i.split()
for j in itme:
len += 1
len_arr.append(len)
return len_arr
len_arr = len_num(data)
len_arr = np.array(len_arr)
# print(len_arr)
arrr = []
for i in vocabulary:
cuont = 0
for j in data:
numm = 0
itme = j.split()
for k in itme:
if i == k:
numm += 1
arrr.append(numm / len_arr[cuont])
cuont += 1
arrr1 = [i for i in arrr[::3]]
arrr2 = [i for i in arrr[1::3]]
arrr3 = [i for i in arrr[2::3]]
arrrr = [arrr1, arrr2, arrr3]
# TF
TF = np.array(arrrr)
# print(TF)
# TF-IDF
TF_IDF = np.dot(TF, TF.T)
print(TF_IDF)
['世界', '你好', '华清', '远见', '李四', '666']
[[0.04938272 0.05555556 0.07407407]
[0.05555556 0.16666667 0. ]
[0.07407407 0. 0.33333333]]