python 二手车数据分析以及价格预测

news2024/10/5 22:22:33

二手车交易信息爬取、数据分析以及交易价格预测

  • 引言
  • 一、数据爬取
    • 1.1 解析数据
    • 1.2 编写代码爬
      • 1.2.1 获取详细信息
      • 1.2.2 数据处理
  • 二、数据分析
    • 2.1 统计分析
    • 2.2 可视化分析
  • 三、价格预测
    • 3.1 价格趋势分析(特征分析)
    • 3.2 价格预测

引言

本文着眼于车辆信息,结合当下较为火热的二手车交易市场数据,对最近二手车的交易价格进行分析以及预测。
经过前期调研,最终决定通过爬取一些网站的二手车数据和一些公开的数据集,分析交易数据的特征,根据交易特征对二手车交易价格进行分析预测。
本文主要核心内容:数据爬取数据分析交易价格预测

一、数据爬取

1.1 解析数据

  1. 选择二手车交易网站-瓜子二手车。点开官网,点击我要买车。以QQ浏览器为例,点击开发者工具(菜单-工具中),选择Network-DOC过滤。获取头部cookie等相关信息,如下图所示。
    在这里插入图片描述
  2. 通过搜索框(点击开发者工具页面右上角 ‘竖着的三个点’ - Search),输入页面商品名称和属性名称,获取想要数据的位置,方便后续爬取解析,如下图所示。
    在这里插入图片描述
  3. 根据以上获取的信息构造程序的headers以及编写具体数据的爬取代码

1.2 编写代码爬

1.2.1 获取详细信息

# 获取详细数据的 url
def get_detail_url(url, headers):
    rq = requests.get(url, headers=headers)
    soup = BeautifulSoup(rq.text, 'lxml')
    content = soup.find(class_='carlist clearfix js-top')
    links = content.find_all('a')
    detail_url_list = []
    for link in links:
        detail_url_list.append(f"https://www.guazi.com{link['href']}")
    return detail_url_list

# 获取详情数据
def get_detail(url, headers):
    rq = requests.get(url, headers=headers)
    soup = BeautifulSoup(rq.text, 'lxml')
    # name
    content = soup.find(class_='product-textbox')
    title = content.find('h1').text

    # info (上牌时间为图片)  里程数 排量 变速箱
    info = content.find(class_='assort clearfix')
    span = info.find_all('span')
    if len(span) >= 4:
        info_dic = {'name': title.strip(), 'km': span[1].text, 'displacement': span[2].text, 'gearbox': span[3].text}
    else:  # 某些网页 span数据较少
        info_dic = {'name': title.strip(), 'km': span[1].text, 'displacement': '无', 'gearbox': '无'}

    # price 价格单位是万
    price = soup.find(class_='price-num')  # price-num  pricebox js-disprice
    price = price.text

    # 销售方
    seller = soup.find(class_='ten')
    seller = seller.find(class_='typebox')
    seller = seller.text

    # 燃油类型
    fuel = soup.find_all(class_='td2')  # 很多信息  第十五个是燃油类型 或者 没有信息
    horsepower = "无"
    if len(fuel)>=13:
        horsepower = fuel[12].text
    if len(fuel)>=15:
        fuel = fuel[14].text
    else:
        fuel = "无"
    # fuel
    return info_dic, price, seller, fuel,horsepower

1.2.2 数据处理

  1. 数据集补充
    网站上的数据爬取难度较高,且数据量较少,一直爬取容易被封IP,所以这里使用公开赛的一个数据集对数据进行补充------阿里天池的二手车交易价格预测数据集,其数据具体内容如下图所示。
    在这里插入图片描述

  2. 统一数据格式
    网站上爬取的数据与公开赛数据集的数据是不一致的,相对来说公开赛数据集的标签比较多,信息比较详细,且数据类型单一,方便后续处理。所以这里需要对两个数据集进行统一,爬取的数据向公开赛数据靠拢,并将其转换为同一单位(比如fuelType网站上的数据是汉字,而公开赛数据集里的数据为数字,为了较少存储内存以及方便数据的后续处理,在这里将其统一为数字),同时删除无法在网站上爬取的公开赛数据中的标签

  3. 代码

name = []
fuelType = []
gearbox = []
power = []
kilometer = []
seller = []
price = []
# 爬取 保存数据
for page in range(1,3):
    print("************第{}页正在保存**********".format(page)) # 每一页 数量不定
    base_url = 'https://www.guazi.com/sjz/buy/o{}/#bread'.format(page) #
    detail_url = get_detail_url(base_url, headers)  # 所有车辆详细信息链接
    print(len(detail_url))
    for d_url in detail_url:
        print(d_url)
        info_dic, pric, sell, fuel, horsepower = get_detail(d_url, headers)
        name.append(info_dic['name'])  # 名字
        if fuel.find("汽油"):
            fuel = 0
        elif fuel.find("柴油"):
          fuel = 1
        elif fuel.find("液化石油气"):
            fuel = 2
        elif fuel.find("天然气"):
            fuel = 3
        elif fuel.find("混合动力"):
            fuel = 4
        else:
            fuel = 6
        fuelType.append(fuel)           # 燃油类型
        tmp = info_dic['gearbox']
        if tmp.find("手动"):
            tmp = 0
        else:                           # 电动汽车 大多是自动挡
            tmp = 1
        gearbox.append(tmp)             # 变速箱 自动 or 手动
        tmp = re.findall("\d+", horsepower)
        if len(tmp) == 0:
            tmp = 0
        else:
            tmp = int(tmp[0]) * 0.735
        power.append(tmp)                # 功率
        km = re.findall(r"\d+\.?\d*", info_dic['km'])
        if len(km) == 0:
            km = 0
        else:
            km = float(km[0])
        kilometer.append(km)             # 里程数
        if sell.find("私户"):
            sell = 0
        else:
            sell = 1
        seller.append(sell)              # 销售方、
        tmp = re.findall(r"\d+\.?\d*", pric)
        if len(tmp) == 0:
            tmp = 0
        else:
            tmp = float(tmp[0]) * 10000
        price.append(tmp)                # 价格

df = pd.DataFrame({'name'    : name,
                   'fuelType': fuelType,
                   'gearbox' : gearbox ,
                   'power'   : power,
                   'kilometer': kilometer,
                   'seller'  : seller,
                   'price'   : price})
df.to_csv('guazi.csv')  # 最终保存为csv文件

二、数据分析

2.1 统计分析

  1. 公开数据集为例,这里只显示了其部分标签列(共30列),一共有15万条交易数据。可以看到每一个数据的SaleID都是不同的,从0递增到149999,name标签最大为19万,但是其一共只有15万条数据,想必name的分布也是相对均匀的。model是车型编码,最大为247,数据中车辆种类一共不超过248种。之后标签的max都很小,其分布相对密集。
    在这里插入图片描述
  2. 查看数据类型、缺失和异常值
    在这里插入图片描述
  3. 代码
#!/usr/bin/env python
# coding: utf-8
## 导入所需包
import numpy as np
import pandas as pd
import warnings
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.special import jn
from IPython.display import display, clear_output
import time
import pickle
warnings.filterwarnings('ignore')
## 在Jupyter noteboo显示图像
get_ipython().run_line_magic('matplotlib', 'inline')
from sklearn import linear_model  ## 模型预测的
from sklearn import preprocessing
from sklearn.svm import SVR
from sklearn.ensemble import RandomForestRegressor,GradientBoostingRegressor
from sklearn.decomposition import PCA,FastICA,FactorAnalysis,SparsePCA ## 数据降维处理的
import lightgbm as lgb
import xgboost as xgb
## 参数搜索和评价的
from sklearn.model_selection import GridSearchCV,cross_val_score,StratifiedKFold,train_test_split
from sklearn.metrics import mean_squared_error, mean_absolute_error

#Train_data = pd.read_csv('used_car_train_20200313.csv', sep=' ') # shape: (150000, 40)
Train_data = pd.read_csv('guazi.csv', sep=',') # shape: (150000, 40)

# In[10]:
pd.set_option('display.max_rows', 500)
pd.set_option('display.max_columns', 500)
pd.set_option('display.width', 1000)
print(Train_data.describe())

# In[11]:
Train_data.head()

# In[12]:
Train_data.info()

# In[13]:
Train_data.isnull().sum()

2.2 可视化分析

在这里插入图片描述

#!/usr/bin/env python
# coding: utf-8
## 导入所需包
import numpy as np
import pandas as pd
import warnings
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.special import jn
from IPython.display import display, clear_output
import time
import pickle
warnings.filterwarnings('ignore')
## 在Jupyter noteboo显示图像
get_ipython().run_line_magic('matplotlib', 'inline')
from sklearn import linear_model  ## 模型预测的
from sklearn import preprocessing
from sklearn.svm import SVR
from sklearn.ensemble import RandomForestRegressor,GradientBoostingRegressor
from sklearn.decomposition import PCA,FastICA,FactorAnalysis,SparsePCA ## 数据降维处理的
import lightgbm as lgb
import xgboost as xgb
## 参数搜索和评价的
from sklearn.model_selection import GridSearchCV,cross_val_score,StratifiedKFold,train_test_split
from sklearn.metrics import mean_squared_error, mean_absolute_error

#Train_data = pd.read_csv('used_car_train_20200313.csv', sep=' ') # shape: (150000, 40)
Train_data = pd.read_csv('guazi.csv', sep=',') 
# In[3]:
plt.hist(Train_data['price'])
plt.show()
# In[4]:
features = Train_data.columns
#print(features)
features = [col for col in features if col not in ['price','notRepairedDamage']]
f = pd.melt(Train_data, value_vars=features)
g = sns.FacetGrid(f, col="variable",  col_wrap=2, sharex=False, sharey=False)
g = g.map(sns.distplot, "value")
# In[ ]:

三、价格预测

爬取的车辆数据集特征数量较少,能否准确预测交易价格?

3.1 价格趋势分析(特征分析)

  1. 按照爬取数据集的特征选取公开赛数据集的部分特征,然后将其分为训练集和验证集,训练集用于训练,验证集用于验证训练的模型的好坏(模型采用xgboost),然后对爬取数据进行测试,查看预测价格与实际价格的分布是否大致相同。
    以下是结果图,黄色表示为实际价格,蓝色为预测价格*6,由于公开赛数据集的二手车交易价格普遍较低,所以预测出来的价格也相对实际价格较低,这里乘以6是为了方便观察其价格分布。
    在这里插入图片描述
  2. 可以看到实际价格和预测价格的趋势大致相同,再计算以下他们的相关性,如下图。
    在这里插入图片描述
  3. 代码
## 导入所需包
import pandas as pd
import matplotlib.pyplot as plt
import lightgbm as lgb
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error
Train_data = pd.read_csv('used_car_train_20200313.csv', sep=' ') # shape: (150000, 40)
## 查看列
#print(Train_data.columns)
cols = Train_data.columns
## 选择特征列
feature_cols =['fuelType','gearbox','power','kilometer','seller']
## 构造训练样本和测试样本
X_data = Train_data[feature_cols]
Y_data = Train_data['price']
def build_model_lgb(x_train,y_train):
    model = lgb.LGBMRegressor(objective='regression',
                              max_depth = 10,
                              num_leaves = 1000,
                              learning_rate=0.1, n_estimators=100,
                              metric='rmse',  #bagging_fraction = 0.8, feature_fraction = 0.8
                              )
    model.fit(x_train, y_train)
    return model
x_train,x_val,y_train,y_val = train_test_split(X_data,Y_data,test_size=0.2)
# 训练模型
print('Predict lgb...')
model_lgb = build_model_lgb(x_train,y_train)
print('ok!')
# 测试模型
val_lgb = model_lgb.predict(x_val)
val_lgb[val_lgb<0] = 0
MAE_lgb = mean_absolute_error(y_val,val_lgb)
print('MAE of val with lgb:',MAE_lgb)
MAE = mean_absolute_error(y_val,val_lgb*0.5)
print('MAE:',MAE)

Test = pd.read_csv('guazi.csv', sep=',') # shape
test_price = model_lgb.predict(Test[feature_cols])
#mean_absolute_error(Test['price'],test_price)
plt.plot(test_price*6)
plt.plot(Test['price'])
plt.show()
data = pd.DataFrame({'predict':test_price,'gt':Test['price']})
t2=data.corr()
print(t2)

3.2 价格预测

  1. 通过对价格趋势的分析,有理由相信爬取的有限的这几个特征:['fuelType','gearbox','power','kilometer','seller'],在一定程度上影响着车辆的价值。同时由于公开赛数据集的价格与爬取数据集的价格相差很大,所以没有办法使用公开赛数据集对爬取数据集做定量分析。只能爬取跟多的二手车数据集对二手车交易价格做定量的预测。

  2. 相对于价格趋势分析,这里同样使用的是lgb模型,但是为了价格预测的准确性,将学习率降低为0.01,迭代次数增加为十万次。其测试误差如下(MAE-平均绝对误差7755):
    在这里插入图片描述

  3. 查看实际价格与预测价格的折线图:
    在这里插入图片描述

  4. 代码

#!/usr/bin/env python
# coding: utf-8
## 导入所需包
import numpy as np
import pandas as pd
import warnings
import matplotlib
import matplotlib.pyplot as plt
import time
import pickle
warnings.filterwarnings('ignore')
## 在Jupyter noteboo显示图像
get_ipython().run_line_magic('matplotlib', 'inline')
from sklearn import preprocessing
import lightgbm as lgb
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, mean_absolute_error

Train_data = pd.read_csv('guazi_more.csv', sep=',') # shape: (150000, 40)
#TestA_data = pd.read_csv('used_car_testB_20200421.csv', sep=' ') # shape: (50000, 39)
Train_data.describe()

# In[35]:
## 查看列
#print(Train_data.columns) 
cols = Train_data.columns
## 选择特征列
feature_cols =['fuelType','gearbox','power','kilometer','seller']
## 构造训练样本和测试样本
X_data = Train_data[feature_cols]
Y_data = Train_data['price']
x_train,x_val,y_train,y_val = train_test_split(X_data,Y_data,test_size=0.2)

# In[62]:
def build_model_lgb(x_train,y_train):
    model = lgb.LGBMRegressor(objective='regression',
                              max_depth = 10,
                              num_leaves = 1000,
                              learning_rate=0.01, n_estimators=100000, # 60000 7千   # 
                              metric='rmse',  #bagging_fraction = 0.8, feature_fraction = 0.8
                              )
    model.fit(x_train, y_train)
    return model

# In[63]:
# 训练模型
print('Predict lgb...')
model_lgb = build_model_lgb(x_train,y_train)
print('ok!')

# In[64]:
# 测试模型
val_lgb = model_lgb.predict(x_val)
#val_lgb[val_lgb<0] = 0
MAE_lgb = mean_absolute_error(y_val,val_lgb)
print('MAE of val with lgb:',MAE_lgb) 

# In[68]:
x = np.arange(0,len(y_val),1)
plt.plot(x,val_lgb) # scatter
plt.plot(x,y_val)
plt.figure(figsize=(30,10),dpi=36)
plt.show()

# In[69]:
data = pd.DataFrame({'predict':val_lgb,'gt':y_val})
t2=data.corr()
print(t2)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1018572.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

6. 装饰器

UML 聚合(Aggregation)关系&#xff1a;大雁和雁群&#xff0c;上图中空心菱形箭头表示聚合关系组合(Composition)关系&#xff1a;大雁和翅膀 &#xff0c;实心菱形箭头表示组合(Composition)关系 测试代码 #include <iostream> #include <stdio.h> #include &l…

IDEA2023.2.1中创建第一个Tomcat的web项目

首先&#xff0c;创建一个普通的java项目。点击【file】-【new】-【project】 创建一个TomcatDemo项目 创建如下图 添加web部门。点击【file】-【project structure】 选择【modules】-选中项目“TomcatDemo” 点击项目名上的加号【】&#xff0c;添加【web】模块 我们就会发现…

【微信小程序】文章设置

设置基本字体样式&#xff1a;行高、首行缩进 font-size: 32rpx;line-height: 1.6em;text-indent: 2em;padding: 20rpx 0;border-bottom: 1px dashed var(--themColor); 两端对齐 text-align: justify; css文字两行或者几行显示省略号 css文字两行或者几行显示省略号_css…

FPGA project : dht11 温湿度传感器

没有硬件&#xff0c;过几天上板测试。 module dht11(input wire sys_clk ,input wire sys_rst_n ,input wire key ,inout wire dht11 ,output wire ds ,output wire …

72、Spring Data JPA 的 Specification 动态查询

Specification&#xff1a;规范、规格 ★ Specification查询 它也是Spring Data提供的查询——是对JPA本身 Criteria 动态查询 的包装。▲ 为何要有动态查询 页面上常常会让用户添加不同的查询条件&#xff0c;程序就需要根据用户输入的条件&#xff0c;动态地组合不同的查询…

外星人入侵游戏-(创新版)

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

不同类型程序的句柄研究

先做一个winform程序&#xff1b;随便放几个控件&#xff1b; 用窗口句柄查看工具看一下&#xff1b;form和上面的每个控件都有一个句柄&#xff1b; 然后看一下记事本&#xff1b;记事本一共包含三个控件&#xff0c;各自有句柄&#xff1b; 这工具的使用是把右下角图标拖到要…

服务器迁移:无缝过渡指南

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

基于SSM+Vue的高校实验室管理系统的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

线程的方法(未完成)

线程的方法 1、sleep(long millis) 线程休眠&#xff1a;让执行的线程暂停一段时间&#xff0c;进入计时等待状态。 static void sleep(long millis):调用此方法后&#xff0c;当前线程放弃 CPU 资源&#xff0c;在指定的时间内&#xff0c;sleep 所在的线程不会获得可运行的机…

如何使用Java语言判断出geek是字符串参数类型,888是整数参数类型,[hello,world]是数组参数类型,2.5是双精度浮点数类型?

如何使用Java语言判断出geek是字符串参数类型&#xff0c;888是整数参数类型&#xff0c;[hello,world]是数组参数类型&#xff0c;2.5是双精度浮点数类型&#xff1f; Java是一种静态类型的编程语言&#xff0c;这意味着我们需要在编译时为变量指定具体的类型。但是&#xff…

web应用及微信小程序版本更新检测方案实践

背景&#xff1a; 随着项目体量越来越大&#xff0c;用户群体越来越多&#xff0c;用户的声音也越来越明显&#xff1b;关于应用发版之后用户无感知&#xff0c;导致用户用的是仍然还是老版本功能&#xff0c;除非用户手动刷新&#xff0c;否则体验不到最新的功能&#xff1b;这…

ICCV 2023 | MPI-Flow:从单视角构建的多平面图像中学习光流

ICCV 2023 | MPI-Flow&#xff1a;从单视角构建的多平面图像中学习光流 引言&#xff1a;主要贡献&#xff1a;Motivation&#xff1a;算法细节&#xff1a;Optical Flow Data GenerationIndependent Object MotionsDepth-Aware Inpainting 实验结果&#xff1a; 来源&#xff…

QT:使用分组框、单选按钮、普通按钮、标签、行编辑器、垂直分布、水平分布做一个小项目

widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QRadioButton> //单选按钮 #include <QGroupBox> //分组框 #include <QHBoxLayout> //水平布局 #include <QVBoxLayout> //垂直布局 #include <QPushButton>…

MFC主框架和视类PreCreateWindow()函数学习

在VC生成的单文档应用程序中&#xff0c;主框架类和视类均具有PreCreateWindow函数&#xff1b; 从名字可知&#xff0c;可在此函数中添加一些代码&#xff0c;来控制窗口显示后的效果&#xff1b; 并且它有注释说明&#xff0c; Modify the Window class or styles here by…

RHCSA 重定向、vim练习题

1.重定向练习题 (1)新建一个文件redirect.txt&#xff0c;并在其中写入20210804RHCSA,保存并退出 先输入命令 [rootlocalhost ~]# vim redirect.txt进入vim编辑器后&#xff0c;按快捷键“i”进入编辑模式&#xff0c;再写入数据&#xff0c;写完之后按“esc"键退出编辑…

python 采用selenium+cookies 获取登录后的网页

百度网页由于需要登陆手机短信验证。比较麻烦 这里我采用先人工登录百度账号&#xff0c;然后将百度账号的相关cookies保存下来 然后采用selenium动态登录网页 整体代码如下 from selenium import webdriverimport timeoptions webdriver.ChromeOptions()options.add_argu…

LLM 08-分布式训练

LLM 08-分布式训练 8.1 为什么分布式训练越来越流行 近年来&#xff0c;深度学习被广泛应用到各个领域&#xff0c;包括计算机视觉、语言理解、语音识别、广告推荐等。在这些不同的领域中&#xff0c;一个共同的特点就是模型规模越来越大&#xff0c;比如 GPT-3 模型的参数量达…

华为云云耀云服务器L实例评测|基于L实例使用Docker部署MySQL服务并连接MySQL—phpMyAdmin管理工具

文章目录 一、云耀云服务器产品优势1、智能不卡顿2、价优随心用3、上手更简单4、管理更省心 二、远程连接云耀云服务器L实例三、安装Docker、docker-compse1、docker安装2、docker-compose安装 四、方法① 使用Docker安装部署MySQL服务五、方法② 使用docker-compse安装部署MyS…

2023年 python结合excel实现快速画图(零基础快速入门)

目录 1.适用人群 2.环境配置 3.基本用法 3.1 数据读取 3.2 数据分析 3.3 数据组装 3.4 制表&#xff1a; 4.快速提升 5.效果展示 1.适用人群 电脑有python环境&#xff0c;会python基本使用&#xff0c;需要短时间内完成大量画图任务的数据分析的人群。&#xff08;有…