🤵♂️ 个人主页:@艾派森的个人主页
✍🏻作者简介:Python学习者
🐋 希望大家多多支持,我们一起进步!😄
如果文章对你有帮助的话,
欢迎评论 💬点赞👍🏻 收藏 📂加关注+
喜欢大数据分析项目的小伙伴,希望可以多多支持该系列的其他文章
大数据分析案例-基于随机森林算法预测人类预期寿命 |
大数据分析案例-基于随机森林算法的商品评价情感分析 |
大数据分析案例-用RFM模型对客户价值分析(聚类) |
大数据分析案例-对电信客户流失分析预警预测 |
大数据分析案例-基于随机森林模型对北京房价进行预测 |
大数据分析案例-基于RFM模型对电商客户价值分析 |
大数据分析案例-基于逻辑回归算法构建垃圾邮件分类器模型 |
大数据分析案例-基于决策树算法构建员工离职预测模型 |
大数据分析案例-基于KNN算法对茅台股票进行预测 |
大数据分析案例-基于多元线性回归算法构建广告投放收益模型 |
大数据分析案例-基于随机森林算法构建返乡人群预测模型 |
大数据分析案例-基于决策树算法构建金融反欺诈分类模型 |
目录
1.项目背景
2.项目简介
2.1项目说明
2.2数据说明
2.3技术工具
3.算法原理
4.项目实施步骤
4.1理解数据
4.2数据预处理
4.3探索性数据分析
4.4特征工程
4.5模型构建
4.6参数调优
4.7模型评估
5.实验总结
源代码
1.项目背景
随着科技的飞速发展和人们对数字化生活的追求,笔记本电脑已经成为了现代社会中不可或缺的重要工具。无论是学生、专业人士还是普通消费者,笔记本电脑都在其日常生活中扮演着重要角色。然而,随着市场上笔记本电脑品牌和型号的日益增多,消费者在选择合适的产品时常常感到困惑。除了关注产品的性能、配置和外观设计外,价格往往是消费者决策的关键因素之一。
在这样一个市场环境下,能够准确预测笔记本电脑价格的技术和工具显得尤为重要。这不仅可以帮助消费者做出更明智的购买决策,还能为制造商和销售商提供市场分析和定价策略的重要参考。近年来,机器学习算法在数据分析和预测领域展现出了强大的能力,其中XGBoost算法以其高效、准确和灵活的特性而备受关注。
XGBoost(Extreme Gradient Boosting)是一种基于梯度提升决策树的优化算法,它通过并行处理和正则化等技术手段,有效提高了模型的训练速度和预测精度。该算法在处理结构化数据方面表现出色,特别适用于解决回归和分类问题。在笔记本电脑价格预测领域,XGBoost算法可以充分利用产品的各种属性(如处理器型号、内存容量、硬盘容量、屏幕尺寸等)以及市场数据(如竞争对手的定价、市场需求等)来构建预测模型,从而实现对产品价格的准确预测。
2.项目简介
2.1项目说明
本研究旨在利用XGBoost算法构建笔记本电脑价格预测模型,以期为消费者提供更有价值的购买建议,并为制造商和销售商提供市场分析和定价策略的支持。通过这一研究,我们希望能够推动机器学习算法在电子产品价格预测领域的应用和发展,为市场参与者提供更准确、更全面的数据支持。
2.2数据说明
本实验数据集来源于Kaggle,原始数据集共有1303条数据,13个变量,各变量含义如下:
0 laptop_ID-数字-产品ID
1 Company-字符串-笔记本电脑制造商
2 Product-字符串-品牌和型号
3 TypeName-字符串-类型(笔记本电脑、超极本、游戏机等)
4 Inches-数字-屏幕尺寸
5 ScreenResolution-字符串-屏幕分辨率
6 Cpu-字符串-中央处理器 (CPU)
7 Ram-字符串-笔记本电脑 RAM
8 Memory-字符串-硬盘/SSD 内存
9 GPU-字符串-图形处理单元 (GPU)
10 OpSys-字符串-操作系统
11 Weight-字符串-笔记本电脑重量
12 Price_euros-数字-价格(欧元)
2.3技术工具
Python版本:3.9
代码编辑器:jupyter notebook
3.算法原理
XGBoost(Extreme Gradient Boosting)是一种基于决策树集成的机器学习算法,它使用梯度提升方法(Gradient Boosting)来训练决策树。XGBoost的主要优点是速度快,准确性高,可扩展性好,因此在机器学习和数据科学领域中非常流行。
下面是XGBoost的算法原理:
1.损失函数:
XGBoost的目标是最小化损失函数,其中损失函数由两个部分组成:正则化项和目标函数。正则化项用于防止过拟合,目标函数用于衡量模型预测结果与实际结果之间的误差。常见的目标函数包括平方误差损失函数、Logistic损失函数等。
2.决策树:
XGBoost使用决策树作为基本模型,而不是使用传统的线性模型。决策树由节点和叶子节点组成,每个节点表示一个特征,每个叶子节点表示一个类别或一个实数值。决策树是通过递归地将数据集分割为越来越小的子集来构建的。
3.梯度提升:
XGBoost使用梯度提升方法训练决策树模型。梯度提升是一种迭代的方法,每次迭代都训练一个新的决策树模型,它的预测结果与前面所有模型的预测结果相加得到最终的预测结果。在每一次迭代中,XGBoost计算残差的梯度,并用残差更新目标函数。然后,XGBoost使用这个更新后的目标函数训练一个新的决策树模型。
4.正则化:
XGBoost通过正则化方法防止过拟合。常用的正则化方法包括L1正则化和L2正则化。L1正则化可以使得一些决策树的权重为0,从而剪枝一些不必要的决策树。L2正则化可以使得决策树的权重变得更加平滑,从而提高模型的泛化能力。
5.优化算法:
XGBoost使用了一些优化算法来提高训练速度和准确性。其中最重要的优化算法是加权梯度下降算法(Weighted Gradient Descent)。加权梯度下降算法可以根据损失函数的梯度和二阶导数来自适应地调整学习率,从而提高模型的准确性。
XGBoost算法的具体步骤如下:
-
初始化模型。设定迭代次数,学习率和决策树的深度等超参数。
-
对于每一次迭代:
a. 计算负梯度。根据当前模型在训练数据上的表现,计算每个样本的负梯度,用于构建下一棵决策树。
b. 构建决策树。根据负梯度的大小,构建一棵新的决策树。
c. 计算叶子节点权重。对于每个叶子节点,计算它的权重,以最小化损失函数。
d. 更新模型。将新的决策树加入模型,并根据学习率更新模型参数。
-
返回最终的模型。
XGBoost的优点在于它的泛化能力强,可以处理高维度、稀疏数据,并且有很好的防止过拟合的机制。同时,它的速度也非常快,可以处理大规模的数据集。因此,XGBoost已经成为了机器学习领域中应用最广泛的算法之一。
4.项目实施步骤
4.1理解数据
导入数据分析第三方库
导入数据集
查看数据大小
查看数据基本信息
查看数值型变量的描述性统计
查看非数值型变量的描述性统计
4.2数据预处理
统计缺失值情况
发现没有缺失值
统计重复值情况
发现没有重复值
复制数据集并删除无关的变量
变量处理
三星的CPU是一个不必要的异常值,所以我们将删除它。
这里我们有4种不同类型的内存:SSD, HDD, Flash Storage和Hybrid。我们可以提取存储类型和内存。
4.3探索性数据分析
4.4特征工程
首先需要对非数值型变量进行编码处理,接着准备建模数据X和y,最后拆分数据集为训练集和测试集
4.5模型构建
构建xgboost模型并打印模型指标
4.6参数调优
自定义一个参数优化的函数
最终得到了最佳模型参数
4.7模型评估
可视化模型特征重要性
绘制残差图
5.实验总结
经过实验验证,基于XGBoost算法构建的笔记本电脑价格预测模型取得了显著的效果。该模型能够准确捕捉笔记本电脑价格与其各项属性之间的复杂关系,并有效整合市场数据,实现了对笔记本电脑价格的精准预测。
实验结果表明,XGBoost算法在预测精度、稳定性和泛化能力方面均表现出色。与其他传统预测方法相比,该模型不仅预测误差更低,而且能够更好地适应不同品牌和型号的笔记本电脑,显示出强大的灵活性和适应性。
通过该实验,我们证明了机器学习算法在电子产品价格预测领域的巨大潜力。基于XGBoost算法的预测模型不仅能够为消费者提供有价值的购买建议,还能为制造商和销售商提供准确的市场分析和定价策略支持,有助于他们更好地了解市场需求和竞争态势,制定更加科学合理的市场策略。
心得与体会:
通过这次Python项目实战,我学到了许多新的知识,这是一个让我把书本上的理论知识运用于实践中的好机会。原先,学的时候感叹学的资料太难懂,此刻想来,有些其实并不难,关键在于理解。
在这次实战中还锻炼了我其他方面的潜力,提高了我的综合素质。首先,它锻炼了我做项目的潜力,提高了独立思考问题、自我动手操作的潜力,在工作的过程中,复习了以前学习过的知识,并掌握了一些应用知识的技巧等
在此次实战中,我还学会了下面几点工作学习心态:
1)继续学习,不断提升理论涵养。在信息时代,学习是不断地汲取新信息,获得事业进步的动力。作为一名青年学子更就应把学习作为持续工作用心性的重要途径。走上工作岗位后,我会用心响应单位号召,结合工作实际,不断学习理论、业务知识和社会知识,用先进的理论武装头脑,用精良的业务知识提升潜力,以广博的社会知识拓展视野。
2)努力实践,自觉进行主角转化。只有将理论付诸于实践才能实现理论自身的价值,也只有将理论付诸于实践才能使理论得以检验。同样,一个人的价值也是透过实践活动来实现的,也只有透过实践才能锻炼人的品质,彰显人的意志。
3)提高工作用心性和主动性。实习,是开端也是结束。展此刻自我面前的是一片任自我驰骋的沃土,也分明感受到了沉甸甸的职责。在今后的工作和生活中,我将继续学习,深入实践,不断提升自我,努力创造业绩,继续创造更多的价值。
这次Python实战不仅仅使我学到了知识,丰富了经验。也帮忙我缩小了实践和理论的差距。在未来的工作中我会把学到的理论知识和实践经验不断的应用到实际工作中,为实现理想而努力。
源代码
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import optuna
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
import xgboost as xgb
from xgboost import XGBRegressor
from xgboost import plot_importance
import warnings
warnings.filterwarnings('ignore')laptop_price = pd.read_csv('laptop_price.csv', encoding='latin-1')
laptop_price.head()
laptop_price.shape
laptop_price.info()
laptop_price.describe()
laptop_price.describe(include='O')
laptop_price.isnull().sum()
laptop_price.duplicated().sum()
df = laptop_price
df = df.drop(['laptop_ID', 'Product'], axis=1)
# 仅从ScreenResolution列中提取分辨率
df['PPI'] = df['ScreenResolution'].str.extract(r'(\d+x\d+)')
# 创建宽度和高度来计算PPI
df[['Width', 'Height']] = df['PPI'].str.split('x', expand=True).astype('int')
# 计算PPI
df['PPI'] = (((df['Width']**2 + df['Height']**2)**0.5)/df['Inches']).round(2)
# 创建基于术语“触摸屏”的触摸屏专栏
df['Touchscreen'] = df['ScreenResolution'].str.contains('Touchscreen', case=False, regex=True).astype(int)
# 我们可以删除不需要的列
df = df.drop(['Height', 'Width', 'ScreenResolution'], axis=1)
# 提取Ghz数
df['Cpu_Ghz'] = df['Cpu'].str.extract(r'(\d+(\.\d+)?)GHz')[0].astype(float)
# 提取制造商名称
df['Cpu_Manufacturer'] = df['Cpu'].str.split(' ').str[0]
df['Cpu_Manufacturer'].value_counts()
三星的CPU是一个不必要的异常值,所以我们将放弃它。
# 去除异常值并删除Cpu变量
df = df[df['Cpu_Manufacturer'] != 'Samsung']
df = df.drop(['Cpu'], axis=1)
# 从“Ram”列中提取数值
df['Ram'] = df['Ram'].str[:-2].astype(int)
df['Memory'].unique()
这里我们有4种不同类型的内存:SSD, HDD, Flash Storage和Hybrid。我们可以提取存储类型和内存。
df['Memory'] = df['Memory'].str.replace('1TB', '1024GB')
df['Memory'] = df['Memory'].str.replace('1.0TB', '1024GB')
df['Memory'] = df['Memory'].str.replace('2TB', '2048GB')
df['Memory'] = df['Memory'].str.replace('GB', '')
df['Memory'] = df['Memory'].str.replace(' ', '')df['Storage_1_Type'] = ''
df['Storage_1_Memory'] = 0
df['Storage_2_Type'] = ''
df['Storage_2_Memory'] = 0storage_types = ['SSD', 'HDD', 'Flash', 'Hybrid']# Storage_1
for storage_type in storage_types:condition = df['Memory'].str.contains(storage_type, case=False, regex=True)df.loc[condition & (df['Storage_1_Type'] == ''), 'Storage_1_Type'] = storage_typedf.loc[condition & (df['Storage_1_Memory'] == 0), 'Storage_1_Memory'] = df['Memory'].str.extract(f'(\d+) {storage_type}', expand=False).astype(float)df['Second_Storage'] = df['Memory'].str.extract(r'(\+\s?\d+\s?\w+)', expand=False).fillna('')
df['Has_Second_Storage'] = df['Second_Storage'].apply(lambda x: False if x == '' else True)# Storage_2
for storage_type in storage_types:condition = df['Second_Storage'].str.contains(storage_type, case=False, regex=True)df.loc[condition & (df['Storage_2_Type'] == ''), 'Storage_2_Type'] = storage_typedf.loc[condition & (df['Storage_2_Memory'] == 0), 'Storage_2_Memory'] = df['Second_Storage'].str.extract(f'(\d+) {storage_type}', expand=False).astype(float)# 删除不必要的列
df.drop(['Memory', 'Second_Storage', 'Has_Second_Storage'], axis=1, inplace=True)
# 提取制造商名称
df['Gpu_Manufacturer'] = df['Gpu'].str.split(' ').str[0]
df = df.drop(['Gpu'], axis=1)
# 提取出重量数字
df['Weight'] = df['Weight'].str[:-2].astype(float)
df.head()
# 按公司划分的产品数量
plt.figure(figsize=(8, 5))
sns.countplot(x='Company', data=df, order=df['Company'].value_counts().index, palette='crest')
plt.xticks(rotation=45, ha='right')
plt.title('Number of Products by Company', fontsize=10)
plt.xlabel('Company', fontsize=8)
plt.ylabel('Number of Products', fontsize=8)
plt.xticks(fontsize=8)
plt.yticks(fontsize=8)
plt.show()
# 按TypeName, Ram, OpSys划分的产品数量
columns_to_plot = ['TypeName', 'Ram', 'OpSys']plt.figure(figsize=(10, 4))for i, feature in enumerate(columns_to_plot):plt.subplot(1, 3, i + 1)sns.countplot(x=feature, data=df, order=df[feature].value_counts().index, palette='crest')plt.title(f'Number of Products by {feature}', fontsize=10)plt.xlabel(feature, fontsize=8)plt.ylabel('Number of Products', fontsize=8)if i == 0 or i == 2:plt.tick_params(rotation=45, axis='both', labelsize=8)else:plt.tick_params(axis='both', labelsize=8)plt.tight_layout()
plt.show()
# 重量分布
plt.figure(figsize=(8, 3))
sns.histplot(df['Weight'], color='navy', bins=8, alpha=0.6)
plt.title('Distribution of Weight')
plt.xlabel('Weight')
plt.ylabel('Frequency')
plt.show()
# CPU和GPU厂商
features = ['Cpu_Manufacturer', 'Gpu_Manufacturer']
plt.figure(figsize=(8, 3))for i, feature in enumerate(features, 1):plt.subplot(1, 2, i)sns.countplot(x=feature, data=df, order=df[feature].value_counts().index, palette='crest')plt.title(f'Count of Products by {feature}', fontsize=10)plt.xlabel('Number of Products', fontsize=8)plt.ylabel(feature, fontsize=8)plt.xticks(fontsize=8)plt.yticks(fontsize=8)
plt.tight_layout()
plt.show()
# 按内存类型划分的产品数量
features = ['Storage_1_Type', 'Storage_2_Type']
plt.figure(figsize=(8, 3))for i, feature in enumerate(features, 1):plt.subplot(1, 2, i)sns.countplot(x=feature, data=df, order=df[feature].value_counts().index, palette='crest')plt.title(f'Count of Products by {feature}', fontsize=10)plt.xlabel('Number of Products', fontsize=8)plt.ylabel(feature, fontsize=8)plt.xticks(fontsize=8)plt.yticks(fontsize=8)
plt.tight_layout()
plt.show()
# 存储内存,重量,PPI,英寸和价格的分布
features = ['Storage_1_Memory', 'Storage_2_Memory', 'Weight', 'PPI', 'Inches', 'Price_euros']plt.figure(figsize=(15, 10))for i, feature in enumerate(features, 1):plt.subplot(2, 3, i)sns.histplot(df[feature].dropna(), kde=True, color='navy', bins='auto', alpha=0.6)plt.title(f'Histogram of {feature}')plt.xlabel(feature)plt.ylabel('Frequency')plt.tight_layout()
plt.show()
# 各公司平均价格
plt.figure(figsize=(12, 6))
order_by_mean_price = df.groupby('Company')['Price_euros'].mean().sort_values(ascending=False).index
sns.barplot(x='Company', y='Price_euros', data=df, palette='crest', order=order_by_mean_price)
plt.title('Mean Price by Company')
plt.xlabel('Company')
plt.ylabel('Mean Price (euros)')
plt.xticks(rotation=45, ha='right')
plt.show()
# 价格与PPI、Ram和Cpu_Ghz的关系
columns_to_plot = ['PPI', 'Ram', 'Cpu_Ghz']plt.figure(figsize=(8, 3))for i, feature in enumerate(columns_to_plot):plt.subplot(1, 3, i + 1)sns.scatterplot(x=feature, data=df, y='Price_euros', color='navy', alpha=0.6)plt.title(f'{feature}', fontsize=10)plt.xlabel(feature, fontsize=8)if i == 0:plt.ylabel('Price euros', fontsize=8)else: plt.ylabel('')plt.tick_params(axis='both', labelsize=8)plt.tight_layout()
plt.show()
# 箱线图:Cpu_Manufacturer和Gpu_Manufacturer与价格
plt.figure(figsize=(8, 4))for i, feature in enumerate(['Cpu_Manufacturer', 'Gpu_Manufacturer']):plt.subplot(1, 2, i + 1)sns.boxplot(x=feature, y='Price_euros', data=df, palette='crest')plt.title(f'{feature} vs. Price', fontsize=10)plt.xlabel(feature, fontsize=8)if i == 0:plt.ylabel('Price euros', fontsize=8)else: plt.ylabel('')plt.tick_params(axis='both', labelsize=8)plt.tight_layout()
plt.show()
# 相关矩阵
numerical_columns = df.select_dtypes(include=['int', 'float']).columns
corr_matrix = df[numerical_columns].corr()
plt.figure(figsize=(12, 10))
sns.heatmap(corr_matrix, annot=True, cmap='crest', fmt=".2f", linewidths=.5)
plt.title('Correlation Matrix', fontsize=10)
plt.xticks(rotation=45, fontsize=8)
plt.yticks(fontsize=8)
plt.show()
import plotly.express as px
fig = px.sunburst(df, path=['Company','Ram','TypeName'], values='Price_euros',color='Price_euros')
fig.update_layout(margin = dict(t=0, l=0, r=0, b=0))
fig.show()
columns = ['Company', 'TypeName','OpSys', 'Cpu_Manufacturer', 'Gpu_Manufacturer', 'Storage_1_Type', 'Storage_2_Type']
# 编码chu
label_encoder = LabelEncoder()
for col in columns:df[col] = label_encoder.fit_transform(df[col])X = df.drop(['Price_euros'], axis=1)
y = df['Price_euros']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.20, random_state = 42)
xgb_model = XGBRegressor(random_state=42)
xgb_model.fit(X_train, y_train)
y_base = xgb_model.predict(X_test)mse = mean_squared_error(y_test, y_base)
rmse = mean_squared_error(y_test, y_base, squared=False)
mae = mean_absolute_error(y_test, y_base)
r2 = r2_score(y_test, y_base)metrics_df = pd.DataFrame({'Metric': ['Mean Squared Error', 'Root Mean Squared Error', 'Mean Absolute Error', 'R-squared'],'Base': [mse, rmse, mae, r2]
})
metrics_df
def objective(trial):params = {'objective': 'reg:squarederror','eval_metric': 'rmse','n_jobs': -1,'learning_rate': trial.suggest_float('learning_rate', 0.01, 0.3),'n_estimators': trial.suggest_int('n_estimators', 50, 2000),'max_depth': trial.suggest_int('max_depth', 3, 10),'min_child_weight': trial.suggest_int('min_child_weight', 1, 10),'subsample': trial.suggest_float('subsample', 0.5, 1),'colsample_bytree': trial.suggest_float('colsample_bytree', 0.5, 1),'gamma': trial.suggest_float('gamma', 0, 1),'reg_alpha': trial.suggest_float('reg_alpha', 0, 1),'reg_lambda': trial.suggest_float('reg_lambda', 0, 1)}model = xgb.XGBRegressor(**params, random_state=42)model.fit(X_train, y_train)y_pred = model.predict(X_test)rmse = mean_squared_error(y_test, y_pred, squared=False)return rmse
study = optuna.create_study(direction='minimize')
study.optimize(objective, n_trials=100)best_params = study.best_params
final_model = xgb.XGBRegressor(**best_params, random_state=42)
final_model.fit(X_train, y_train)y_pred = final_model.predict(X_test)final_rmse = mean_squared_error(y_test, y_pred, squared=False)print(f"Best Parameters: {best_params}")
print(f"Final Root Mean Squared Error: {final_rmse}")
rmse_values = [trial.value for trial in study.trials]
trial_numbers = [trial.number for trial in study.trials]data = {'RMSE': rmse_values, 'Trials': trial_numbers}
df_plot = pd.DataFrame(data)sns.set(style="whitegrid")
plt.figure(figsize=(8, 5))
sns.lineplot(x='Trials', y='RMSE', data=df_plot)
plt.title('RMSE vs. Trials')
plt.xlabel('Trials')
plt.ylabel('Root Mean Squared Error (RMSE)')
plt.show()
mse = mean_squared_error(y_test, y_pred)
rmse = mean_squared_error(y_test, y_pred, squared=False)
mae = mean_absolute_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)metrics_df['Tuned'] = [mse, rmse, mae, r2]
metrics_df
plt.scatter(y_test, y_pred)
plt.xlabel('True Values')
plt.ylabel('Predictions')
plt.title('True Values vs. Predictions')
plt.show()
# 特征重要性
plot_importance(final_model)
plt.show()
# 残差
residuals = y_test - y_pred
plt.scatter(y_pred, residuals)
plt.axhline(y=0, color='r', linestyle='--')
plt.xlabel('Predicted Values')
plt.ylabel('Residuals')
plt.title('Residual Plot')
plt.show()
sns.kdeplot(y_test, label='Actual', color='cyan')
sns.kdeplot(y_pred, label='Predicted', color='red')
plt.xlabel('Values')
plt.ylabel('Density')
plt.title('Distribution of Actual vs Predicted Values')
plt.legend()
plt.show()