文章目录
- 摘要
- 项目地址
- 实战代码(初级版)
- 实战代码(进阶版)
摘要
- 本文介绍了一个完整的机器学习流程项目,重点涵盖了多元线性回归的建模与评估方法。项目详细讲解了特征工程中的多项实用技巧,包括:通过np.log变换使数据符合正态分布、离散型数据的one-hot编码处理、缺失值处理、数据标准化归一化、以及多项式回归升维等关键技术。此外,项目还特别介绍了使用正则化方法提高模型泛化能力的重要技巧。该研究为机器学习实践者提供了一个全面的技术参考,特别是在数据预处理和模型优化方面具有较高的实用价值。
项目地址
- 人工智能学习代码库
实战代码(初级版)
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import Ridge
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, PolynomialFeatures# 设置全局字体为支持中文的字体
plt.rcParams['font.sans-serif'] = ['SimHei'] # 使用黑体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题# 设置显示宽度: 解决数据显示不完整
pd.set_option('display.max_columns', None) # 显示所有列
pd.set_option('display.width', None) # 自动调整显示宽度# 1 读取数据
data =pd.read_csv("./data/insurance.csv")
print(data.head(3))# 2 EDA数探索
# 2.1 原数据右偏
plt.hist(data["charges"])
plt.title("原数据 'charges' 的分布")
plt.xlabel("charges")
plt.ylabel("频数")
plt.show()# 2.2 矫正后的数据
plt.hist(np.log(data["charges"]))
plt.title("对数变换后的 'charges' 的分布")
plt.xlabel("log(charges)")
plt.ylabel("频数")
plt.show()# 3 特征工程# 3.1 非数值型的列离散化
data=pd.get_dummies(data,columns=["sex","smoker","region"])
data.head(3)# 3.2 删除目标列 花销一列
x=data.drop("charges",axis=1)
y=data['charges']# 3.3 缺失值填充
x.fillna(0,inplace=True)
y.fillna(0,inplace=True)
# 3.4 数据切分 训练集(70%)和测试集(30%)
x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.3)# 3.5 标准归一化(均值归一化+方差归一化) 确保训练集和测试集的均值和方差相同
scaler=StandardScaler(with_mean=True,with_std=True).fit(x_train)
# 对训练集进行拟合并转换
x_train_scaled = scaler.transform(x_train)
# 对测试集进行转换(使用训练集的均值和标准差)
x_test_scaled = scaler.transform(x_test)# 3.6 升维 增加Y的维度或因素 利用线性模型做回归
polynomial_features = PolynomialFeatures(degree=2, include_bias=False)
x_train_scaled = polynomial_features.fit_transform(x_train_scaled)
x_test_scaled = polynomial_features.fit_transform(x_test_scaled)# 4 模型训练 Ridge=LinearRegression+L2正则化reg=Ridge(alpha=10.0)
reg.fit(x_train_scaled,np.log1p(y_train)) #np.log1p对log函数的优化
y_predict=reg.predict(x_test_scaled)# 5 模型评估
'''
RMSE(均方根误差)和 MSE(均方误差)是常用的模型评估指标,用于衡量模型预测值与真实值之间的差异。''''''
对数变换后的 RMSE
重要性:这些指标衡量了模型在对数变换后的目标变量上的预测误差。对数变换通常用于处理右偏分布的数据,使其更接近正态分布。因此,这些指标可以帮助你了解模型在对数空间中的表现。
适用场景:当你希望模型在对数空间中表现良好时,这些指标非常重要。
'''# 计算训练集上对数变换后的真实值与预测值之间的均方根误差(RMSE)
rmse_train_log = np.sqrt(mean_squared_error(y_true=np.log1p(y_train), y_pred=reg.predict(x_train_scaled)))
print(f"训练集上对数变换后的 RMSE: {rmse_train_log}")# 计算测试集上对数变换后的真实值与预测值之间的均方根误差(RMSE)
rmse_test_log = np.sqrt(mean_squared_error(y_true=np.log1p(y_test), y_pred=y_predict))
print(f"测试集上对数变换后的 RMSE: {rmse_test_log}")# 计算训练集上对数变换后的真实值与预测值之间的均方误差(MSE)
mse_train_log = mean_squared_error(y_true=np.log1p(y_train), y_pred=reg.predict(x_train_scaled))
print(f"训练集上对数变换后的 MSE: {mse_train_log}")# 计算测试集上对数变换后的真实值与预测值之间的均方误差(MSE)
mse_test_log = mean_squared_error(y_true=np.log1p(y_test), y_pred=y_predict)
print(f"测试集上对数变换后的 MSE: {mse_test_log}")'''
还原后的 RMSE
重要性:这些指标衡量了模型在原始目标变量上的预测误差。还原后的 RMSE 更直观地反映了模型在实际数据尺度上的表现。
适用场景:当你希望模型在原始数据尺度上表现良好时,这些指标非常重要。
'''# 计算训练集上真实值与预测值(经过指数变换还原)之间的均方根误差(RMSE)
rmse_train_exp = np.sqrt(mean_squared_error(y_true=y_train, y_pred=np.exp(reg.predict(x_train_scaled))))
print(f"训练集上还原后的 RMSE: {rmse_train_exp}")# 计算测试集上真实值与预测值(经过指数变换还原)之间的均方根误差(RMSE)
rmse_test_exp = np.sqrt(mean_squared_error(y_true=y_test, y_pred=np.exp(y_predict)))
print(f"测试集上还原后的 RMSE: {rmse_test_exp}")
age sex bmi children smoker region charges
0 19 female 27.90 0 yes southwest 16884.9240
1 18 male 33.77 1 no southeast 1725.5523
2 28 male 33.00 3 no southeast 4449.4620
训练集上对数变换后的 RMSE: 0.35492916766241805
测试集上对数变换后的 RMSE: 0.3896820204464227
训练集上对数变换后的 MSE: 0.12597471405753685
测试集上对数变换后的 MSE: 0.1518520770592062
训练集上还原后的 RMSE: 4940.399449726374
测试集上还原后的 RMSE: 5243.354576700596
实战代码(进阶版)
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.linear_model import Ridge
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import PolynomialFeatures# 设置全局字体为支持中文的字体
plt.rcParams['font.sans-serif'] = ['SimHei'] # 使用黑体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题# 设置显示宽度: 解决数据显示不完整
pd.set_option('display.max_columns', None) # 显示所有列
pd.set_option('display.width', None) # 自动调整显示宽度# 1 读取数据
data = pd.read_csv("./data/insurance.csv")
print("原数据:")
print(data.head(3))# 2 EDA数探索
# 2.1 原数据右偏
plt.hist(data["charges"])
plt.title("原数据 'charges' 的分布")
plt.xlabel("charges")
plt.ylabel("频数")
plt.show()# 2.2 矫正后的数据
plt.hist(np.log(data["charges"]))
plt.title("对数变换后的 'charges' 的分布")
plt.xlabel("log(charges)")
plt.ylabel("频数")
plt.show()# 2.2 性别对花费的影响分析
sns.kdeplot(data.loc[data.sex == "male", "charges"], label='male')
sns.kdeplot(data.loc[data.sex == "female", "charges"], label='female')
plt.legend(title="性别对花费的影响分析")
plt.show()# 2.3 区域对花费的影响分析
sns.kdeplot(data.loc[data.region == "northwest", "charges"], label='northwest')
sns.kdeplot(data.loc[data.region == "northeast", "charges"], label='northeast')
sns.kdeplot(data.loc[data.region == "southwest", "charges"], label='southwest')
sns.kdeplot(data.loc[data.region == "southeast", "charges"], label='southeast')
plt.legend(title="区域对花费的影响分析")
plt.show()# 2.4 吸烟对花费的影响分析
sns.kdeplot(data.loc[data.smoker == "yes", "charges"], label='smoker')
sns.kdeplot(data.loc[data.smoker == "no", "charges"], label='no smoker')
plt.legend(title="吸烟对花费的影响分析")
plt.show()# 2.5 孩子个数对花费的影响分析
sns.kdeplot(data.loc[data.children == 0, "charges"], label='no children')
sns.kdeplot(data.loc[data.children == 1, "charges"], label='one children')
sns.kdeplot(data.loc[data.children == 2, "charges"], label='two children')
sns.kdeplot(data.loc[data.children == 3, "charges"], label='three children')
sns.kdeplot(data.loc[data.children == 4, "charges"], label='four children')
sns.kdeplot(data.loc[data.children == 5, "charges"], label='five children')
plt.legend(title="孩子个数对花费的影响分析")
plt.show()# 3 特征工程
# 3.1 删除系数相关低的列 region、sex
data = data.drop(["region", "sex"], axis=1)
print("删除系数相关低的列 region、sex")
print(data.head(3))# 3.2 降噪 连续值变为离散值
def greater(df, bmi, num_child):df['bmi'] = 'over' if df['bmi'] >= bmi else 'under'df['children'] = 'no' if df['children'] == num_child else 'yes'return dfdata = data.apply(greater, axis=1, args=(30, 0))# 3.3 非数值型的列离散化
data = pd.get_dummies(data)
print("bmi,num_child连续值变为离散值")
print(data.head(3))# 3.4 删除目标列 花销一列
x = data.drop("charges", axis=1)
y = data['charges']# 3.5 缺失值填充
x.fillna(0, inplace=True)
y.fillna(0, inplace=True)# 3.6 数据切分 训练集(70%)和测试集(30%)
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3)# 3.7 升维 增加Y的维度 利用线性模型做回归
polynomial_features = PolynomialFeatures(degree=2, include_bias=False)
x_train_poly = polynomial_features.fit_transform(x_train)
x_test_poly = polynomial_features.fit_transform(x_test)# 4 模型训练 Ridge=LinearRegression+L2正则化
reg = Ridge(alpha=10.0)reg.fit(x_train_poly, np.log1p(y_train)) # np.log1p对log函数的优化
y_predict = reg.predict(x_test_poly)# 5 模型评估
# 计算训练集上对数变换后的真实值与预测值之间的均方根误差(RMSE)
print("计算训练集上对数变换后的真实值与预测值之间的均方根误差(RMSE)")
print(np.sqrt(mean_squared_error(y_true=np.log1p(y_train), y_pred=reg.predict(x_train_poly))))# 计算测试集上对数变换后的真实值与预测值之间的均方根误差(RMSE)
print("计算测试集上对数变换后的真实值与预测值之间的均方根误差(RMSE)")
print(np.sqrt(mean_squared_error(y_true=np.log1p(y_test), y_pred=y_predict)))# 计算训练集上真实值与预测值(经过指数变换还原)之间的均方根误差(RMSE)
print("计算训练集上真实值与预测值(经过指数变换还原)之间的均方根误差(RMSE)")
print(np.sqrt(mean_squared_error(y_true=y_train, y_pred=np.exp(reg.predict(x_train_poly)))))# 计算测试集上真实值与预测值(经过指数变换还原)之间的均方根误差(RMSE)
print("计算测试集上真实值与预测值(经过指数变换还原)之间的均方根误差(RMSE)")
print(np.sqrt(mean_squared_error(y_true=y_test, y_pred=np.exp(y_predict))))
原数据:age sex bmi children smoker region charges
0 19 female 27.90 0 yes southwest 16884.9240
1 18 male 33.77 1 no southeast 1725.5523
2 28 male 33.00 3 no southeast 4449.4620
删除系数相关低的列 region、sexage bmi children smoker charges
0 19 27.90 0 yes 16884.9240
1 18 33.77 1 no 1725.5523
2 28 33.00 3 no 4449.4620
bmi,num_child连续值变为离散值age charges bmi_over bmi_under children_no children_yes smoker_no smoker_yes
0 19 16884.9240 False True True False False True
1 18 1725.5523 True False False True True False
2 28 4449.4620 True False False True True False
计算训练集上对数变换后的真实值与预测值之间的均方根误差(RMSE)
0.38316517904805586
计算测试集上对数变换后的真实值与预测值之间的均方根误差(RMSE)
0.3812317453220069
计算训练集上真实值与预测值(经过指数变换还原)之间的均方根误差(RMSE)
4746.576620613462
计算测试集上真实值与预测值(经过指数变换还原)之间的均方根误差(RMSE)
4899.862272153837