1.作业简介
1.1问题描述
淡水是我们最重要和最稀缺的自然资源之一,仅占地球总水量的 3%。它几乎触及我们日常生活的方方面面,从饮用、游泳和沐浴到生产食物、电力和我们每天使用的产品。获得安全卫生的供水不仅对人类生活至关重要,而且对正在遭受干旱、污染和气温升高影响的周边生态系统的生存也至关重要。
1.2预期解决方案
通过参考英特尔的类似实现方案,预测淡水是否可以安全饮用和被依赖淡水的生态系统所使用,从而可以帮助全球水安全和环境可持续性发展。这里分类准确度和推理时间将作为评分的主要依据。
1.3数据集
https://filerepo.idzcn.com/hack2023/datasetab75fb3.zip
1.4项目加速相关技术
-
modin:Modin 使用Ray、Dask或Unidist提供一种轻松的方式来加速pandas 、脚本和库。与其他分布式 DataFrame 库不同,Modin 提供与现有 pandas 代码的无缝集成和兼容性。即使使用 DataFrame 构造函数也是相同的。
-
sklearnex:借助面向 Scikit-learn* 的英特尔® 扩展,加速 Scikit-learn ,并且仍然完全符合所有 Scikit-Learn API 和算法。英特尔® Extension for Scikit-learn是一款免费软件 AI 加速器,可为各种应用程序带来超过 10-100 倍的加速。
面向 Scikit-learn* 的英特尔® 扩展为您提供了一种加速现有 scikit-learn 代码的方法。加速是通过打补丁实现的:用扩展提供的优化版本替换现有的 scikit-learn 算法。
-
daal4py组件:可将训练好的xgboost转换为 daal4py 模型,以便进一步改进预测时间性能, 利用底层的英特尔® 高级矢量扩展指令集(英特尔® AVX-512)硬件,最大限度地提高英特尔® 至强® 处理器上的梯度提升性能。
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
import daal4py as d4p
import modin.pandas as pd
from modin.config import Engine
Engine.put("dask")
from sklearnex import patch_sklearn
patch_sklearn()
运行上面的代码之后会输出下方内容,表示sklearn的扩展已经启用。
os.environ['NLSLANG']='SIMPLIFIED CHINESE_CHINA.UTF8'
pd.set_option( 'display.max_columns', 100)
2.2读入数据并分析
使用pandas读入csv数据文件,并输出数据的大小,部分信息,和数据的结构。
df = pd.read_csv('./dataset.csv')
print("Data shape: {}\n".format(df.shape))
display(df.head())
df.info()
2.3数据特征分析
查看各类特征是离散值还是连续值。
cat_cols = [] # 存储离散特征
float_cols = [] # 存储连续特征
for col in df.columns:
if df[col].dtype == 'object':
cat_cols.append(col)
else:
float_cols.append(col)
print('离散特征:', cat_cols)
print('连续特征:', float_cols)
将离散值转换成连续性数据。
display(df.head())
factor = pd.factorize(df['Color'])
print(factor)
df.Color = factor[0]
factor = pd.factorize(df['Source'])
print(factor)
df.Source = factor[0]
factor = pd.factorize(df['Month'])
print(factor)
df.Month = factor[0]
df.describe()
2.4数据相关性分析
对处理后的数据进行对Target的相关性分析。
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, 18'
}
plt.rcParams.update(params)
plt.xticks(bar.index, bar.index, rotation=-60, fontsize=10)
plt.show()
针对相关性较差的和无关的数据,我们将其舍去。
df = df.drop(
columns=['Index', 'Day', 'Time of Day', 'Month', 'Water Temperature', 'Source', 'Conductivity', 'Air Temperature'])
2.5缺失值,重复值,偏差值处理
查看处理过后的数据的缺失和重复情况。
display(df.isna().sum())
missing = df.isna().sum().sum()
duplicates = df.duplicated().sum()
print("\nThere are {:,.0f} missing values in the data.".format(missing))
print("There are {:,.0f} duplicate records in the data.".format(duplicates))
由于缺失值较多,我们将其删除会使有效数据大量流失,所以这里对缺失值采取线性插值的方法进行补全,而对少量的重复值直接舍去。
df = df.fillna(df.interpolate(method='linear'))
df = df.drop_duplicates()
处理后再次查看缺失和重复情况。
对于偏差值,我们通过检查皮尔逊相关系数与缺失值的比例和数值型特征的方差值来筛选符合要求的特征。
from scipy.stats import pearsonr
variables = df.columns
df = df
var = df.var()
numeric = df.columns
df = df.fillna(df.interpolate())
for i in range(0, len(var) - 1):
if var[i] <= 0.1: # 方差大于10%
print(variables[i])
df = df.drop(numeric[i],axis=1)
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(variables[i],axis=1)
variables = df.columns
print(variables)
print(len(variables))
在这里,我们将Lead特征舍去,最后剩下15个有效特征。
2.6数据分布变换
我们查看剩下的数据分布情况。
df.hist(bins=50,figsize=(16,12))
发现有些数据的分布不规则,此处对其进行非线性变换,使其转换成便于模型拟合的类正态分布。
# 针对不规则分布的变量进行非线性变换,一般进行log
log_col = ['Iron', 'Zinc', 'Turbidity', 'Copper', 'Manganese']
show_col = []
for col in log_col:
df[col + '_log'] = np.log(df[col])
show_col.append(col + '_log')
df[show_col].hist(bins=50,figsize=(16,12))
3.模型训练
3.1数据划分
对最后处理好的数据进行划分,分为训练集和测试集,并对数据进行标准化处理。
X = df.drop( ['Target','Iron', 'Zinc', 'Turbidity', 'Copper', 'Manganese'], axis=1)
y = df['Target']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=21)
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
3.2创建XGBoost分类器
xgb = XGBClassifier(
learning_rate=0.1,
n_estimators=15,
max_depth=12,
min_child_weight=6,
gamma=0,
subsample=1,
colsample_bytree=1,
objective='binary:logistic',
nthread=4,
alpha=4,
scale_pos_weight=1,
seed=27)
3.3参数设置
对随机网格搜索的参数进行配置。
param_grid = {
'max_depth': [10, 15, 20],
"gamma": [0, 1, 2],
"subsample": [0.9, 1],
"colsample_bytree": [0.3, 0.5, 1],
'min_child_weight': [4, 6, 8],
"n_estimators": [10,50, 80, 100],
"alpha": [3, 4, 5]
}
3.4模型训练
对模型进行训练。
refit_score = "f1_score"
start_time = time.time()
print(start_time)
rd_search = RandomizedSearchCV(xgb, param_grid, n_iter=10, cv=3, refit=refit_score, scoring=sklearn.metrics.make_scorer(f1_score), 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(time.time() - start_time)
训练完成后,输出训练过程和最优参数如下。
使用训练好后的模型对测试集进行推理测试。
test_data = pd.read_csv('test_data.csv')
test_data = test_data.drop(
columns=['Index', 'Day', 'Time of Day', 'Month', 'Water Temperature', 'Source', 'Conductivity', 'Air Temperature'])
pd.factorize(test_data['Color'])
test_data.Color = factor[0]
test_data = test_data.fillna(test_data.interpolate(method='linear'))
test_data = test_data.drop_duplicates()
log_col = ['Iron', 'Zinc', 'Turbidity', 'Copper', 'Manganese']
show_col = []
for col in log_col:
test_data[col + '_log'] = np.log(test_data[col])
show_col.append(col + '_log')
test_data = test_data.drop( ['Iron', 'Zinc', 'Turbidity', 'Copper', 'Manganese'], axis=1)
y_true = test_data['Target']
X_test = test_data.drop(
columns=['Lead', 'Target'])
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
from datetime import datetime
start = datetime.now()
y_pred = xgb.predict(X_test)
time = datetime.now() - start
f1 = f1_score(y_true, y_pred)
print('\nF1 score: {}'.format(f1))
print('Inference time: {} seconds'.format(time))
4.总结
在本次项目中,我学习使用了Intel下的oneAPI组件来对淡水的质量进行预测,在项目的实际开发中,Intel AI Analytics Toolkit对问题的解决有很大的提升,面对如此大量的数据也能很快的训练出模型,并且模型的效果也很令人满意。相信在未来,Intel的oneAPi组件会给我们带来更多的惊喜。