SCIKIT-LEARN学习记录

虽然是sklearn学习记录帖,但也会涉及XGBoost等其他库。


#

记录如何使用 scikit-learn 训练机器学习模型,微调参数以及获取获取相关指标。

# 通用流程

# 加载数据

 scikit-learn 提供了非常多的数据集作为示例数据,使得初学者能够利用这些数据集进行练习。这些返回数据实例的函数位于 sklearn.datasets 中,具体使用方式如下:

from sklearn.datasets import load_iris

# 获取数据实例
data_object = load_iris()
# 得到数据集
X = data_object.get('data')  # X = data_object.data
# 得到目标变量集合
Y = data_object.get('target')  # Y = data_object.target

从EXCEL中加载数据:

data = pandas.read_excel('excel.xlsx', header=0, index_col=False)

X = data.iloc[:, 0:17]  # 1到17列作为输入特征
X = numpy.array(X.values) # 将输入特征从DataFrame转为numpy列表
Y = numpy.array(data.iloc[:, 19:20].values)  # 第20列作为目标变量

若在拟合模型时提示:

A column-vector y was passed when a 1d array was expected
 XGBoost 不需要将一维数组转为二维以作为目标变量,但 scikit-learn 的随机森林需要将一维数组转为二维数组。

# 使用.ravel()将其降为一维数组
regressor = RandomForestRegressor(n_estimators=500).fit(X_train, Y_train.ravel())

# 处理缺失值

有四种常用的处理缺失值的方式,分别是将缺失值填充为平均数、中位数、众数和自定义常数。需要调用的函数是 SimpleImputer() 

from sklearn.impute import SimpleImputer

# 导入数据并查看数据情况
data = pandas.read_csv('./data.csv', index_col=0)
data.info()
# 创建不同方式处理缺失值的实例,missing_value参数确定何为缺失值,copy默认为True指创建副本而不是改变原数据
imp_mean = SimpleImputer(missing_values=numpy.nan, strategy='mean', copy=True)  # 使用均值替代缺失值
imp_median = SimpleImputer(missing_values='缺失值', strategy='median', copy=True)  # 使用中位数替代缺失值
imp_most_frequent = SimpleImputer(missing_values=numpy.nan, strategy='most_frequent', copy=True)  # 众数替代

imp_constant = SimpleImputer(missing_values='缺失', strategy='constant', fill_value=0, copy=True)  # 自定义常数

# 获取想要处理缺失值的列,特征必须为二维所以需要reshape,但标签允许一维所以不需要reshape
age = data.loc[:, 'age'].values.reshape(-1, 1)
# 缺失值处理
data.loc[:, 'age'] = imp_mean.fit_transform(age)
# 使用pandas处理缺失值
data.loc[:, 'age'] = data.loc[:, 'age'].fillna(data.loc[:, 'age'].mean())

除上面代码块最后一行用于填充缺失值的 pandas 代码外,还有删除缺失值所在行或列的代码:

# axis=0指删除行, axis=1时为删除列, inplace=True时在原数据上进行修改, 默认为False
data.dropna(axis=0, inplace=True)

# 离散型变量

 scikit-learn 中使用不同编码器分别将输入特征和目标变量进行编码,这些转换仅针对有序变量或有距变量;但输入特征为名义变量时,则需要使用独热编码 One-hot encoder 

有序变量:可以从小到大排序,学历,初中,高中,大学

有距变量:连续性,可以计算,如身高,体重

名义变量:有互斥性,你属于一类,就不会属于另一类。如:性别,付费方式

对目标变量进行编码

使用 LabelEncoder() 对作为有序、有距变量的目标变量进行编码:

from sklearn.preprocessing import LabelEncoder

# 从CSV读取数据
data = pandas.read_csv('./data.csv', index_col=0)
# 获取目标变量的值
Y = data.iloc[:, -1]
# 实例化LabelEncoder
le = LabelEncoder()
# (见推荐)导入数据
le = le.fit(Y)
# (可选,见推荐)查看类别
le.classes_
# (见推荐)编码并输出结果
labels = le.transform(Y)
# (推荐)可以一步到位,如果不查看classes_的话
labels = le.fit_transform(Y)
# (可选)标签可以逆转
le.inverse_transform(labels)
# 将编码好的值赋给原始数据
data.iloc[:, -1] = labels
# (省流版)一步到位
data.iloc[:, -1] = LabelEncoder().fit_transform(data.iloc[:, -1])

对输入特征进行编码

使用 OrdinalEncoder() 对作为有序、有距变量的输入特征进行编码:

from sklearn.preprocessing import OrdinalEncoder

# 从CSV读取数据
data = pandas.read_csv('./data.csv', index_col=0)
# 获取想要编码为离散型变量的输入特征
x1 = data.loc[:, '这是类别列']
# 实例化OrdinalEncoder
ol = OrdinalEncoder()
# (见推荐)导入数据
ol = ol.fit(x1)
# (可选,见推荐)查看类别
ol.categories_
# (见推荐)编码并输出结果
x1_cat = ol.transform(x1)
# (推荐)可以一步到位,如果不查看categories_的话
x1_cat = ol.fit_transform(x1)
# 将编码好的类别赋值给原始数据
data.loc[:, '这是类别列'] = x1_cat
# (省流版)一步到位
data.loc[:, '这是类别列'] = OrdinalEncoder().fit_transform(data.loc[:, '这是类别列'])

独热编码

当输入特征值为名义变量时,取值没有任何数学联系,如性别、舱门等,需要使用独热编码(参考此处)将它们转换为哑变量

from sklearn.preprocessing import OneHotEncoder

# 导入数据见上文
# 获取要独热编码的特征
X_oh = data.iloc[:, 1:23]
# 实例化OneHotEncoder
oh_enc = OneHotEncoder(sparse_output=False, drop=None)
# 编码并输出编码结果,将这一结果转换为array
X_ndarray = X_oh.values
for col in [3, 14]:
    encoded_columns = oh_enc.fit_transform(X.iloc[:, col].values.reshape(-1, 1))
    X_ndarray = numpy.hstack((X_ndarray, encoded_columns))  # 将生成的独热编码与原始数据合并
# (可选,要求df)还原
inverse_df = pandas.DataFrame(oh_enc.inverse_transform(oh_result))
# 查看独热编码后的特征名
print(oh_enc.get_feature_names_out())
# 删除用于独热编码的原始列
newdata.drop(['name1', 'name2'], axis=1, inplace=True)
X_ndarray = numpy.delete(X_ndarray, [3, 14], axis=1)  # 转为ndarray后用该行代码删除
# 重新设置列名,若已转为ndarray,需要再转为DataFrame再重设列名
newdata.columns = ['name1', 'name2',..., 'namen']

将目标变量转为哑变量

 LabelBinarizer() 可以将目标变量转为哑变量。

# 划分训练集与测试集

在训练集上拟合模型,在测试集上验证模型的性能。可以按七比三将数据划分为训练集和测试集:

from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris

X = data_object.get('data')  # X = data_object.data
Y = data_object.get('target')  # Y = data_object.target
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.3, random_state=120)  # random_state参数用来设置随机数种子,以固定划分方便复现

# 评估模型

查看评估指标:

import sklearn

print(sklearn.metrics.SCORERS.keys())

值得注意的是,回归任务和分类任务使用的评估指标不同。如explained_variance_scorer2_score一般用于回归任务。而分类任务多用f1_scoreaccuracy_score等指标评估模型。

使用交叉验证集进行模型评估:

from sklearn.model_selection import cross_val_score

# estimator可以是实例化的任意模型;cv=5指把输入的数据集分为5份,循环5次使得每份都作为一次交叉验证集
cv_score = cross_val_score(estimator, X_train, Y_train, cv=5, scoring='从上面的指标选,默认r2').mean()

 log_loss 作为指标评估模型:

from sklearn.metrics import log_loss

# .predict_proba()是输出概率,.predict()是输出预测结果
logloss = log_loss(Y_test, classifier.predict_proba(X_test))

使用 classification_report() 评估模型,并自动给出准确率、召回率、F1_Score:

from sklearn.metrics import classification_report, f1_score

print(classification_report(Y_test, classifier.predict(X_test)))
# 结果中的accuracy代表正确分类个数/总个数

# 单独计算F1_socre
f1_score(Y_test, regressor.predict(X_test))

计算 % var explained

from sklearn.metrics import explained_variance_score

explained_var = explained_variance_score(Y_test, regressor.predict(X_test))

# 学习曲线

结合 sklearn.model_selection.learning_curve() 返回的数据,并使用 matplotlib 绘制学习曲线。

关于前者,该函数返回训练集大小、训练分数、测试分数以及可选的拟合时间和打分时间(需要设置参数,详见帮助文档)用于绘图:

from sklearn.model_selection import KFold
from sklearn.model_selection import learning_curve

# n_splits指将数据集分为几份,shuffle指是否打乱数据,random_state为随机数种子
cv = KFold(n_splits=5, shuffle=True, random_state=120)
# estimator为实例化的任意模型;可以直接写cv=5
train_sizes, train_scores, test_scores = learning_curve(estimator, X_train, Y_train, shuffle=True, cv=cv, random_state=120,scoring=scoring, train_sizes=range(5, 60, 5))
# train_sizes还可以为训练集占比
train_sizes, train_scores, test_scores = learning_curve(regressor, X_train, Y_train.values.ravel(), shuffle=True, cv=5, train_sizes=[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1])
# 设置返回分数为负的均方误,画图时要给train_scores和test_scores设定负号
train_sizes, train_scores, test_scores = learning_curve(regressor, X_train, Y_train.values.ravel(), shuffle=True, scoring='neg_mean_squared_error', cv=5, train_sizes=[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1])

值得注意的是, training_sizes  cv 这两个参数共同控制train_scores和test_scores的维度。具体而言,前者控制_scores的行数,而后者控制列数。

从上述代码中得到用于绘制学习曲线的数据后,开始使用画图包进行绘图:

from matplotlib import pyplot

fig, ax = pyplot.subplots()
ax.plot(train_sizes, numpy.mean(train_scores, axis=1), 'o-', c='red', label='train score')
ax.plot(train_sizes, numpy.mean(test_scores, axis=1), 'o-', c='blue', label='test score')

# ROC曲线和偏依赖图

ROC曲线是用于评估分类模型性能的一种常用工具,特别是在二分类问题中。

偏依赖分析是机器学习模型解释和分析工具的一部分,它的作用是帮助理解模型中特征与预测结果之间的关系。可以揭示单个特征对模型预测结果的影响程度。

from sklearn.inspection import PartialDependenceDisplay
from sklearn.metrics import RocCurveDisplay

PartialDependenceDisplay.from_estimator(regressor, X, features=[1, 2, 3])
rfc_disp = RocCurveDisplay.from_estimator(classifier, X_test, Y_test)

# 偏相关分析

偏相关与皮尔逊相关分析不同的是,偏相关分析的是两变量回归后预测值与真实值的残差。具体而言,是将两个变量作为因变量,其他变量(控制变量)做为自变量,做回归分析,得到模型后求这两个变量的残差。再将这两个残差做相关分析。代码实现如下:

from pingouin import partial_corr
import pingouin

data = pandas.read_excel('questcopy.xlsx', header=0, index_col=False)
print(data.pcorr().to_string())  # to_string()是将全部值展现出来

指定协变量

pcorr_data = a_dataframe.partial_corr(x=x, y=y, covar=['covar1', 'covar2' ,'covar3']).round(3)
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments