数据集划分
- 训练集:帮助我们训练模型,简单的说就是通过训练集的数据让我们确定拟合曲线的参数。
- 验证集:也叫开发集,用来做模型的选择,即模型的最终优化及确定,用来辅助我们的模型的构建,即训练超参数,可选
- 测试集:为测试已经训练好的模型的精确度。
- 数据不平衡的处理:数据不平衡是指数据集中各类样本数量不均衡的情况,常用的处理方法有采用和代价敏感学习
- 代价敏感学习:代价敏感学习是指为不同类别的样本提供不同的权重,从而让机器学习模型进行学习的一种方法
评价指标
正则化、偏差和方差
-
为什么要进行标准化和归一化
提升模型精度:不同维度之间的特征在数值上有一定的比较性,可以大大提高分类的准确性。
**加速模型收敛:**最优解的寻优过程明显会变得平缓,更容易正确的收敛到最优解。 -
归一化(最大-最小规范化)
x ∗ = x − x m i n x m a x − x m i n x^{*}=\frac{x-x_{min}}{x_{max}-x_{min}} x∗=xmax−xminx−xmin
将数据映射到区间[0,1]之间,数据归一化的目的是使得各个特征对目标变量的影响一致,会将特征数据进行伸缩变化,所以数据归一化是会改变数据特征分布的 -
Z-Score标准化
x ∗ = x − μ σ x^{*}=\frac{x-\mu}{\sigma} x∗=σx−μ,其中 σ 2 = 1 m ∑ i = 1 m ( x ( i ) − μ ) 2 \sigma^{2}=\frac{1}{m}\sum^{m}_{i=1}(x^{(i)}-\mu)^{2} σ2=m1∑i=1m(x(i)−μ)2, μ = 1 m ∑ i = 1 m x ( i ) \mu=\frac{1}{m}\sum^{m}_{i=1}x^{(i)} μ=m1∑i=1mx(i),处理后的数据均值为0,方差为1
数据标准化为了不同特征之间具备可比性,经过标准化变换之后的特征数据分布没有发生改变 -
就是当数据特征取值范围或单位差异较大时,最好是做一下标准化处理。
-
需要做数据归一化/标准化的模型有:
线性模型,如基于距离度量的模型包括KNN(K近邻)、K-means聚类、
感知机和SVM、神经网络。另外,线性回归类的几个模型一般情况下也
是需要做数据归一化/标准化处理的。 -
不需要做数据归一化/标准化的模型:
决策树、基于决策树的Boosting和Bagging等集成学习模型对于特征取
值大小并不敏感,如随机森林、XGBoost、LightGBM等树模型,以及
朴素贝叶斯,以上这些模型一般不需要做数据归一化/标准化处理 -
过拟合和欠拟合
过拟合的处理方法
- 获得更多的训练数据
使用更多的训练数据是解决过拟合问题的最有效的手段,因为样本更多的样本能够让模型学习到更多的有效特征,减小噪声的影响。
降维:
即丢弃一些不能帮助我们正确预测的特征。可以是手工选择保留那些特征,或者使用一些模型选择的算法来帮忙(例如pca)
正则化:
正则化技术保留所有的特征,但是减少参数的大小,它可以改善或者减少过拟合的问题
集成学习方法:
集成学习是把多个模型集成在一起,来降低单一模型的过拟合风险。
欠拟合的处理
- 1、添加新的特征:当特征不足或者表现有特征与样本标签的相关性不强时,模型容易出现欠拟合。通过挖掘组合特征等新的特征,往往能够取得更好的效果
- 2.增加模型复杂度
简单模型的学习能力较差,通过增加模型的复杂度可以使模型拥有更强的拟合能力。例如,在线性模型中添加高次项,在神经网络模型中增加网络层数或神经元个数等。 - 3.减小正则化系数
正则化是用来防止过拟合的,但当模型出现欠拟合现象时,则需要有针对性地减小正则化系数。
正则化
偏差和方差
- 方差Variance:
描述的是预测值的变化范围,离散程度,也就是离其期望值的距离。**方差越大,数据的分布越分散,**如下图列所示
- 偏差Bias:
描述的是预测值(估计值)的期望与真实值之间的差距。偏差越大,越偏离真实数据,如下图所示。
实践代码
# -*- coding: utf-8 -*-
"""
=========================
@Time : 2021/12/28 15:07
@Author : yhz
@File : machinelearning.py
=========================
"""
# 机器学习联系
# 1.基本用例:训练和测试分类器
# 对于第一个示例,我们将在数据集上训练和测试一个分类器。 我们将使用此示例来回忆scikit-learn的API。
# 我们将使用digits数据集,这是一个手写数字的数据集。
from matplotlib import pyplot as plt
from sklearn.datasets import load_digits
# 加载数据
X, y = load_digits(return_X_y=True)
# print(X, y)
# print(X.shape)
# X中的每行包含64个图像像素的强度。 对于X中的每个样本,我们得到表示所写数字对应的y。
# 画出图片
print(X[0].reshape(8, 8))
plt.imshow(X[0].reshape(8, 8), cmap='Blues_r')
plt.axis('off')
print("the digit in the image is {}".format(y[0]))
plt.show()
# 在机器学习中,我们应该通过在不同的数据集上进行训练和测试来评估我们的模型。
# train_test_split 是一个用于将数据拆分为两个独立数据集的效用函数。
# stratify参数可强制将训练和测试数据集的类分布与整个数据集的类分布相同。
# y表示标签
print(y)
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=0.25, random_state=42)
# 划分数据为训练集与测试集,添加stratify参数,以使得训练和测试数据集的类分布与整个数据集的类分布相同。
# 一旦我们拥有独立的培训和测试集,我们就可以使用fit方法学习机器学习模型。 我们将使用score方法来测试此方法,
# 依赖于默认的准确度指标。
from sklearn.linear_model import LogisticRegression
# 导入逻辑回归算法
clf = LogisticRegression(solver='lbfgs', multi_class="ovr", max_iter=5000, random_state=42)
clf.fit(X_train, y_train)
accuracy = clf.score(X_test, y_test)
# print(' LogisticRegression Accuracy score of the {} is {:.4f}'.format(clf.__class__.__name__,accuracy))
# scikit-learn的API在分类器中是一致的。
# 因此,我们可以通过RandomForestClassifier轻松替换LogisticRegression分类器。
# 这些更改很小,仅与分类器实例的创建有关
# 导入随机森林分类器
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(n_estimators=1000, n_jobs=-1, random_state=42)
clf.fit(X_train, y_train)
accuracy = clf.score(X_test, y_test)
# print(' RandomForestClassifier Accuracy score of the {} is {:.2f}'.format(clf.__class__.__name__, accuracy))
from xgboost import XGBClassifier
clf = XGBClassifier(n_estimators=1000)
clf.fit(X_train, y_train)
accuracy = clf.score(X_test, y_test)
print('XGBClassifier Accuracy score of the {} is {:.2f}'.format(clf.__class__.__name__, accuracy))
from sklearn.ensemble import GradientBoostingClassifier
clf = GradientBoostingClassifier(n_estimators=100, random_state=0)
clf.fit(X_train, y_train)
accuracy = clf.score(X_test, y_test)
print('Accuracy score of the {} is {:.2f}'.format(clf.__class__.__name__,
accuracy))
from sklearn.metrics import balanced_accuracy_score
y_pred = clf.predict(X_test)
accuracy = balanced_accuracy_score(y_pred, y_test)
print('Accuracy score of the {} is {:.2f}'.format(clf.__class__.__name__,
accuracy))
from sklearn.svm import SVC, LinearSVC
clf = SVC()
clf.fit(X_train, y_train)
accuracy = clf.score(X_test, y_test)
print('Accuracy score of the {} is {:.2f}'.format(clf.__class__.__name__,
accuracy))
clf = LinearSVC()
clf.fit(X_train, y_train)
accuracy = clf.score(X_test, y_test)
print('Accuracy score of the {} is {:.2f}'.format(clf.__class__.__name__,
accuracy))
# 在学习模型之前可能需要预处理。例如,一个用户可能对创建手工制作的特征或者算法感兴趣,
# 那么他可能会对数据进行一些先验假设。
# 在我们的例子中,线性模型使用的求解器期望数据被规范化。因此,我们需要在训练模型之前标准化数据。
# 为了观察这个必要条件,我们将检查训练模型所需的迭代次数。
# MinMaxScaler变换器用于归一化数据,StandardScaler用于标准化数据。该标量应该以下列方式应用:
# 学习(即,fit方法)训练集上的统计数据并标准化(即,transform方法)训练集和测试集。
# 最后,我们将训练和测试这个模型并得到归一化后的数据集
from sklearn.preprocessing import MinMaxScaler, StandardScaler
# 归一化MinMaxScaler的对象
scaler = MinMaxScaler()
# X_train和X_test进行归一化
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
# 定义一个线性的svm
clf = LinearSVC()
# 拿训练集和训练标签进行训练
clf.fit(X_train_scaled, y_train)
# 训练完成后,利用测试集和测试标签进行测算精确度
accuracy = clf.score(X_test_scaled, y_test)
print('Accuracy score of the {} is {:.2f}'.format(clf.__class__.__name__,
accuracy))
# 标准化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
clf = LinearSVC()
clf.fit(X_train_scaled, y_train)
accuracy = clf.score(X_test_scaled, y_test)
print('Accuracy score of the {} is {:.2f}'.format(clf.__class__.__name__,
accuracy))
# 训练完成后进行预测
from sklearn.metrics import confusion_matrix, classification_report
# 利用测试集进行预测
y_pred = clf.predict(X_test_scaled)
print(confusion_matrix(y_pred, y_test))
import pandas as pd
pd.DataFrame(
(confusion_matrix(y_pred, y_test)),
columns=range(10),
index=range(10))
print(classification_report(y_pred, y_test))
# 交叉验证
# 分割数据对于评估统计模型性能是必要的。 但是,它减少了可用于学习模型的样本数量。 因此,应尽可能使用交叉验证。
# 有多个拆分也会提供有关模型稳定性的信息。
# scikit-learn提供了三个函数:cross_val_score,cross_val_predict和cross_validate。
# 后者提供了有关拟合时间,训练和测试分数的更多信息。 我也可以一次返回多个分数。
# 交叉验证
from sklearn.model_selection import cross_validate
# 逻辑回归
clf = LogisticRegression(solver='lbfgs', multi_class='auto', max_iter=1000, random_state=42)
scores = cross_validate(clf, X_train_scaled, y_train, cv=3, return_train_score=True)
print(clf.get_params())
import pandas as pd
df_scores = pd.DataFrame(scores)
print(df_scores)
# 网格搜索调参
# 可以通过穷举搜索来优化超参数。GridSearchCV提供此类实用程序,并通过参数网格进行交叉验证的网格搜索。
# 如下例子,我们希望优化LogisticRegression分类器的C和penalty参数。
from sklearn.model_selection import GridSearchCV
clf = LogisticRegression(solver='saga', multi_class='auto', random_state=42, max_iter=5000)
param_grid = {'logisticregression__C': [0.01, 0.1, 1],
'logisticregression__penalty': ['l2', 'l1']}
tuned_parameters = [{
'C': [0.01, 0.1, 1, 10],
'penalty': ['l2', 'l1'],
}]
grid = GridSearchCV(
clf, tuned_parameters, cv=3, n_jobs=-1, return_train_score=True)
print(grid.fit(X_train_scaled, y_train))
print(grid.get_params())
df_grid = pd.DataFrame(grid.cv_results_)
print(df_grid)
# 流水线操作
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import make_pipeline
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import cross_validate
X = X_train
y = y_train
# 创建一个管道
pipe = make_pipeline(
MinMaxScaler(),
LogisticRegression(
solver='saga', multi_class='auto', random_state=42, max_iter=5000))
param_grid = {
'logisticregression__C': [0.1, 1.0, 10],
'logisticregression__penalty': ['l2', 'l1']
}
grid = GridSearchCV(pipe, param_grid=param_grid, cv=3, n_jobs=-1)
scores = pd.DataFrame(
cross_validate(grid, X, y, cv=3, n_jobs=-1, return_train_score=True))
scores[['train_score', 'test_score']].boxplot()
# 管道预测
pipe.fit(X_train, y_train)
accuracy = pipe.score(X_test, y_test)
print('Accuracy score of the {} is {:.2f}'.format(pipe.__class__.__name__, accuracy))
print(pipe.get_params())
# 练习 异构数据:当您使用数字以外的数据时
import os
data = pd.read_csv('G:\python\AiMLDL\Machinelearning\data\\titanic_openml.csv', na_values='?')
print(data.head())
y = data['survived']
X = data.drop(columns='survived')
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
clf = LogisticRegression()
# clf.fit(X_train, y_train)#这里肯定会报错。
# 大多数分类器都设计用于处理数值数据。 因此,我们需要将分类数据转换为数字特征。
# 最简单的方法是使用OneHotEncoder对每个分类特征进行读 让热编码。
# 我们以sex与embarked列为例。 请注意,我们还会遇到一些缺失的数据。 我们将使用SimpleImputer用常量值替换缺失值
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder
# 使用常量区填充缺失值
ohe = make_pipeline(SimpleImputer(strategy='constant'), OneHotEncoder())
X_encoded = ohe.fit_transform(X_train[['sex', 'embarked']])
X_encoded.toarray()
# 这样,可以对分类特征进行编码。 但是,我们也希望标准化数字特征。
# 因此,我们需要将原始数据分成2个子组并应用不同的预处理:
# (i)分类数据的独热编;(ii)数值数据的标准缩放(归一化)。
# 我们还需要处理两种情况下的缺失值: 对于分类列,我们将字符串'missing_values'替换为缺失值,
# 该字符串将自行解释为类别。 对于数值数据,我们将用感兴趣的特征的平均值替换缺失的数据。
col_cat = ['sex', 'embarked']
col_num = ['age', 'sibsp', 'parch', 'fare']
X_train_cat = X_train[col_cat]
X_train_num = X_train[col_num]
X_test_cat = X_test[col_cat]
X_test_num = X_test[col_num]
from sklearn.preprocessing import StandardScaler
scaler_cat = make_pipeline(SimpleImputer(strategy='constant'), OneHotEncoder())
X_train_cat_enc = scaler_cat.fit_transform(X_train_cat)
X_test_cat_enc = scaler_cat.transform(X_test_cat)
scaler_num = make_pipeline(SimpleImputer(strategy='mean'), StandardScaler())
X_train_num_scaled = scaler_num.fit_transform(X_train_num)
X_test_num_scaled = scaler_num.transform(X_test_num)
import numpy as np
from scipy import sparse
# 转为稀疏矩阵
X_train_scaled = sparse.hstack((X_train_cat_enc,
sparse.csr_matrix(X_train_num_scaled)))
X_test_scaled = sparse.hstack((X_test_cat_enc,
sparse.csr_matrix(X_test_num_scaled)))
clf = LogisticRegression(solver='lbfgs')
clf.fit(X_train_scaled, y_train)
accuracy = clf.score(X_test_scaled, y_test)
print('Accuracy score of the {} is {:.4f}'.format(clf.__class__.__name__, accuracy))