前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python二手车价格预测(一)—— 数据处理

Python二手车价格预测(一)—— 数据处理

作者头像
吉吉的机器学习乐园
发布2022-07-13 16:42:37
1.5K0
发布2022-07-13 16:42:37
举报
文章被收录于专栏:吉吉的机器学习乐园

01

数据获取


我们的数据来源是“人人车”二手车网站,通过Python爬虫获取291个城市所有在售二手车详细数据。

数据爬取的全过程已经发表在CSDN博客上,欢迎大家点赞收藏,扫描下方二维码即可查看博文。

想了解爬取代码的同学可以clone我的git仓库https://gitee.com/hanxianzhe/spider/tree/master/spider_renren

02

数据处理


原始数据维度为:93738*212

获取时间为:2020年7月25日

【写在前面】

数据处理十分重要,一个机器学习模型预测结果的好坏与数据处理有直接关联。每个人处理数据的思维和方式都不一样,因此本文只是依据我的一些学习经验进行数据处理,给大家当个baseline~

【Step 1:导包】

代码语言:javascript
复制
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import sys
import seaborn as sns
import warnings
import datetime
warnings.filterwarnings("ignore")
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
# 设置可显示的最大行列数量
pd.set_option('display.max_rows', 100,'display.max_columns', 100,"display.max_colwidth",1000,'display.width',1000)

【Step 2:删除无效列与填充空值】

数据的许多列包含大量的空值和单一数据,当这些数据超过一定量时,对模型来说是无效的,因此先将这一部分数据进行删除。

代码语言:javascript
复制
# 读取数据
data = pd.read_excel("cars_info.xlsx", na_values=np.nan)

# 每列数据为空的列,数量大于80000,删除该列(无参考价值)
for c in data.columns:
    if data[c].isna().sum() > 80000:
        data.drop([c], axis=1, inplace=True)
        
# 每列数据为“无”的列,数量大于60000,删除该列(无参考价值)
for c in data.columns:
    if data[c].isin(["无"]).sum() > 60000:
        data.drop([c], axis=1, inplace=True)

# 因为数据本身含有长宽高的单独列,因此“长*宽*高(mm)”列删除
data.drop(['长*宽*高(mm)'], axis=1, inplace=True)

# 数据中许多列都包含“标配”,数量大于60000时无参考价值
for c in data.columns:
    if data[c].isin(["标配"]).sum() > 60000:
        print(c, data[c].isin(["标配"]).sum())
        data.drop([c], axis=1, inplace=True)

# 删除 “售价” 和 “排量” 为空的行
data.dropna(axis=0,subset = ["售价", "排量(L)"], inplace=True)

# 该列含有大量范围值,且已有新车售价,删除处理
data.drop(['厂商新车指导价'], axis=1, inplace=True)

# “过户记录”许多为空,我们认为可能无过户记录,因此填充0;“载客/人”按照该列平均值进行填充
data['过户记录'].fillna(0, inplace=True)
data['载客/人'].fillna(int(data['载客/人'].mean()), inplace=True)

【Step 3:数值型数据处理】

通过Excel表我们可以发现,有些列可以完全处理成数值型数据。剔除这些列中的异常数据,并且为空值进行填充,可以使用平均值或众数进行填充。

代码语言:javascript
复制
# 筛选出可以转化为数值型数据的列
numerical_col = ['售价', '新车售价', '行驶里程', '过户记录', 
                 '载客/人', '排量(L)', '最高车速(km/h)', '官方0-100km/h加速(s)',
                 '工信部综合油耗(L/100km)', '长度(mm)', '宽度(mm)', '高度(mm)', 
                 '轴距(mm)', '前轮距(mm)', '后轮距(mm)', '车门数', '油箱容积(L)',
                 '整备质量(kg)', '最小离地间隙(mm)', '排量(mL)', '气缸数(个)', 
                 '每缸气门数(个)', '压缩比', '最大马力(Ps)', '最大功率(kW)',
                 '最大扭矩(N·m)'
                ]
numerical_df = data[numerical_col]

# 将非数值型数据替换为np.nan
for c in numerical_col[5:]:
    numerical_df[c] = numerical_df[c].replace("无", np.nan).replace("false", np.nan).replace("未知", np.nan)

# 空值填充
mean_fill_col = ['排量(L)', '最高车速(km/h)', '官方0-100km/h加速(s)',
                 '工信部综合油耗(L/100km)', '长度(mm)', '宽度(mm)', '高度(mm)', 
                 '轴距(mm)', '前轮距(mm)', '后轮距(mm)', '油箱容积(L)',
                 '整备质量(kg)', '最小离地间隙(mm)', '排量(mL)', '压缩比', 
                 '最大马力(Ps)', '最大功率(kW)', '最大扭矩(N·m)'
                ]
many_fill_col = ['车门数', '气缸数(个)', '每缸气门数(个)'] # 多数都为4

# 将dataframe转化成float类型
numerical_df = numerical_df.astype(float)

# 进行填充
for c in mean_fill_col:
    numerical_df[c].fillna(numerical_df[c].mean(), inplace=True)
    
for c in many_fill_col:
    numerical_df[c].fillna(4, inplace=True)

# 将处理完的数据更新至data中
data[ numerical_col ] = numerical_df

# 处理 ['座位数', '行李厢容积(L)', '最大功率转速(rpm)', '最大扭矩转速(rpm)'] 中的异常值
# 异常值处理函数
def pickNum(df, c):
    if '-' in df[c]:
        num_list = df[c].split('-')
        return num_list[0]
    elif '―' in df[c]:
        num_list = df[c].split('―')
        return num_list[0]
    elif '~' in df[c]:
        num_list = df[c].split('~')
        return num_list[0]
    elif '/' in df[c]:
        num_list = df[c].split('/')
        return num_list[0]
    else:
        return df[c]

pickNum_col = ['座位数', '行李厢容积(L)', '最大功率转速(rpm)', '最大扭矩转速(rpm)']

# 转化为str类型
data[pickNum_col] = data[pickNum_col].astype(str)

# 异常值处理
for c in pickNum_col:
    data[c] = data.apply(lambda x:pickNum(x, c), axis=1)

# 将“无”、“false”、“未知” 等数据替换为空
for c in pickNum_col:
    data[c] = data[c].replace("无", np.nan).replace("false", np.nan).replace("未知", np.nan)

data[pickNum_col] = data[pickNum_col].astype(float)

# 众数填充
data['座位数'].fillna(5, inplace=True)

# 均值填充
for c in pickNum_col[1:]:
    data[c].fillna(data[c].mean(), inplace=True)

【Step 4:日期型数据处理】

数据中包含许多日期数据,我将它们转换成天数差,即用数据获取的时间减去对应的时间。

代码语言:javascript
复制
# 处理日期型数据
date_col = ['商业险过期日期','交强险过期日期', '注册日期', '出厂日期', '车船税过期日期']

data['数据获取日期'] = '2020-07-25'

date_col.append('数据获取日期')

# 处理日期型数据函数
def calDate(df, c):
    if pd.isnull(df['出厂日期']):
        return np.nan
    else:
        d1=datetime.datetime.strptime('2020-07-25',"%Y-%m-%d")
        d2=datetime.datetime.strptime(df[c],"%Y-%m-%d")
        diff_days=d1-d2
        # print(diff_days)
        return diff_days.days

# 处理数据中的异常值
for c in date_col[:-1]:
    data[c] = data[c].replace("--", np.nan)
    
# 生成时间差的列
for c in date_col[:-1]:
    data[c+'差(天)'] = data.apply(lambda x:calDate(x, c), axis=1)

new_date_col = ['商业险过期日期差(天)','交强险过期日期差(天)', '注册日期差(天)', '出厂日期差(天)', '车船税过期日期差(天)']

# 均值填充
for c in new_date_col:
    data[c].fillna(data[c].mean(), inplace=True)

# 删除之前的日期列
data.drop(date_col, axis=1, inplace=True

【Step 5:二值型数据处理】

许多列的数据要么为"有",要么为"无"。类似这种的数据我们称为"二值型"数据,可以将其转化为0-1的形式。

代码语言:javascript
复制
# 处理0-1型数据
zero_one_col_names = ['前排侧气囊', '无钥匙启动系统', 'TRC牵引力控制系统', '上坡辅助', '电动天窗', 
                      '真皮方向盘', '日间行车灯', '自动头灯', '后视镜加热', '后雨刷', '后座出风口', 
                      '4S店保养', '原始购车/过户发票', '车辆购置税完税证明']

# 异常值替换及空值填充
for c in zero_one_col_names:
    data[c] = data[c].replace("无", 0).replace("false", 0).replace("true", 1).replace("标配", 1).replace("false", 0).replace("否", 0).replace("是", 1).replace("有(已见发票)", 1).replace("有(未见发票)", 0).replace("已缴税(未见证明)", 0).replace("已缴税(已见证明)", 1).replace("K请问欺负我测了没人粉粉嫩嫩妇女。。佛方法v。。", 0)
    data[c].fillna(0, inplace=True)

【Step 6:One-Hot型数据处理】

当一列值可以被分成多个类别时,我们可以将数据处理成独热编码(One-Hot)的形式,建议类别的个数超过10的时候就不要使用独热编码了,因为会导致数据过于稀疏,它的详细作用就不介绍了,朋友们自行百度。

代码语言:javascript
复制
one_hot_col_names = ['进气形式', '气缸排列形式', '配气机构', '燃油标号', '供油方式', '缸盖材料', 
                     '缸体材料', '燃油形式', '变速箱类型', '驱动方式', '助力类型', '车体结构', 
                     '前制动', '后制动', '驻车制动类型', '备胎规格', '定速巡航', '真皮座椅', 
                     '变速器类型', '燃料类型', '车身颜色', '挡位个数']

# 这些是在excel筛选时发现的一些异常值,进行替换
data['挡位个数'] = data['挡位个数'].replace("无", "无级变速")
data['车身颜色'] = data['车身颜色'].replace("--", np.nan)
data['真皮座椅'] = data['真皮座椅'].replace(",", np.nan)
data['定速巡航'] = data['定速巡航'].replace("/", np.nan).replace("田......看", np.nan)
data['助力类型'] = data['助力类型'].replace("无助力", "无")

for c in one_hot_col_names:
    data[c] = data[c].replace("false", "无")
    data[c].fillna("无", inplace=True)

# 使用pandas中的get_dummies方法,直接将想要转换成独热编码额数据进行转换
one_hot_data = pd.get_dummies(data[one_hot_col_names])

# 合并独热编码数据,并删除之前的列
data = pd.concat([data,one_hot_data],axis = 1)
data.drop(one_hot_col_names, axis=1, inplace=True)

# 获取当前数据类型为数值型的列
final_col = list(data.describe().columns)
final_data = data[final_col]

# 有22列数据形式较为复杂,在这里就不进行处理了
# 有兴趣的同学可以自己尝试进行处理

# 保存处理后的数据
final_data.to_excel("final_data.xlsx", index=False)

03

结语


经过以上步骤的数据处理,我们将原始数据转换成可以放入机器学习模型的数据了。这里的数据处理过程比较简单,其中的一些操作也可以简单的理解成特征工程的过程(毕竟只是baseline),有能力的同学也可以按照自己的想法进行数据处理和特征工程。

最后的数据维度为:93738*190

下一期将进行机器学习的模型训练,以及实验结果的分析。

最后,整理不易,朋友们请点个赞、转个发

· END ·

最近是懒吉吉

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-04-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 吉吉的机器学习乐园 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档