二手车市场探索性数据分析

二手车市场探索性数据分析

项目描述:近年随着汽车工业发展,二手车市场越来越火热。根据获取的二手车市场数据,对影响二手车价格的因素进行研究与分析

项目职责:1.二手车市场的数据采集和数据集的预处理

                 2.可视化分析,确定二手车价格的影响因素

                 3.针对关键因素,分析对二手车价格的影响规律

                 4.分析图表的制作及分析报告的输出。

第一步:数据获取。抓取所有二手车对应的信息。1.找到各品牌车,对应的目标链接。2.获取所有页面下面,二手车的目标链接。3.通过该目标链接,获取所有二手车的各类信息。4.对各二手车及对应信息进行保存。以便后续分析。

## ********************************** 第一步:抓取二手车的所有品牌 **********************************
# 导入第三方包
import requests
from bs4 import BeautifulSoup
import time

# 设置头
headers = {
    'Accept':'*/*',
    'Accept-Encoding':'gzip, deflate, br',
    'Accept-Language':'zh-CN,zh;q=0.8',
    'Connection':'keep-alive',
    'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36'
}
# 二手车主页的链接及解析html
url = 'http://shanghai.taoche.com/all/'
res = requests.get(url, headers = headers).text
soup = BeautifulSoup(res,'html.parser')

# 抓取二手车名称及对应的链接
car_brands = soup.findAll('div',{'class':'brand-name'})
car_brands = [j for i in car_brands for j in i]
brands = [i.text for i in car_brands]
urls = ['http://shanghai.taoche.com' + i['href'] for i in car_brands]


## ********************************** 第二步:抓取所有页面下二手车的目标链接 **********************************
# 构建空列表,生成所需抓取的目标链接
target_urls = []
target_brands = []

for b,u in zip(brands,urls):
    # 抓取各品牌二手车主页下的所有页码
    res = requests.get(u, headers = headers).text
    soup = BeautifulSoup(res,'html.parser')
    
    if len(soup.findAll('div',{'class':'the-pages'})) == 0:
        pages = 1
    else:
        pages = int([page.text for page in soup.findAll('div',{'class':'the-pages'})[0].findAll('a')][-2])
    time.sleep(3)
    
    for i in range(1,pages + 1):
        target_brands.append(b)
        target_urls.append(u+'?page='+str(i)+'#pagetag')
        

## ********************************** 第三步:对二手车信息进行采集 **********************************        
# 构建空列表,用于数据的存储
brand = []
title = []
boarding_time = []
km = []
discharge = []
sec_price = []
new_price = []

# 对每个链接发生请求
for b,u in zip(target_brands,target_urls):
    
    res = requests.get(u, headers = headers).text
    soup = BeautifulSoup(res,'html.parser')
    
    # 每页车子的数量
    N = len([i.findAll('a')[0]['title'] for i in soup.findAll('div',{'class':'item_details'})])
    try:
        #车名称
        brands = (b+'-')*N
        brand.extend(brands.split('-')[:-1])
        title.extend([i.findAll('a')[0]['title'] for i in soup.findAll('div',{'class':'item_details'})])
        # 二手车的上牌时间、行驶里程数等信息
        info = [i.findAll('li') for i in soup.findAll('ul',{'class':'ul_news'})]
        boarding_time.extend([i[0].text[4:] for i in info])
        km.extend([i[1].text[4:] for i in info])
        discharge.extend([i[3].text[4:] for i in info])
        sec_price.extend([float(i.findAll('h2')[0].text[:-1]) for i in soup.findAll('div',{'class':'item_price'})])
        new_price.extend([i.findAll('p')[0].text.split('\xa0')[0][5:].strip() for i in soup.findAll('div',{'class':'item_price'})])
        
    except IndexError:
        pass
    # 每3秒停顿一次
    time.sleep(3)

    
## ********************************** 第四步:将采集来的数据进行存储 **********************************      
# 数据导出
import pandas as pd
cars_info = pd.DataFrame([brand,title,boarding_time,km,discharge,sec_price,new_price]).T
cars_info = cars_info.rename(columns={0:'Brand',1:'Name',2:'Boarding_time',3:'Km',4:'Discharge',5:'Sec_price',6:'New_price'})
cars_info.to_csv('second_cars_info.csv', index=False)

二手车市场探索性数据分析_第1张图片

第二步:数据清洗。对抓取的数据,进行预处理。

通过上表,可以清楚看到整个数据结构,各变量包括代表汽车品牌、汽车款式、上牌时间、行驶里程数、排放标准、二手价格和同款新车的参考价格。从中也发现一些问题:1.二手车上牌时间,存在‘’未上牌‘’,行驶里程、新车价格、上牌时间为字符串,所以需要进行数据预处理工作。

In [12]:
# 导入第三方模块
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression

# 可视化的中文处理
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
plt.rcParams['axes.unicode_minus'] = False
plt.style.use('ggplot')

# 读取数据
cars = pd.read_csv('C:/Users/Administrator/Desktop/second_cars_info.csv')


#********************第一部分:数据预处理*****************************
# “未上牌”的二手车占比
N = np.sum(cars.Boarding_time == '未上牌')
Ratio = N/cars.shape[0]
Ratio
Out[12]:
0.00824395000443223
In [13]:
# 由于未上牌的汽车数量占比极少,仅千分之八,这里不妨考虑将其删除
cars = cars.loc[cars.Boarding_time != '未上牌',:]
In [14]:
cars.index = range(0,cars.shape[0])
# 取出上牌时间变量中的年和月
cars['year'] = cars.Boarding_time.str[:4].astype('int')
month = cars.Boarding_time.str.findall('年(.*?)月')
# print(month.head(10))

# 由于month是列表构成的序列,所以需要非列表化,再序列化
month = pd.Series([i[0] for i in month]).astype('int')
cars['month'] = month
# print(month.head(10))

# 计算上牌日期距离2018年03月份的月数
cars['diff_months'] = (2018-cars.year)*12 + (3-cars.month) + 1
# 显示数据的前5行
cars.head()
Out[14]:
  Brand Name Boarding_time Km Discharge Sec_price New_price year month diff_months
0 奥迪 奥迪A6L 2006款 2.4 CVT 舒适型 2006年8月 9.00万公里 国3 6.90 50.89万 2006 8 140
1 奥迪 奥迪A6L 2007款 2.4 CVT 舒适型 2007年1月 8.00万公里 国4 8.88 50.89万 2007 1 135
2 奥迪 奥迪A6L 2004款 2.4L 技术领先型 2005年5月 15.00万公里 国2 3.82 54.24万 2005 5 155
3 奥迪 奥迪A8L 2013款 45 TFSI quattro舒适型 2013年10月 4.80万公里 欧4 44.80 101.06万 2013 10 54
4 奥迪 奥迪A6L 2014款 30 FSI 豪华型 2014年9月 0.81万公里 国4,国5 33.19 54.99万 2014 9 43
In [23]:
# 数值类型转换
# “百公里内”的样本量
N = np.sum(cars.Km == '百公里内')
Ratio = N/cars.shape[0]
Ratio
Out[23]:
0.005631033249910619
In [27]:
# 剔除“万公里”三个字
cars['Km_new'] = cars.Km.str[:-3]
# 将“百”字替换为0.005
cars.Km_new.replace('百','0.005', inplace=True)
# 数据类型转换
cars.Km_new = cars.Km_new.astype('float')
cars.head()
Out[27]:
  Brand Name Boarding_time Km Discharge Sec_price New_price year month diff_months Km_new
0 奥迪 奥迪A6L 2006款 2.4 CVT 舒适型 2006年8月 9.00万公里 国3 6.90 50.89万 2006 8 140 9.00
1 奥迪 奥迪A6L 2007款 2.4 CVT 舒适型 2007年1月 8.00万公里 国4 8.88 50.89万 2007 1 135 8.00
2 奥迪 奥迪A6L 2004款 2.4L 技术领先型 2005年5月 15.00万公里 国2 3.82 54.24万 2005 5 155 15.00
3 奥迪 奥迪A8L 2013款 45 TFSI quattro舒适型 2013年10月 4.80万公里 欧4 44.80 101.06万 2013 10 54 4.80
4 奥迪 奥迪A6L 2014款 30 FSI 豪华型 2014年9月 0.81万公里 国4,国5 33.19 54.99万 2014 9 43 0.81
In [28]:
#cars.New_price_new.astype('float')
# 这里无法实现数据类型的转换,因为该字段中含有“暂无”这样的值。

# “暂无”的样本量
N = np.sum(cars.New_price == '暂无')
Ratio = N/cars.shape[0]
Ratio
Out[28]:
0.012602788702180907
In [30]:
# 删除字段中的“万”字
cars['New_price_new'] = cars.New_price.str[:-1]
cars = cars.loc[cars.New_price != '暂无',:]
# 数据类型的转换
cars.New_price_new = cars.New_price_new.astype('float')
In [31]:
# 数据集的概览信息
cars.describe()
Out[31]:
  Sec_price year month diff_months Km_new New_price_new
count 11047.000000 11047.000000 11047.000000 11047.000000 11047.000000 11047.000000
mean 26.081886 2011.669141 6.653571 73.316738 6.230649 51.725339
std 53.401052 3.003765 3.346884 35.880047 3.502620 80.081184
min 0.650000 1997.000000 1.000000 6.000000 0.005000 2.910000
25% 5.200000 2010.000000 4.000000 45.000000 3.990000 16.160000
50% 10.350000 2012.000000 7.000000 74.000000 6.000000 26.790000
75% 23.980000 2014.000000 9.000000 97.000000 8.200000 52.730000
max 808.000000 2017.000000 12.000000 244.000000 34.600000 976.920000
第三步:数据可视化分析及分析模型构建
首先看下二手车价格分布,然后分析影响二手车价格的因素。
In [32]:
#***********************第二部分:可视化分析*********************
# 二手车价格分布情况
min_price = cars.Sec_price.min()
max_price = cars.Sec_price.max()

# 直方图
plt.hist(cars.Sec_price, # 二手车价格数据
         bins = np.arange(min_price,max_price+10,10), # 以10万元为组距
         color = 'steelblue', # 指定填充色
         )

# 设置坐标轴标签和标题
plt.title('二手车价格分布直方图')
plt.xlabel('价格')
plt.ylabel('频数')

# 去除图形顶部边界和右边界的刻度
plt.tick_params(top='off', right='off')

# 图形显示
plt.show()

图形属于是偏态分布,即随着二手车价格越高,车子的数量就急剧下降。下借助于累计频率直方图来展示,每个区间上二手车分布比例及情况。。                      

                                         

二手车市场探索性数据分析_第2张图片
In [33]:
# 累积频率直方图
plt.hist(cars.Sec_price, # 二手车价格数据
         bins = np.arange(min_price,max_price+10,10), # 以10万元为组距
         normed = True, # 设置为频率直方图
         cumulative = True, # 积累直方图
         color = 'steelblue', # 指定填充色
         )

# 添加水平参考线
plt.axhline(y = 0.5, color = 'blue', linestyle = '--', linewidth = 2)
plt.axhline(y = 0.8, color = 'red', linestyle = '--', linewidth = 2)

# 设置坐标轴标签和标题
plt.title('二手车价格累积分布直方图')
plt.xlabel('价格')
plt.ylabel('累积频率')

# 去除图形顶部边界和右边界的刻度
plt.tick_params(top='off', right='off')

# 图形显示
plt.show()

                       
从累积直方图可知,50%的二手车价格在10万以内就整体而言,80%的二手车均在30万以内。
二手车市场探索性数据分析_第3张图片
In [34]:
# 指定任意的切割点,将数据分段
price_cuts = pd.cut(cars.Sec_price, bins = [min_price,3,5,8,10,15,20,30,50,max_price])

# 按照数据段,进行数据的统计,即频数统计
price_stats = price_cuts.value_counts()

x = range(len(price_stats))
# 将索引用作绘图的刻度标签
label = price_stats.index
# 占比用于绘图的数值标签
percent = [str(round(i*100,2))+'%' for i in price_stats/price_stats.sum()]
# 绘图
plt.bar(x, # x轴数据
        price_stats, # y轴数据
        align = 'center', # 刻度居中对齐
        color='steelblue', # 填充色
        alpha = 0.8 # 透明度
       )

# 设置y轴的刻度范围
plt.ylim(0,2200)
# x轴刻度标签
plt.xticks(x,label)

# 设置坐标轴标签和标题
plt.title('二手车价格区间条形图')
plt.xlabel('价格区间')
plt.ylabel('频数')

# 去除图形顶部边界和右边界的刻度
plt.tick_params(top='off', right='off')

# 为每个条形图添加数值标签
for x,y,z in zip(x,price_stats,percent):
    plt.text(x, y+30,'%s' %z,ha='center')

# 显示图形
plt.show()
                                         
借助cut函数,将连续的数值切割成不同的数据段,自定义价格范围,再作条形图,如上图所示。5~8万的二手车最多,占了17.72%,其次是3~5
 万,也占了16.21%
。总体来看,10万以内的二手车数量,排在了前3。
二手车市场探索性数据分析_第4张图片
                                                               In [35]:
# 行驶公里数的饼图展现
km_min = cars.Km_new.min()
km_max = cars.Km_new.max()
# 指定任意的切割点,将数据分段
km_cuts = pd.cut(cars.Km_new, bins = [km_min, 1,3,5,10,km_max])
km_stats = km_cuts.value_counts()
km_stats

# 绘制饼图
# 将横、纵坐标轴标准化处理,保证饼图是一个正圆,否则为椭圆
plt.axes(aspect='equal')
# 提取出索引作为标签
labels = km_stats.index
# 自定义颜色
colors=['#9999ff','#ff9999','#7777aa','#2442aa','#dd5555'] 

# 绘制饼图
plt.pie(km_stats.values,
        labels=labels, 
        colors = colors, # 设置颜色
        autopct='%.1f%%', # 设置百分比的格式,这里保留一位小数
        counterclock = False, # 设置为顺时针方向
        wedgeprops = {'linewidth': 1.5, 'edgecolor':'green'},# 设置饼图内外边界的属性值
        textprops = {'fontsize':12, 'color':'k'} # 设置文本标签的属性值
       )

# 添加图标题
plt.title('二手车行驶公里数分布(万公里)')
# 显示图形   
plt.show()
二手车的价格与行驶里程数有关系。将行驶里程数分割为5段,即1万公里以内、1~3万公里、3~5万公里、5~10万公里及10万公里以上进行分析,得到饼图。超过一半的车,其行驶里程数在5~10万公里,而占比最少的是1万公里以内的二手车,6%不到。
二手车市场探索性数据分析_第5张图片                                       
回归模型的构建与分析:影响二手车价格的因素可能包括二手车的行驶时长、行驶公里数和汽车品牌,接下来探索一下。为减少汽车品牌的影响, 这里以奥迪和大众为例,绘制散点图。
In [37]:
# 取出奥迪和大众两种车辆
index = cars['Brand'].isin(['奥迪','大众'])
some_cars = cars.loc[index,:]

# 散点图的绘制
brands = some_cars['Brand'].unique()
colors = ['steelblue', '#ff9999']

for i in range(len(brands)):
    
    plt.scatter(some_cars.loc[some_cars['Brand'] == brands[i],'Km_new'], # x轴数据为二手车行驶公里
                some_cars.loc[some_cars['Brand'] == brands[i],'Sec_price'], # y轴数据为二手车价格
                s = 20, # 设置点的大小 
                c = colors[i], # 设置点的颜色
                marker = 'o', # 设置点的形状
                alpha = 0.9, # 设置点的透明度
                linewidths = 0.3, # 设置散点边界的粗细
                edgecolors = 'k', # 设置散点边界的颜色
                label = brands[i] # 添加标签
                )
    
# 添加轴标签和标题
plt.title('二手车行驶公里数与价格的关系')
plt.xlabel('行驶公里数')
plt.ylabel('价格')

# 去除图边框的顶部刻度和右边刻度
plt.tick_params(top = 'off', right = 'off')

# 显示图例
plt.legend()
# 显示图形
plt.show()
                                             
显然,从图中可 知,二手车的行驶里程数与价格成反向关系,似乎 奥迪车显示的更为明显。
二手车市场探索性数据分析_第6张图片
                                                               
 接下来再来看看二手车的行驶时长与价格之间是否也是反向关系,以奥迪车为例,在散点图的基础上再添加一条回归线
In [38]:
from sklearn.linear_model import LinearRegression
aodi_car = cars.loc[cars['Brand'] == '奥迪',:]
plt.scatter(aodi_car.diff_months, 
            aodi_car.Sec_price, 
            s = 30, # 设置点的大小 
            c = 'steelblue', # 设置点的颜色
            marker = 'o', # 设置点的形状
            alpha = 0.9, # 设置点的透明度
            linewidths = 0.3, # 设置散点边界的粗细
            label = '观测点')

# 建模
reg = LinearRegression().fit(aodi_car.diff_months.reshape(-1,1), aodi_car.Sec_price)
# 回归预测值
pred = reg.predict(aodi_car.diff_months.reshape(-1,1))

# 绘制回归线
plt.plot(aodi_car.diff_months, pred, linewidth = 2, label = '回归线')

# 添加轴标签和标题
plt.title('二手车的行驶时长与价格的关系')
plt.xlabel('行驶时长(月)')
plt.ylabel('价格(万元)')

# 去除图边框的顶部刻度和右边刻度
plt.tick_params(top = 'off', right = 'off')

# 显示图例
plt.legend(loc = 'best')
# 显示图形
plt.show()

                               
从图中可知,二手车的行驶时长与价格之 间确实存在反向关系。图中也存在一些远离总体的异常点,猜测可能是价格在100万以上的顶级高档的奥迪汽车。这些“异常点”也符合行驶时长与价格之间反向关系
二手车市场探索性数据分析_第7张图片

下一步:二手车价格影响因素较多,包括品牌、行驶时间、行驶里程、上牌时间等。而每种因素的影响程度不同,有待具体分析。且应该根据二手价格和新车价格做对比分析,更利于购买者或售卖者,能够提供有用的价格定位参考。

你可能感兴趣的:(数据分析)