1.项目准备
1.1问题描述
淡水是我们最重要和最稀缺的自然资源之一,仅占地球总水量的 3%。它几乎触及我们日常生活的方方面面,从饮用、游泳和沐浴到生产食物、电力和我们每天使用的产品。获得安全卫生的供水不仅对人类生活至关重要,而且对正在遭受干旱、污染和气温升高影响的周边生态系统的生存也至关重要。
1.2任务描述
通过参考英特尔的类似实现方案,预测淡水是否可以安全饮用和被依赖淡水的生态系统所使用,从而可以帮助全球水安全和环境可持续性发展。
1.3数据集
根据课程组给的数据集压缩包,里面包含了训练集datasetab75fb3.zip和测试集test_data.rar,用训练集训练模型,用测试集预测。
链接:https://filerepo.idzcn.com/hack2023/datasetab75fb3.zip
2.开始项目
2.1加载库
以下是机器学习以及深度学习过程中所要用到的库
import os
import xgboost
from xgboost import XGBClassifier
import time
import warnings
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import plotly.io as pio
import plotly.graph_objects as go
from sklearn.utils import resample
from sklearn.model_selection import train_test_split, StratifiedKFold, GridSearchCV, RandomizedSearchCV
from sklearn.preprocessing import RobustScaler
from sklearn.metrics import roc_auc_score, roc_curve, auc, accuracy_score, f1_score
from sklearn.preprocessing import StandardScaler
import sklearn
from sklearn.metrics import precision_recall_curve, average_precision_score
2.2查看数据集情况
读取用户相关的特征,包括每个列的名称、非空值的数量、数据类型以及占用的内存等。
# Read data
df = pd.read_csv('./datasetab75fb3/dataset.csv')
print("Data shape: {}\n".format(df.shape))
display(df.head())
# Print dataset information
df.info()
2.3处理数据集
计算数据集中数值型列的描述统计量、偏度和峰度,并将结果合并成一个 DataFrame 进行显示。
import modin.pandas as pd # 使用 Modin 加快数据处理速度
# 假设 numeric_cols 是要计算偏度和峰度的列名或索引
numeric_cols = df.select_dtypes(include=['float64', 'int64']).columns.tolist()
# 计算描述统计量并转换为 Pandas DataFrame
desc = df.describe() # 计算描述统计量
skewness = df[numeric_cols].skew() # 计算偏度
kurtosis = df[numeric_cols].kurtosis() # 计算峰度
# 将偏度、峰度转换为单列的 Pandas DataFrame
skewness_df = pd.DataFrame(skewness, columns=['skewness']).transpose()
kurtosis_df = pd.DataFrame(kurtosis, columns=['kurtosis']).transpose()
# 将结果与描述统计量合并
result = pd.concat([desc, skewness_df, kurtosis_df])
# 显示结果
result
将数据集中的 "Color"、"Source" 和 "Month" 等英文字段进行因子化(Factorize)处理,转换为数字型变量。
# 显示数据集的前几行
display(df.head())
# 对 'Color' 列进行因子化处理并存储结果
factor = pd.factorize(df['Color'])
print(factor)
df.Color = factor[0]
# 对 'Source' 列进行因子化处理并存储结果
factor = pd.factorize(df['Source'])
print(factor)
df.Source = factor[0]
# 对 'Month' 列进行因子化处理并存储结果
factor = pd.factorize(df['Month'])
print(factor)
df.Month = factor[0]
相关性分析,使用 df.corr()
函数计算数据集中各列之间的相关系数矩阵,然后选择 'Target' 列与其它列的相关系数的绝对值,并按照从大到小的顺序进行排序,存储在 bar
变量中。接着,将 bar
变量中的数据可视化为条形图。
# 相关性分析
bar = df.corr()['Target'].abs().sort_values(ascending=False)[1:]
plt.bar(bar.index, bar, width=0.5)
# 设置figsize的大小
pos_list = np.arange(len(df.columns))
params = {
'figure.figsize': '20, 10'
}
plt.rcParams.update(params)
plt.xticks(bar.index, bar.index, rotation=-60, fontsize=10)
plt.show()
根据柱状图,进一步处理不相关的数据,将 df
数据集中的一些不相关的列进行删除,例如 'Index'、'Day'、'Time of Day'、'Month'、'Water Temperature'、'Source'、'Conductivity' 和 'Air Temperature' 等。
# 删除不相关的列
df = df.drop(
columns=['Index', 'Day', 'Time of Day', 'Month', 'Water Temperature', 'Source', 'Conductivity', 'Air Temperature'])
使用 df.fillna(df.mean())
函数将缺失值用各列的平均值进行填充,使用 df.drop_duplicates()
函数删除数据集中的重复记录。
df = df.fillna(df.mean()) # 使用各列的平均值填充缺失值
df = df.drop_duplicates() # 删除重复的行
通过计算每个特征列的方差,筛选出方差小于等于0.1的特征列,并将其从数据集中删除。然后,使用Pearson相关系数检验特征列与目标变量之间的相关性,如果p值大于0.05,则认为两者不相关,从数据集中删除该特征列。最后输出保留下来的特征列名称以及特征列的数量。
from scipy.stats import pearsonr
# 获取数据集的所有变量名和方差
variables = df.columns
var = df.var()
numeric = df.columns
# 填充缺失值为0
df = df.fillna(0)
# 根据方差进行特征选择
for i in range(0, len(var) - 1):
if var[i] <= 0.1: # 方差小于等于0.1
print(variables[i])
df = df.drop(columns=[numeric[i]])
# 根据Pearson相关系数进行特征选择
variables = df.columns
for i in range(0, len(variables)):
x = df[variables[i]]
y = df[variables[-1]]
if pearsonr(x, y)[1] > 0.05:
print(variables[i])
df = df.drop(columns=[variables[i]])
# 输出最终保留的特征列
variables = df.columns
print(variables)
print(len(variables))
2.4加载数据集
将Modin DataFrame转换为pandas DataFrame,然后从test_data.csv
文件中加载测试数据。
接下来,将DataFrame的特征列保存到X变量中,将目标变量保存到y变量中。
使用RandomUnderSampler进行欠采样,平衡数据集中的类别分布,得到欠采样后的X_resampled和y_resampled。
然后,将欠采样后的数据集划分为训练集和测试集,其中测试集是从test_data
中获取的。
使用StandardScaler对特征进行缩放,然后打印训练集和测试集的形状。
最后,更新训练集和测试集以包含缩放后的特征,可以用于接下来的数据处理和模型训练。
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from imblearn.under_sampling import RandomUnderSampler
# 将Modin DataFrame转换为pandas DataFrame
df_pandas = df._to_pandas()
# 从test_data.csv加载测试数据
test_data = pd.read_csv('./datasetab75fb3/test_data.csv')
# X包含除最后一列之外的所有列作为特征
X = df_pandas.iloc[:, :-1].values
y = df_pandas.iloc[:, -1].values
# 欠采样
rus = RandomUnderSampler()
X_resampled, y_resampled = rus.fit_resample(X, y)
# 其他数据处理或模型训练代码在这里继续
# 使用test_data作为测试集
X_test = test_data.values
# 将欠采样后的数据集划分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X_resampled, y_resampled, test_size=0.2, random_state=21)
# 使用StandardScaler对特征进行缩放
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
# 打印缩放后的训练集和测试集形状
print("Train Shape: {}".format(X_train_scaled.shape))
print("Test Shape: {}".format(X_test_scaled.shape))
# 使用缩放后的特征更新训练集和测试集
X_train, X_test = X_train_scaled, X_test_scaled
2.5模型训练及预测
使用随机森林分类器进行超参数调优和模型评估的过程,添加了一些注释以便理解。
首先定义了要调优的超参数网格和评分器,然后初始化了随机森林分类器。指定了用于重新拟合的评分指标,并记录了开始时间。
接下来执行了随机搜索交叉验证,输出了最佳参数、最佳得分和最佳估计器,以及执行时间。
最后使用最佳模型进行预测,并输出了各项评估指标。
from sklearn.metrics import make_scorer, precision_score, recall_score, accuracy_score, f1_score, roc_auc_score
import datetime
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import RandomizedSearchCV
# 定义要调优的超参数网格
param_grid = {
'n_estimators': [100, 200, 300],
'max_depth': [10, 15, 20, None],
'min_samples_split': [2, 5, 10],
'min_samples_leaf': [1, 2, 4],
'max_features': [1, 2, 'sqrt', 'log2', None]
}
# 定义评分器
scorers = {
'precision_score': make_scorer(precision_score),
'recall_score': make_scorer(recall_score),
'accuracy_score': make_scorer(accuracy_score),
'f1_score': make_scorer(f1_score),
'roc_auc_score': make_scorer(roc_auc_score),
}
# 初始化随机森林分类器
classifier = RandomForestClassifier(criterion='entropy', oob_score=True, random_state=42)
# 指定用于重新拟合的评分指标
refit_score = "f1_score"
# 记录开始时间
start_time = datetime.datetime.now()
print(start_time)
# 执行随机搜索交叉验证
rd_search = RandomizedSearchCV(classifier, param_grid, n_iter=10, cv=3, refit=refit_score, scoring=scorers, verbose=10, return_train_score=True)
rd_search.fit(X_train, y_train)
# 输出最佳参数、最佳得分和最佳估计器
print(rd_search.best_params_)
print(rd_search.best_score_)
print(rd_search.best_estimator_)
# 输出执行时间
print(datetime.datetime.now() - start_time)
# 使用最佳模型进行预测,并输出各项评估指标
y_pred = rd_search.predict(X_test)
print("roc:", roc_auc_score(y_test, rd_search.predict_proba(X_test)[:, 1]))
print("accuracy:", accuracy_score(y_test, y_pred))
print("recall:", recall_score(y_test, y_pred))
print("f1:", f1_score(y_test, y_pred))
2.6加速组件
面向 Scikit-learn 的英特尔扩展是一款免费的 AI 加速器,可以显著加速 Scikit-learn 应用程序,并且完全符合所有 Scikit-Learn API 和算法。通过使用英特尔扩展,可以获得超过 10-100 倍的加速效果,而无需修改现有的 Scikit-learn 代码。这个扩展通过打补丁的方式来实现加速,即通过用优化版本替换现有的 Scikit-learn 算法来提高性能。同时,结合使用 daal4py
、Modin
和 sklearnex
库,可以进一步优化和加速机器学习应用程序的执行速度,提高整体性能。
import daal4py as d4p # 导入 daal4py 库,用于加速机器学习算法的执行
import modin.pandas as pd # 导入 Modin 库的 Pandas 模块
from modin.config import Engine # 导入 Modin 的配置模块
Engine.put("dask") # 设置 Modin 的引擎为 Dask,以实现并行处理和加速
from sklearnex import patch_sklearn # 从 sklearnex 库中导入 patch_sklearn 函数,用于对 Scikit-learn 进行额外的补丁和优化
patch_sklearn() # 调用 patch_sklearn 函数,优化 Scikit-learn 算法
3.结论
-
代码首先读取了一个数据集,并对数据进行了一系列的数据预处理和特征工程操作,包括计算偏度和峰度、因子化处理英文字段、相关性分析、删除不相关的列、处理缺失值和重复值、特征选择等操作。
-
在数据准备好之后,进行了数据切分和标准化处理,并使用了 imblearn 库进行了欠采样(RandomUnderSampler)操作,以解决数据不平衡的问题。
-
接着使用随机森林分类器(RandomForestClassifier)结合随机搜索(RandomizedSearchCV)进行模型训练和调参,优化的评价指标为 F1 分数。在训练过程中输出了最佳参数、最佳评分和最佳模型等信息。
-
最后评估了模型在测试集上的性能表现,包括 ROC-AUC、准确率、召回率和 F1 分数等指标,可以看出训练的效果较好。