python 二手车数据分析以及价格预测
二手车交易信息爬取、数据分析以及交易价格预测
- 引言
- 一、数据爬取
- 1.1 解析数据
- 1.2 编写代码爬
- 1.2.1 获取详细信息
- 1.2.2 数据处理
- 二、数据分析
- 2.1 统计分析
- 2.2 可视化分析
- 三、价格预测
- 3.1 价格趋势分析(特征分析)
- 3.2 价格预测
引言
本文着眼于车辆信息,结合当下较为火热的二手车交易市场数据,对最近二手车的交易价格进行分析以及预测。
经过前期调研,最终决定通过爬取一些网站的二手车数据和一些公开的数据集,分析交易数据的特征,根据交易特征对二手车交易价格进行分析预测。
本文主要核心内容:数据爬取
、数据分析
、交易价格预测
一、数据爬取
1.1 解析数据
- 选择二手车交易网站-瓜子二手车。点开官网,点击我要买车。以QQ浏览器为例,点击
开发者工具
(菜单-工具中),选择Network-DOC过滤。获取头部cookie等相关信息,如下图所示。
- 通过
搜索框
(点击开发者工具页面右上角 ‘竖着的三个点’ - Search),输入页面商品名称和属性名称,获取想要数据的位置,方便后续爬取解析,如下图所示。
- 根据以上获取的信息构造程序的
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')# namecontent = 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-dispriceprice = 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].textif len(fuel)>=15:fuel = fuel[14].textelse:fuel = "无"# fuelreturn info_dic, price, seller, fuel,horsepower
1.2.2 数据处理
-
数据集补充
网站上的数据爬取难度较高,且数据量较少,一直爬取容易被封IP,所以这里使用公开赛的一个数据集对数据进行补充------阿里天池的二手车交易价格预测数据集,其数据具体内容如下图所示。
-
统一数据格式
网站上爬取的数据与公开赛数据集的数据是不一致的,相对来说公开赛数据集的标签比较多,信息比较详细,且数据类型单一,方便后续处理。所以这里需要对两个数据集进行统一
,爬取的数据向公开赛数据靠拢,并将其转换为同一单位
(比如fuelType网站上的数据是汉字,而公开赛数据集里的数据为数字,为了较少存储内存以及方便数据的后续处理,在这里将其统一为数字),同时删除无法在网站上爬取的公开赛数据中的标签
。 -
代码
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 = 0elif fuel.find("柴油"):fuel = 1elif fuel.find("液化石油气"):fuel = 2elif fuel.find("天然气"):fuel = 3elif fuel.find("混合动力"):fuel = 4else:fuel = 6fuelType.append(fuel) # 燃油类型tmp = info_dic['gearbox']if tmp.find("手动"):tmp = 0else: # 电动汽车 大多是自动挡tmp = 1gearbox.append(tmp) # 变速箱 自动 or 手动tmp = re.findall("\d+", horsepower)if len(tmp) == 0:tmp = 0else:tmp = int(tmp[0]) * 0.735power.append(tmp) # 功率km = re.findall(r"\d+\.?\d*", info_dic['km'])if len(km) == 0:km = 0else:km = float(km[0])kilometer.append(km) # 里程数if sell.find("私户"):sell = 0else:sell = 1seller.append(sell) # 销售方、tmp = re.findall(r"\d+\.?\d*", pric)if len(tmp) == 0:tmp = 0else:tmp = float(tmp[0]) * 10000price.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 统计分析
- 以
公开数据集
为例,这里只显示了其部分标签列(共30列),一共有15万条交易数据。可以看到每一个数据的SaleID都是不同的,从0递增到149999,name标签最大为19万,但是其一共只有15万条数据,想必name的分布也是相对均匀的。model是车型编码,最大为247,数据中车辆种类一共不超过248种。之后标签的max都很小,其分布相对密集。
查看数据类型、缺失和异常值
代码
#!/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 价格趋势分析(特征分析)
- 按照爬取数据集的特征选取公开赛数据集的部分特征,然后将其分为训练集和验证集,训练集用于训练,验证集用于验证训练的模型的好坏(
模型采用xgboost
),然后对爬取数据进行测试,查看预测价格与实际价格的分布是否大致相同。
以下是结果图,黄色表示为实际价格,蓝色为预测价格*6,由于公开赛数据集的二手车交易价格普遍较低
,所以预测出来的价格也相对实际价格较低,这里乘以6是为了方便观察其价格分布。
- 可以看到实际价格和预测价格的趋势大致相同,再计算以下他们的相关性,如下图。
代码
## 导入所需包
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 价格预测
-
通过对价格趋势的分析,有理由相信爬取的
有限的这几个特征:['fuelType','gearbox','power','kilometer','seller']
,在一定程度上影响着车辆的价值。同时由于公开赛数据集的价格与爬取数据集的价格相差很大,所以没有办法使用公开赛数据集对爬取数据集做定量分析。只能爬取跟多的二手车数据集对二手车交易价格做定量的预测。 -
相对于价格趋势分析,这里同样使用的是
lgb模型
,但是为了价格预测的准确性,将学习率降低为0.01,迭代次数增加为十万次。其测试误差如下(MAE-平均绝对误差7755):
-
查看实际价格与预测价格的折线图:
-
代码
#!/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_errorTrain_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)
相关文章:

python 二手车数据分析以及价格预测
二手车交易信息爬取、数据分析以及交易价格预测 引言一、数据爬取1.1 解析数据1.2 编写代码爬1.2.1 获取详细信息1.2.2 数据处理 二、数据分析2.1 统计分析2.2 可视化分析 三、价格预测3.1 价格趋势分析(特征分析)3.2 价格预测 引言 本文着眼于车辆信息,结合当下较…...

JAVA医药进销存管理系统(附源码+调试)
JAVA医药进销存管理系统 功能描述 (1)登录模块:登录信息等存储在数据库中 (2)基本信息模块:分为药品信息模块、客户情况模块、供应商情况模块; (3)业务管理模块&#x…...
H5 <blockquote> 标签
主要应用于:内容引用 标签定义及使用说明 <blockquote> 标签定义摘自另一个源的块引用。 浏览器通常会对 <blockquote> 元素进行缩进。 提示和注释 提示:如果标记是不需要段落分隔的短引用,请使用 <q>。 HTML 4.01 与 H…...

nginx配置指南
nginx.conf配置 找到Nginx的安装目录下的nginx.conf文件,该文件负责Nginx的基础功能配置。 配置文件概述 Nginx的主配置文件(conf/nginx.conf)按以下结构组织: 配置块功能描述全局块与Nginx运行相关的全局设置events块与网络连接有关的设置http块代理…...

【数据结构】优先级队列(堆)
文章目录 💐1. 优先级队列1.1 概念 💐2.堆的概念及存储方式2.1 什么是堆2.2 为什么要用完全二叉树描述堆呢?2.3 为什么说堆是在完全二叉树的基础上进行的调整?2.4 使用数组还原完全二叉树 💐3. 堆的常用操作-模拟实现3…...

前端笔试2
1.下面哪一个是检验对象是否有一个以自身定义的属性? foo.hasOwnProperty("bar")bar in foo foo["bar"] ! undefinedfoo.bar ! null 解析: bar in foo 检查 foo 对象是否包含名为 bar 的属性,但是这个属性可以是从原型链继承来的&a…...
LeetCode:66.加一
66.加一 来源:力扣(LeetCode) 链接: https://leetcode.cn/problems/plus-one/description/ 给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 你可以假设除了整数 0 之外,这个整数…...

Redis 常用命令
目录 全局命令 1)keys 2)exists 3) del(delete) 4)expire 5)type SET命令 GET命令 MSET 和 MGET命令 其他SET命令 计数命令 redis-cli,进入redis 最核心的命令:我们这里只是先介绍 set 和 get 最简单的操作…...
Integer.valueOf()用于字符和字符串的区别
LeetCode 17 电话号码的字母组合 先贴代码 class Solution {List<String> result new ArrayList<>();String temp new String("");Integer num;public List<String> letterCombinations(String digits) {dfs(digits, 0);return result;} publi…...

机械寿命预测(基于NASA C-MAPSS数据的剩余使用寿命RUL预测,Python代码,CNN_LSTM模型,有详细中文注释)
1.效果视频:机械寿命预测(NASA涡轮风扇发动机剩余使用寿命RUL预测,Python代码,CNN_LSTM模型,有详细中文注释)_哔哩哔哩_bilibili 环境库版本: 2.数据来源:https://www.nasa.gov/int…...

ConfigMaps-1
文章目录 主要内容一.使用 YAML 文件创建1.在data节点创建了一些键值:代码如下(示例): 2.解释 二.使用命令行创建1.创建了一个名为 person 的键值:代码如下(示例): 2.解释3.创建了一个 index.html 文件&…...
docker上安装es
安装docker 1 安装docker依赖 yum install -y yum-utils2 设置docker仓库镜像地址 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo3 安装制定版本的docker yum -y install docker-ce-20.10.17-3.el74 查看是否安装成功 y…...

#循循渐进学51单片机#c语言基础和流水灯实现#not.3
1、熟练掌握二进制、十进制和十六进制的转换方法。 多少进制就是多少之间相加,比如十六进制就是十六一次一加;二进制转化十六进制,分成四个一组。 2、C语言变量类型与取值范围,for、while等基本语句的用法。 for、while等基本语句…...

算法刷题 week3
这里写目录标题 1.重建二叉树题目题解(递归) O(n) 2.二叉树的下一个节点题目题解(模拟) O(h) 3.用两个栈实现队列题目题解(栈,队列) O(n) 1.重建二叉树 题目 题解 (递归) O(n) 递归建立整棵二叉树:先递归创建左右子树,然后创建根节点&…...

TCP详解之流量控制
TCP详解之流量控制 发送方不能无脑的发数据给接收方,要考虑接收方处理能力。 如果一直无脑的发数据给对方,但对方处理不过来,那么就会导致触发重发机制,从而导致网络流量的无端的浪费。 为了解决这种现象发生,TCP 提…...
mac根目录下创建文件不能问题
mac根目录下创建文件不能问题 解决办法2: 原因 mac os引入了系统完整性保护(SIP)机制,无法在/、/usr目录下新建文件 解决办法1: 打开终端,输入 csrutil status显示enabled表示启用了SIP,接下来需要禁用SIP…...
stable diffusion model训练遇到的问题【No module named ‘triton‘】
一天早晨过来,发现昨天还能跑的diffusion代码,突然出现了【No module named ‘triton’】的问题,导致本就不富裕的显存和优化速度雪上加霜,因此好好探究了解决方案。 首先是原因,由于早晨过来发现【电脑重启】导致了【…...
线性dp,优化记录,273. 分级
273. 分级 273. 分级 - AcWing题库 给定长度为 N 的序列 A,构造一个长度为 N 的序列 B,满足: B 非严格单调,即 B1≤B2≤…≤BN 或 B1≥B2≥…≥BN。最小化 S∑Ni1|Ai−Bi|。 只需要求出这个最小值 S。 输入格式 第一行包含一…...

JWT 安全及案例实战
文章目录 一、JWT (json web token)安全1. Cookie(放在浏览器)2. Session(放在服务器)3. Token4. JWT (json web token)4.1 头部4.1.1 alg4.1.2 typ 4.2 payload4.3 签名4.4 通信流程 5. 防御措施 二、漏洞实例(webgoa…...

Vue2+Vue3
文章目录 Vue快速上手Vue是什么第一个Vue程序插值表达式Vue核心特性:响应式 Vue指令v-htmlv-show 与 v-ifv-else 与 v-else-ifv-onv-bindv-forv-model指令修饰符 计算属性watch侦听器(监视器)watch——简写watch——完整写法 Vue生命周期 和 …...

微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...

Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...

计算机基础知识解析:从应用到架构的全面拆解
目录 前言 1、 计算机的应用领域:无处不在的数字助手 2、 计算机的进化史:从算盘到量子计算 3、计算机的分类:不止 “台式机和笔记本” 4、计算机的组件:硬件与软件的协同 4.1 硬件:五大核心部件 4.2 软件&#…...
【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)
LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 题目描述解题思路Java代码 题目描述 题目链接:LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...