?在本教程中,您将学习如何构建线性回归模型。这是您在学习机器学习时首先要做的事情之一,因此它将帮助您迈出进入这个竞争激烈的市场的第一步。?? ?目录目录???先决条件什么是线性回归?评估指标R 平方均方根误差线性回归示例 - 汽车价格预测模型导入所需的包:导入数据集预处理 数据集如何找到异常值分析数据集双变量分析销售价格与数字特征双变量分析销售价格与分类特征双变量分析分类变量编码相关性分析如何构建模型 标准化数据集训练模型如何评估模型使用 K 折交叉验证评估模型结果可视化结论先决条件使用 IDE(最好是 VS Code)的中等水平 经验对 Python Notebook (.pynb) 文件的基本了解对Python编程语言有很好的理解Pandas(处理数据帧) 、Numpy、Scikit Learn 和 Matplot 库的基本知识一些统计学知识有助于分析数据什么是线性回归?线性回归是一种 监督学习方法,其中预测输出本质上是连续的。例如,价格预测、标记预测等。线性回归是一种基本的统计和机器学习技术,用于对因变量(也称为 目标变量或响应变量)与一个或多个自变量(预测变量或特征)之间的关系进行建模。它的目的是建立一个最能代表这些变量之间关联的线性方程, 使我们能够做出预测并从数据中得出见解。线性回归的主要目标是找到“最佳拟合”线(或更高维度的超平面),以最小化预测值和实际观测值之间 的差异。这条最佳拟合线由以下形式的线性方程定义:Y = b0?+ b1?X1?+ b2?X2?+...+ bn?Xn?在这个等式中 :Y 代表我们想要预测的因变量。X1,X2,...,Xn 是自变量或特征。b0 是截距(当所有 X 值均为零时 Y 的值)。b1, b2,...,bn 是确定每个自变量和因变量之间关系的系数。线性回归假设预测变量和目标变量之间存在线性关系。该模型的目标是估计系数 (b0,b1,...,bn),以最小化训练数据中预测值与实际值之间的平方差之和。此过程通常称为“拟合模型”。评估指标线性回归模型 的评估指标是:决定系数或 R 平方 (R2)均方根误差 (RSME)让我们看看它们分别是什么。R 平方R-Squared 描述了开 发模型捕获的变化量。它始终介于 0 和 1 之间。R 平方的值越高,模型与数据的拟合程度越好。均方根误差RMSE 测量模型生成的预 测值与数据集中的实际观测值之间的误差或残差的平均大小。它的范围始终在 0 和正无穷大之间。RMSE 值越低表明预测性能越好。线性回 归示例 - 汽车价格预测模型在此示例中,我们将尝试通过构建线性回归模型来预测汽车价格。我在 Kaggle 中发现了https:// www.kaggle.com/datasets/nehalbirla/vehicle-dataset-from-cardekho这 个问题和数据集。我注意到有一个针对这个问题的https://www.kaggle.com/code/farzadnekouei/p olynomial-regression-regularization-assumptions/notebook提交,这是完美的。 事实上,我通过采用该解决方案的一部分来构建我的解决方案。让我们深入探讨这个问题。我们得到了一个二手车数据集,其中包含汽车名称、年份 、售价、当前价格、行驶公里数、燃料类型、卖家类型、变速箱以及卖家是否是二手车所有者。我们的目标是预测汽车的售价。我们来探讨一下解决 方案。导入所需的包:您将需要各种软件包来解决此问题。以下是导入它们的方法:import numpy as npimport pan das as pdimport matplotlib.pyplot as pltimport seaborn as snsfrom sklearn.model_selection import train_test_splitfrom sklearn.prep rocessing import StandardScalerfrom sklearn.linear_model import L inearRegressionfrom sklearn import metricsfrom sklearn.model_sele ction import KFoldfrom sklearn.pipeline import make_pipelinefrom statsmodels.stats.diagnostic import normal_adfrom statsmodels.sta ts.outliers_influence import variance_inflation_factorfrom statsm odels.stats.stattools import durbin_watsonfrom scipy import stats 导入数据集?可以从我的https://github.com/5minslearn/Car-Price-Prediction-usi ng-Linear-Regression/blob/master/car%20data.csvGithub 存储库下载。df = pd.read_csv(''./car data.csv'') 导入数据集预处理数据集下面的代码显示了列及其数据类型和行数。我们的数据 集有 9 列和 301 行。df.info()用于查找数据帧信息的命令,例如列、数据类型、行数等。?? “Car_Name”列描述 汽车名称。我们的数据集中应忽略该字段。这是因为,只有汽车的功能才重要,而不是它的名称。以下代码返回数据集中唯一汽车名称的数量。df [''Car_Name''].nunique()Car_Name查找列中唯一条目的数量我们的数据集中有 98 个独特的汽车名称。?唯一 汽车名称的数量显然,它不会给我们的数据集添加任何意义,因为类别太多。让我们删除该列。df.drop(''Car_Name'', axi s=1, inplace=True)删除Car_Name列该数据集具有名为“Year”的列。理想情况下,我们需要购买/出售汽车的年 份。因此,我们将其转换为“年龄”并删除“年份”列。df.insert(0, "Age", df["Year"].max()+1-d f["Year"] )df.drop(''Year'', axis=1, inplace=True)“车龄”是通过查找数据集中可用的最 大年份与特定汽车年份之间的差异来计算的。这是因为,我们的计算将特定于该特定时间段和该数据集。? 如何找到异常值异常值是与其他观察值 显着不同的数据点。它们可能会导致模型的性能下降。? 分类列的数据类型为“对象”。让我们将数字列和分类列分组到 NumPy 数组中。 数组中的前 5 个元素将是数字列,其余 3 个元素将是分类列。我们可以使用库在列中绘制数据seaborn。分类列将包含多个条形,而 数字列将包含单个条形。让我们尝试使用以下代码查找数据集中的异常值:sns.set_style(''darkgrid'')colors = [''#0055ff'', ''#ff7000'', ''#23bf00'']CustomPalette = sns.set_palett e(sns.color_palette(colors))OrderedCols = np.concatenate([df.sele ct_dtypes(exclude=''object'').columns.values, df.select_dtypes(inc lude=''object'').columns.values])fig, ax = plt.subplots(2, 4, figsi ze=(15,7),dpi=100)for i,col in enumerate(OrderedCols): x = i//4 y = i%4 if i<5: sns.boxplot(data=df, y=col, ax=ax[x,y]) ax[x,y].ya xis.label.set_size(15) else: sns.boxplot(data=df, x=col, y=''Selli ng_Price'', ax=ax[x,y]) ax[x,y].xaxis.label.set_size(15) ax[x,y].y axis.label.set_size(15)plt.tight_layout()plt.show()用于查找每列中的异常值并将其 绘制为图表的代码?数据集中的异常值确定让我们尝试使用四分位数范围规则来查找异常值。这是基于四分位数的概念,将数据集分为四个相等的部 分。IQR(四分位数范围规则)规则特别关注数据中间 50% 内的值范围,并使用该范围来识别潜在的异常值。我们必须找到分类列中每个唯 一值的最小和最大分位数值,并过滤掉不适合目标列(销售价格)第 25 个和 75 个百分位的异常值样本。另一方面,数值列中的异常值可 以通过同一列的第 25 个和第 75 个百分位数进行过滤。我们不需要针对目标列进行过滤。outliers_indexes = [] target = ''Selling_Price''for col in df.select_dtypes(include=''obje ct'').columns: for cat in df[col].unique(): df1 = df[df[col] == ca t] q1 = df1[target].quantile(0.25) q3 = df1[target].quantile(0.75 ) iqr = q3-q1 maximum = q3 + (1.5 iqr) minimum = q1 - (1.5 iq r) outlier_samples = df1[(df1[target] < minimum) | (df1[target] > maximum)] outliers_indexes.extend(outlier_samples.index.tolist() ) for col in df.select_dtypes(exclude=''object'').columns: q1 = df [col].quantile(0.25) q3 = df[col].quantile(0.75) iqr = q3-q1 maxi mum = q3 + (1.5 iqr) minimum = q1 - (1.5 iqr) outlier_samples = df[(df[col] < minimum) | (df[col] > maximum)] outliers_indexes .extend(outlier_samples.index.tolist()) outliers_indexes = list(s et(outliers_indexes))print(''{} outliers were identified, whose in dices are:\n\n{}''.format(len(outliers_indexes), outliers_indexes) )显示检测到的异常值的索引的代码通过运行上面的代码,我们发现数据集中有 38 个异常值。?但请记住,删除异常值并不总是正确的决定。 它们可以是合理的观察结果,在决定是否丢弃异常值之前调查异常值的性质非常重要。我们可以在两种情况下删除异常值:异常值是由于错误输入或 测量的数据造成的异常值产生显着关联让我们进一步挖掘并找到完美的异常值。为此,我们假设如果售价超过 330 万卢比,或者汽车的行驶里 程超过 40 万公里,那么这些都是异常值。我们将它们标记为绿色。保存变量中的所有索引removing_indices。使用库以散点 图格式绘制它们seaborn,将每列与我们的目标列进行比较。# Outliers Labelingdf1 = df.copy()d f1[''label''] = ''Normal''df1.loc[outliers_indexes,''label''] = ''Outlie r''# Removing Outliersremoving_indexes = []removing_indexes.extend (df1[df1[target]>33].index)removing_indexes.extend(df1[df1[''Kms_D riven'']>400000].index)df1.loc[removing_indexes,''label''] = ''Removi ng''# Plottarget = ''Selling_Price''features = df.columns.drop(targe t)colors = [''#0055ff'',''#ff7000'',''#23bf00'']CustomPalette = sns.set _palette(sns.color_palette(colors))fig, ax = plt.subplots(nrows=3 ,ncols=3, figsize=(15,12), dpi=200)for i in range(len(features)) : x=i//3 y=i%3 sns.scatterplot(data=df1, x=features[i], y=target, hue=''label'', ax=ax[x,y]) ax[x,y].set_title(''{} vs. {}''.format(ta rget, features[i]), size = 15) ax[x,y].set_xlabel(features[i], si ze = 12) ax[x,y].set_ylabel(target, size = 12) ax[x,y].grid()ax[2 , 1].axis(''off'')ax[2, 2].axis(''off'')plt.tight_layout()plt.show()用 绿色绘制最佳异常值的代码? 异常值用绿色标记让我们看看完美的异常值:removing_indexes = list(set(rem oving_indexes))removing_indexes列出最佳异常值的代码?原始异常值指数列表我们有 2 个。我们必须删除 它们。但在此之前,我们必须检查数据集中是否存在空数据。df.isnull().sum()查找每列中空条目的数量我们的数据集中没有空 值。?数据集中没有空值让我们删除已识别的异常值并重置数据帧的索引。df1 = df.copy()df1.drop(removing _indexes, inplace=True)df1.reset_index(drop=True, inplace=True)从数 据框中删除异常值分析数据集让我们分析一下数据,看看每个字段/类别与汽车的售价有多少相关性。我们需要对我们的数据集进行一些分析才能得 出一些结论。为此,我们必须识别数据集中的数值和分类字段,因为每种类型的绘制方法都不同。NumCols = [''Age'', ''Sel ling_Price'', ''Present_Price'', ''Kms_Driven'', ''Owner'']CatCols = [''F uel_Type'', ''Seller_Type'', ''Transmission'']数字和分类列的列表双变量分析如果您不熟悉什么是双 变量分析,https://en.wikipedia.org/wiki/Bivariate_analysis这里有一个基本定义:双变 量分析是最简单的定量分析形式之一。它涉及对两个变量的分析,以确定它们之间的经验关系。双变量分析有助于检验简单的关联假设。让我们使用 双变量分析将销售价格与其他列进行比较,并尝试从该数据中得出一些结论。销售价格与数字特征双变量分析让我们使用双变量分析将数值特征与销 售价格进行比较。数值列将绘制在散点图中。fig, ax = plt.subplots(nrows=2 ,ncols=2, figs ize=(10,10), dpi=90)num_features = [''Present_Price'', ''Kms_Driven'' , ''Age'', ''Owner'']target = ''Selling_Price''c = ''#0055ff''for i in ra nge(len(num_features)): row = i//2 col = i%2 ax[row,col].scatter( df1[num_features[i]], df1[target], color=c, edgecolors=''w'', linew idths=0.25) ax[row,col].set_title(''{} vs. {}''.format(target, num_ features[i]), size = 12) ax[row,col].set_xlabel(num_features[i], size = 12) ax[row,col].set_ylabel(target, size = 12) ax[row,col]. grid()plt.suptitle(''Selling Price vs. Numerical Features'', size = 20)plt.tight_layout()plt.show()数值列与售价的比较? 销售价格与数字特征双变量分析销售价格与分类特 征双变量分析让我们使用双变量分析将分类特征与销售价格进行比较。分类列将绘制在带状图中。这给出了类别中多个值之间的比较。fig, a xes = plt.subplots(nrows=1 ,ncols=3, figsize=(12,5), dpi=100)cat_ features = [''Fuel_Type'', ''Seller_Type'', ''Transmission'']target = '' Selling_Price''c = ''#0055ff''for i in range(len(cat_features)): sns .stripplot(ax=axes[i], x=cat_features[i], y=target, data=df1, siz e=6, color=c) axes[i].set_title(''{} vs. {}''.format(target, cat_fe atures[i]), size = 13) axes[i].set_xlabel(cat_features[i], size = 12) axes[i].set_ylabel(target, size = 12) axes[i].grid()plt.supt itle(''Selling Price vs. Categorical Features'', size = 20)plt.tigh t_layout()plt.show()分类列与售价的比较? 销售价格与分类特征双变量分析以下是我们从数据分析中可以得出的结论:随 着现价上涨,售价也会上涨。它们是成正比的。销售价格与行驶公里数成反比。售价与汽车的车龄成反比。随着旧车拥有者数量的增加,其售价会下 降。所以售价与所有者成反比。就售价而言,柴油车 > CNG 汽车 > 汽油车。个人销售汽车的销售价格低于经销商销售汽车的价格。自动 挡汽车比手动挡汽车贵。分类变量编码我们不能按原样使用分类字段。它们必须转换为数字,因为机器只能理解数字。我们以“燃料”列为例。根据 我们的数据集,我们的汽车使用两种燃料。它们是汽油和柴油。分类变量编码会将燃料列分为 2 列(Fuel_Type_Petrol 和 Fuel_Type_Diesel)。假设一辆汽车使用汽油。对于此汽车,数据将转换为 Fuel_Type_Petrol 列设置为 1 (True),Fuel_Type_Diesel 列设置为 0 (False)。计算机可以理解 1 和 0,而不是“汽油”和“柴油 ”。为此,我们将对分类列执行 one-hot 编码。Pandas 提供了get_dummies对列进行编码的方法。CatCols = [''Fuel_Type'', ''Seller_Type'', ''Transmission'']df1 = pd.get_dummie s(df1, columns=CatCols, drop_first=True)df1.head(5)对分类列进行 One-Hot 编码? 分类变量编码假设True和分别False是0和。1相关性分析相关矩阵是总结数据集中变量对之间线性关系的强度和方向的矩阵。 它是统计和数据分析中的重要工具,用于检查变量之间的关联模式并了解它们如何相关。如果值为正,则相关性为正比;如果值为负,则相关性为反 比。这是查找与销售价格相关的相关矩阵的代码。target = ''Selling_Price''cmap = sns.divergin g_palette(125, 28, s=100, l=65, sep=50, as_cmap=True)fig, ax = pl t.subplots(figsize=(9, 8), dpi=80)ax = sns.heatmap(pd.concat([df1 .drop(target,axis=1), df1[target]],axis=1).corr(), annot=True, cm ap=cmap)plt.show()绘制相关矩阵?相关矩阵从上面的矩阵中,我们可以推断出目标变量“销售价格”与当前价格、卖家类型和 燃料类型高度相关。如何构建模型我们已经到了最后阶段。让我们训练和测试我们的模型。让我们从输入中删除“Selling_Price”并 将其设置为输出。这意味着它必须被预测。X = df1.drop(''Selling_Price'', axis=1)y = df1['' Selling_Price'']将输入和输出(销售价格)拆分为单独的数据帧让我们分割数据集,将 70% 的数据用于训练,30% 的数 据用于测试。X_train, X_test, y_train, y_test = train_test_split(X, y, t est_size=0.3, random_state=0)将原始数据集拆分为测试数据集和训练数据集让我们备份我们的测试数据。我们需 要这个来进行最终比较。y_test_actual = y_test拥有原始输出的副本标准化数据集这StandardScaler是机 器学习和数据分析中常用的一种预处理技术,用于标准化或规范化数据集的特征(变量)。其主要目的是转换数据,使每个特征的平均值为 0,标 准差为 1。让我们使用 标准化我们的数据集StandardScaler。scaler = StandardScaler()scal er.fit(X_train)X_train_scaled = scaler.transform(X_train)X_test_s caled = scaler.transform(X_test)标准化输入数据集非常重要的是,StandardScaler变换只能 从训练集中获得,否则会导致数据泄漏。训练模型linear_reg = LinearRegression()linear_reg.f it(X_train_scaled, y_train)训练模型让我们找到训练数据集中每列的截距和系数。pd.DataFrame(d ata = np.append(linear_reg.intercept_ , linear_reg.coef_), index = [''Intercept'']+[col+" Coef." for col in X.columns], columns=[''Va lue'']).sort_values(''Value'', ascending=False)求斜率和截距? 斜率和截距值如何评估模型S cikit Learn 提供了指标功能,可以帮助我们衡量模型的指标。我们可以用它来确定指标,包括均方误差、平均绝对误差、均方根误差 和 R2 分数。现在是时候评估模型了:def model_evaluation(model, X_test, y_test, mo del_name): y_pred = model.predict(X_test) MAE = metrics.mean_abs olute_error(y_test, y_pred) MSE = metrics.mean_squared_error(y_te st, y_pred) RMSE = np.sqrt(MSE) R2_Score = metrics.r2_score(y_tes t, y_pred) return pd.DataFrame([MAE, MSE, RMSE, R2_Score], index =[''MAE'', ''MSE'', ''RMSE'' ,''R2-Score''], columns=[model_name])model_e valuation(linear_reg, X_test_scaled, y_test, ''Linear Reg.'')模型评估? 模型评估使用 K 折交叉验证评估模型在 k 折交叉验证中,数据集被分为 k 个大小大致相等的子集或“折叠”。该模型被训练和评估 k 次,每次使用不同的折叠作为验证集,剩余的折叠作为训练集。然后对这 k 次运行的结果(例如准确度、误差)进行平均,以获得对模型性能 的更稳健的估计。优点是每个数据点都用于训练和验证,降低了评估中的偏差风险。linear_reg_cv = LinearRegres sion()scaler = StandardScaler()pipeline = make_pipeline(StandardS caler(), LinearRegression())kf = KFold(n_splits=6, shuffle=True, random_state=0) scoring = [''neg_mean_absolute_error'', ''neg_mean_ squared_error'', ''neg_root_mean_squared_error'', ''r2'']result = cros s_validate(pipeline, X, y, cv=kf, return_train_score=True, scorin g=scoring)MAE_mean = (-result[''test_neg_mean_absolute_error'']).me an()MAE_std = (-result[''test_neg_mean_absolute_error'']).std()MSE_ mean = (-result[''test_neg_mean_squared_error'']).mean()MSE_std = ( -result[''test_neg_mean_squared_error'']).std()RMSE_mean = (-result [''test_neg_root_mean_squared_error'']).mean()RMSE_std = (-result['' test_neg_root_mean_squared_error'']).std()R2_Score_mean = result['' test_r2''].mean()R2_Score_std = result[''test_r2''].std()pd.DataFram e({''Mean'': [MAE_mean,MSE_mean,RMSE_mean,R2_Score_mean], ''Std'': [MAE_std,MSE_std,RMSE_std,R2_Score_std]}, index=[''MAE'', ''MSE'', ''RMSE'' ,''R2-Score''])使用 K 折交叉验证进行模型评估? 使用交叉验证进行模型评估结果可视化让我们使用实际值和预测值创建一个数据框。y_test_pred = linear_reg.predict(X_test_scaled)df_comp = pd.DataFrame({''Actual'':y_test_actual, ''Predicted'':y_test_pred})创建具有实际值和预测值的数据框让我们借助条形图来比较测试数据的实际目标值和预测目标值。def compare_plot(df_comp): df_comp.reset_index(inplace=True) df_comp.plot(y=[''Actual'',''Predicted''], kind=''bar'', figsize=(20,7), width=0.8) plt.title(''Predicted vs. Actual Target Values for Test Data'', fontsize=20) plt.ylabel(''Selling_Price'', fontsize=15) plt.show()compare_plot(df_comp)在图表中绘制预测值与实际值? 实际值与预测值的比较在上图中,蓝线表示实际价格,橙色线表示汽车的预测价格。您可以看到一些预测值为负。但在大多数情况下,我们的模型都很好地预测了这一点。这不是完美的模型。但如果您想对其进行微调以做出更好的预测,如果我收到更多请求,我会写一篇相关教程。结论在本教程中,您通过实际示例了解了线性回归。我希望它能帮助您在 ML 之旅中取得进步。? |
|