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

引言

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

一、数据爬取

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)

  • 2
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
当然可以!下面是一个简单的Python共享单车数据分析预测的代码示例,我们可以使用Pandas和Scikit-Learn库来实现。 首先,我们需要导入必要的库: ```python import pandas as pd from sklearn.model_selection import train_test_split from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_squared_error, r2_score ``` 然后,我们加载我们要分析的共享单车数据集。在这个示例中,我们使用的是UCI机器学习库中的Bike Sharing Dataset。 ```python url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/00275/Bike-Sharing-Dataset.zip' zipfile = 'Bike-Sharing-Dataset.zip' csvfile = 'hour.csv' # 下载并解压数据集 import urllib.request import zipfile urllib.request.urlretrieve(url, zipfile) with zipfile.ZipFile(zipfile, 'r') as zip_ref: zip_ref.extractall() # 加载数据集 data = pd.read_csv(csvfile) ``` 接下来,我们对数据进行一些预处理。在这个示例中,我们选择了一些特征进行分析,并将它们转换为数值类型。 ```python # 选择特征 features = ['season', 'holiday', 'workingday', 'weathersit', 'temp', 'atemp', 'hum', 'windspeed'] # 将特征转换为数值类型 for feature in features: data[feature] = pd.to_numeric(data[feature], errors='coerce') ``` 然后,我们将数据集划分为训练集和测试集。 ```python # 划分数据集 X = data[features] y = data['cnt'] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0) ``` 接下来,我们使用线性回归模型进行预测。 ```python # 训练模型 model = LinearRegression() model.fit(X_train, y_train) # 预测数据 y_pred = model.predict(X_test) # 计算误差 mse = mean_squared_error(y_test, y_pred) r2 = r2_score(y_test, y_pred) print('Mean squared error: %.2f' % mse) print('Coefficient of determination: %.2f' % r2) ``` 最后,我们可以输出模型的预测结果,并可视化预测结果与测试集数据的比较。 ```python # 输出预测结果 predictions = pd.DataFrame({'Actual': y_test, 'Predicted': y_pred}) print(predictions) # 可视化预测结果 import matplotlib.pyplot as plt plt.scatter(y_test, y_pred) plt.xlabel('Actual') plt.ylabel('Predicted') plt.show() ``` 以上就是一个简单的Python共享单车数据分析预测的代码示例。当然,这只是一个基础的模板,你可以根据实际需求进行修改和优化。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大米粥哥哥

感谢认可!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值