文章目录
前言
本文章为天池“零基础入门数据挖掘 - 二手车交易价格预测”学习赛的Task02-学习日志,旨在了解EDA的分析步骤,通过分析数据,对数据清洗,了解变量间的相互关系以及变量与预测值之间的存在关系,并通过数据处理和特征工程提高预测的可靠性。 学习网址:[添加链接描述](https://github.com/datawhalechina/team-learning-data-mining/blob/master/SecondHandCarPriceForecast/Task2%20%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90.md)一、EDA学习思维导图
二、EDA是什么?
EDA定义:探索性数据分析(Exploratory Data Analysis,简称EDA),是一种通过可视化方法概括性分析数据集的主要特征的分析方法,通常使用形式化建模或假设检验的方法,探索性数据分析是上世纪六十年代美国统计学家John Tukey提出。 EDA作用:EDA不同于初始数据分析(IDA),其更集中于检查模型拟合和假设检验所需的假设,以及处理缺少的值,了解变量间的相互关系以及变量与预测值之间的存在关系,并根据需要进行变量转换。二、EDA分析步骤
1.载入数据库
1.1代码如下:
import warnings
warnings.filterwarnings('ignore')
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import missingno as msno
1.2导入库常见问题
Q1:如后期需要使用的lightgbm库需要通过pip下载,下载需通过CMD,直接输入pip会报错:
A1:需进入pip.exe所在文件夹路径,复制路径(通常在python/anaconda的Scripts文件夹中),转到该文件夹,再运行pip 安装:
注:下载时间过长会被墙,将安装包下载至本地Scripts文件夹中安装,安装地址:添加链接描述
## 2.读入数据及预览 ![在这里插入图片描述](https://www.icode9.com/i/ll/?i=2021041615562178.jpg#pic_center)
2.1读入数据
代码如下:
path = 'D:/python/ItemofSecondHandCarPriceForecast/Data/data/'
Train_data = pd.read_csv(path+'used_car_train_20200313.csv', sep=' ')
TestA_data = pd.read_csv(path+'used_car_testA_20200313.csv', sep=' ')
注:参数1为数据所在路径
2.2数据预览
数据预览代码如下:
Train_data.head().append(Train_data.tail())
注:简略预览数据前五行和后五行,输出结果如下
SaleID name regDate model brand bodyType fuelType gearbox power kilometer ... v_5 v_6 v_7 v_8 v_9 v_10 v_11 v_12 v_13 v_14
0 0 736 20040402 30.0 6 1.0 0.0 0.0 60 12.5 ... 0.235676 0.101988 0.129549 0.022816 0.097462 -2.881803 2.804097 -2.420821 0.795292 0.914762
1 1 2262 20030301 40.0 1 2.0 0.0 0.0 0 15.0 ... 0.264777 0.121004 0.135731 0.026597 0.020582 -4.900482 2.096338 -1.030483 -1.722674 0.245522
2 2 14874 20040403 115.0 15 1.0 0.0 0.0 163 12.5 ... 0.251410 0.114912 0.165147 0.062173 0.027075 -4.846749 1.803559 1.565330 -0.832687 -0.229963
3 3 71865 19960908 109.0 10 0.0 0.0 1.0 193 15.0 ... 0.274293 0.110300 0.121964 0.033395 0.000000 -4.509599 1.285940 -0.501868 -2.438353 -0.478699
4 4 111080 20120103 110.0 5 1.0 0.0 0.0 68 5.0 ... 0.228036 0.073205 0.091880 0.078819 0.121534 -1.896240 0.910783 0.931110 2.834518 1.923482
149995 149995 163978 20000607 121.0 10 4.0 0.0 1.0 163 15.0 ... 0.280264 0.000310 0.048441 0.071158 0.019174 1.988114 -2.983973 0.589167 -1.304370 -0.302592
149996 149996 184535 20091102 116.0 11 0.0 0.0 0.0 125 10.0 ... 0.253217 0.000777 0.084079 0.099681 0.079371 1.839166 -2.774615 2.553994 0.924196 -0.272160
149997 149997 147587 20101003 60.0 11 1.0 1.0 0.0 90 6.0 ... 0.233353 0.000705 0.118872 0.100118 0.097914 2.439812 -1.630677 2.290197 1.891922 0.414931
149998 149998 45907 20060312 34.0 10 3.0 1.0 0.0 156 15.0 ... 0.256369 0.000252 0.081479 0.083558 0.081498 2.075380 -2.633719 1.414937 0.431981 -1.659014
149999 149999 177672 19990204 19.0 28 6.0 0.0 1.0 193 12.5 ... 0.284475 0.000000 0.040072 0.062543 0.025819 1.978453 -3.179913 0.031724 -1.483350 -0.342674
数据规模代码如下:
Train_data.shape
注:预览数据矩阵规模,结果如下
(50000, 30)
3.总数据概述
3.1 描述各变量的特征值
代码如下
Train_data.describe()
结果如下
SaleID name regDate model brand bodyType fuelType gearbox power kilometer ... v_5 v_6 v_7 v_8 v_9 v_10 v_11 v_12 v_13 v_14
count 50000.000000 50000.000000 5.000000e+04 50000.000000 50000.000000 48587.000000 47107.000000 48090.000000 50000.000000 50000.000000 ... 50000.000000 50000.000000 50000.000000 50000.000000 50000.000000 50000.000000 50000.000000 50000.000000 50000.000000 50000.000000
mean 174999.500000 68542.223280 2.003393e+07 46.844520 8.056240 1.782185 0.373405 0.224350 119.883620 12.595580 ... 0.248669 0.045021 0.122744 0.057997 0.062000 -0.017855 -0.013742 -0.013554 -0.003147 0.001516
std 14433.901067 61052.808133 5.368870e+04 49.469548 7.819477 1.760736 0.546442 0.417158 185.097387 3.908979 ... 0.044601 0.051766 0.195972 0.029211 0.035653 3.747985 3.231258 2.515962 1.286597 1.027360
min 150000.000000 0.000000 1.991000e+07 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.500000 ... 0.000000 0.000000 0.000000 0.000000 0.000000 -9.160049 -5.411964 -8.916949 -4.123333 -6.112667
25% 162499.750000 11203.500000 1.999091e+07 10.000000 1.000000 0.000000 0.000000 0.000000 75.000000 12.500000 ... 0.243762 0.000044 0.062644 0.035084 0.033714 -3.700121 -1.971325 -1.876703 -1.060428 -0.437920
50% 174999.500000 52248.500000 2.003091e+07 29.000000 6.000000 1.000000 0.000000 0.000000 109.000000 15.000000 ... 0.257877 0.000815 0.095828 0.057084 0.058764 1.613212 -0.355843 -0.142779 -0.035956 0.138799
75% 187499.250000 118856.500000 2.007110e+07 65.000000 13.000000 3.000000 1.000000 0.000000 150.000000 15.000000 ... 0.265328 0.102025 0.125438 0.079077 0.087489 2.832708 1.262914 1.764335 0.941469 0.681163
max 199999.000000 196805.000000 2.015121e+07 246.000000 39.000000 7.000000 6.000000 1.000000 20000.000000 15.000000 ... 0.291618 0.153265 1.358813 0.156355 0.214775 12.338872 18.856218 12.950498 5.913273 2.624622
注:describe种有每列的统计量,个数count、平均值mean、标准差std、最小值min、中位数25% 50% 75% 、以及最大值
3.2 了解数据类型及空值情况
代码如下
Train_data.describe()
结果如下
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 150000 entries, 0 to 149999
Data columns (total 31 columns):
SaleID 150000 non-null int64
name 150000 non-null int64
regDate 150000 non-null int64
model 149999 non-null float64
brand 150000 non-null int64
bodyType 145494 non-null float64
fuelType 141320 non-null float64
gearbox 144019 non-null float64
power 150000 non-null int64
kilometer 150000 non-null float64
notRepairedDamage 150000 non-null object
regionCode 150000 non-null int64
seller 150000 non-null int64
offerType 150000 non-null int64
creatDate 150000 non-null int64
price 150000 non-null int64
v_0 150000 non-null float64
v_1 150000 non-null float64
v_2 150000 non-null float64
v_3 150000 non-null float64
v_4 150000 non-null float64
v_5 150000 non-null float64
v_6 150000 non-null float64
v_7 150000 non-null float64
v_8 150000 non-null float64
v_9 150000 non-null float64
v_10 150000 non-null float64
v_11 150000 non-null float64
v_12 150000 non-null float64
v_13 150000 non-null float64
v_14 150000 non-null float64
dtypes: float64(20), int64(10), object(1)
memory usage: 35.5+ MB
注:info()用以了解数据type及nan情况
4.判断和处理数据缺失和异常
4.1 异常值检测常用方法
(1)简单统计:利用pandas.describe()+散点图发现异常值;
(2)3σ原则:此方法数据分布需要服从正态分布或者近似正态分布,正态分布99.730020%的数据在[u-3σ,u-3σ]内,如果在3σ之外根据小概率原理可判定为异常值;
(3)箱线图法:离四分位数构成箱子较远的值
(4)基于模型检测:需构建概率分布模型,根据分布将低概率判定为异常点
(5)基于近邻度的离群点检测:确定数据集的有意义的邻近性来度量异常值
(6)基于密度的异常检测
(7)基于聚类的异常检测
(8)专门的离群点检测
(9) 孤立森林(可列为学习重点)
(10)Robust Random Cut Forest
以上方法根据可大侠的“数据分析–异常值处理”总结链接如下:添加链接描述
4.2 常见异常值及对应检测方法
4.2.1存在nan的情况
4.2.1.1列表直观了解:简要了解“nan”是否过多
代码如下
Train_data.isnull().sum()
结果如下
SaleID 0
name 0
regDate 0
model 1
brand 0
bodyType 4506
fuelType 8680
gearbox 5981
power 0
kilometer 0
notRepairedDamage 0
regionCode 0
seller 0
offerType 0
creatDate 0
price 0
v_0 0
v_1 0
v_2 0
v_3 0
v_4 0
v_5 0
v_6 0
v_7 0
v_8 0
v_9 0
v_10 0
v_11 0
v_12 0
v_13 0
v_14 0
dtype: int64
将上述列表可视化代码如下
missing = Train_data.isnull().sum()
missing = missing[missing > 0]
missing.sort_values(inplace=True)
missing.plot.bar()
plt.show()
结果如下
注:也可以根据info函数结果查看
4.2.1.2缺省值(nan)可视化:missingno模块
通常通过missingno模块实现nan值可视化,常用函数如下,本次主要学习matrix和bar。
- msno.matrix
- msno.bar
- msno.heatmap
- msno.dendrogram
msno.matrix代码如下
msno.matrix(Train_data.sample(250))
plt.show()
msno.matrix结果如下
msno.bar代码如下
msno.bar(Train_data.sample(1000))
plt.show()
msno.bar结果如下
4.2.2存在空缺值的情况“-”
根据info结果得知只有’notRepairedDamage’的数据类型为object,其可能存在空缺值,需要读取’notRepairedDamage’的取值。
'notRepairedDamage’取值代码如下
Train_data['notRepairedDamage'].value_counts()
结果如下
0.0 111361
- 24324
1.0 14315
Name: notRepairedDamage, dtype: int64
‘ - ’也为空缺值,对于空值可直接处理,但本次baseline将其替换为nan
替换代码如下
Train_data['notRepairedDamage'].replace('-', np.nan, inplace=True)
Train_data['notRepairedDamage'].value_counts()
结果如下:
0.0 111361
1.0 14315
Name: notRepairedDamage, dtype: int64
注:
1.replace用法
第一个参数是这是要进行更换的旧子串,第二个参数是这是新的子串,将取代旧的子字符串,第三个参数是替换多少次,默认是全部X.repalce(old,new,max);
2.inplace参数的理解:
修改一个对象:
inplace=True:不创建新的对象,直接对原始对象进行修改;
inplace=False:对数据进行修改,创建并返回新的对象承载其修改结果。
4.2.2 存在严重倾斜数据情况
有的特征数据会有严重倾斜,一般不会对预测有什么帮助,故先删除。
倾斜数据取值代码如下
Train_data["seller"].value_counts()
结果如下
0 149999
1 1
Name: seller, dtype: int64
Train_data[“offerType”].value_counts()
Train_data["seller"].value_counts()
5.了解预测值的总体分布
5.1 绘图了解大概分布
分布绘图代码如下
TRP=Train_data['price']
TRP_co=Train_data['price'].value_counts()
print(TRP)
print(TRP_co)
## 总体分布概况(*约翰逊分布等)
import scipy.stats as st
y = Train_data['price']
plt.figure(1); plt.title('Johnson SU') #绘制画布
sns.distplot(y, kde=False, fit=st.johnsonsu)#根据数据于画布上作图
plt.figure(2); plt.title('Normal')
sns.distplot(y, kde=False, fit=st.norm)
plt.figure(3); plt.title('Log Normal')
sns.distplot(y, kde=False, fit=st.lognorm)
plt.show()
结果如下
注-上述函数知识补充:
1.figure(num=None, figsize=None, dpi=None, facecolor=None, edgecolor=None, frameon=True)
- num:图像编号或名称,数字为编号 ,字符串为名称 ;
- figsize:指定figure的宽和高,单位为英寸;
- dpi参数指定绘图对象的分辨率,即每英寸多少个像素,缺省值为80 1英寸等于2.5cm,A4纸是 21*30cm的纸张;
facecolor:背景颜色 edgecolor:边框颜色 frameon:是否显示边框
2.seaborn的displot()集合了matplotlib的hist()与核函数估计kdeplot的功能,
增加了rugplot分布观测条显示与利用scipy库fit拟合参数分布的新颖用途,具体用法如下:
seaborn.distplot(a, bins=None, hist=True, kde=True, rug=False, fit=None, hist_kws=None, kde_kws=None, rug_kws=None, fit_kws=None, color=None, vertical=False, norm_hist=False, axlabel=None, label=None, ax=None)
- 参数:
- a:绘图数据(Series, 1d-array, or list)
- bins:设置矩形图数量
- hist: 控制是否显示条形图
- kde:控制是否显示核密度估计图
- rug: 控制是否显示观测的小细条(边际毛毯)
- fit: 控制拟合的参数分布图形
- vertical: 显示正交控制
学习链接添加链接描述
5.2 偏度和峰度
单个特征偏度和风度获取代码如下:
sns.distplot(Train_data['price']);
print("Skewness: %f" % Train_data['price'].skew())
print("Kurtosis: %f" % Train_data['price'].kurt())
结果如下:
Skewness: 3.346487
Kurtosis: 18.995183
结果分析:函数分布图为右偏尖峰图,结果与图形一致。
注-知识补充:
- 偏度定义中包括正态分布(偏度=0),右偏分布(也叫正偏分布,其偏度>0),左偏分布(也叫负偏分布,其偏度<0)。
- 峰度(peakedness;kurtosis)又称峰态系数。表征概率密度分布曲线在平均值处峰值高低的特征数。直观看来,峰度反映了峰部的尖度。随机变量的峰度计算方法为:随机变量的四阶中心矩与方差平方的比值。峰度包括正态分布(峰度值=3),厚尾(峰度值>3),瘦尾(峰度值<3)。注意,个别的软件会将峰度值减3,ArcGIS默认正态分布的峰度为3,MS Excel的计算公式与上面略有不同。
偏度和风度可视化代码如下:
Train_data.skew(), Train_data.kurt()
sns.distplot(Train_data.skew(),color='blue',axlabel ='Skewness')
结果如下:
5.3 查看预测具体频数
查看预测值的具体频数代码如下:
plt.hist(Train_data['price'], orientation = 'vertical',histtype = 'bar', color ='red')
plt.show()
结果如下:
结果分析:由上图可知图形右偏严重,可将大于20000得值作特殊得值(异常值)直接用填充或者删掉,上述进行log变换之后的分布较均匀,也可以进行log变换进行预测。
6.了解各变量(即不同类别)数据分布及分析
-通过对数据分析,本次数据主要包括数字特征和类型特征,因此先进行label的分离再依次对不同的数据进行分析。
6.1 分离label即预测值
查看不同类型所包含的变量代码如下:
Y_train = Train_data['price']
numeric_features = Train_data.select_dtypes(include=[np.number])
numeric_features.columns
categorical_features = Train_data.select_dtypes(include=[np.object])
categorical_features.columns
numeric_features = ['power', 'kilometer', 'v_0', 'v_1', 'v_2', 'v_3', 'v_4', 'v_5', 'v_6', 'v_7', 'v_8', 'v_9', 'v_10', 'v_11', 'v_12', 'v_13','v_14' ]
categorical_features = ['name', 'model', 'brand', 'bodyType', 'fuelType', 'gearbox', 'notRepairedDamage', 'regionCode',]
6.2 数字特征分析
6.2.1相关性分析
相关性分析代码如下:
numeric_features.append('price')
price_numeric = Train_data[numeric_features]
correlation = price_numeric.corr()
print(correlation['price'].sort_values(ascending = False),'\n')
结果如下:
price 1.000000
v_12 0.692823
v_8 0.685798
v_0 0.628397
power 0.219834
v_5 0.164317
v_2 0.085322
v_6 0.068970
v_1 0.060914
v_14 0.035911
v_13 -0.013993
v_7 -0.053024
v_4 -0.147085
v_9 -0.206205
v_10 -0.246175
v_11 -0.275320
kilometer -0.440519
v_3 -0.730946
Name: price, dtype: float64
相关性分析可视化代码如下:
f , ax = plt.subplots(figsize = (7, 7))
plt.title('Correlation of Numeric Features with Price',y=1,size=16)
sns.heatmap(correlation,square = True, vmax=0.8)
结果如下:
注:
sort_values()用法:
.sort_values(by=‘##’,axis=0,ascending=True,inplace=False, na_position=‘last’)
-by: 指定列名(axis=0或’index’)或索引值(axis=1或’columns’)
-axis:若axis=0或’index’,则按照指定列中数据大小排序;若axis=1或’columns’,
则按照指定索引中数据大小排序,默认axis=0
-ascending:是否按指定列的数组升序排列,默认为True,即升序排列
-inplace:是否用排序后的数据集替换原来的数据,默认为False,即不替换
-na_position:{‘first’,‘last’},设定缺失值的显示位置
6.2.2 特征值偏度和峰值及可视化
偏度和峰值获取代码如下:
for col in numeric_features:
print('{:15}'.format(col),
'Skewness: {:05.2f}'.format(Train_data[col].skew()) ,
' ' ,
'Kurtosis: {:06.2f}'.format(Train_data[col].kurt())
)
plt.show()
#{:15}——位置映射,相当于{0:15},对应于format中的'',15为字符宽度
结果如下:
power Skewness: 65.86 Kurtosis: 5733.45
kilometer Skewness: -1.53 Kurtosis: 001.14
v_0 Skewness: -1.32 Kurtosis: 003.99
v_1 Skewness: 00.36 Kurtosis: -01.75
v_2 Skewness: 04.84 Kurtosis: 023.86
v_3 Skewness: 00.11 Kurtosis: -00.42
v_4 Skewness: 00.37 Kurtosis: -00.20
v_5 Skewness: -4.74 Kurtosis: 022.93
v_6 Skewness: 00.37 Kurtosis: -01.74
v_7 Skewness: 05.13 Kurtosis: 025.85
v_8 Skewness: 00.20 Kurtosis: -00.64
v_9 Skewness: 00.42 Kurtosis: -00.32
v_10 Skewness: 00.03 Kurtosis: -00.58
v_11 Skewness: 03.03 Kurtosis: 012.57
v_12 Skewness: 00.37 Kurtosis: 000.27
v_13 Skewness: 00.27 Kurtosis: -00.44
v_14 Skewness: -1.19 Kurtosis: 002.39
price Skewness: 03.35 Kurtosis: 019.00
偏度峰度可视化代码如下:
f = pd.melt(Train_data, value_vars=numeric_features)
g = sns.FacetGrid(f, col="variable", col_wrap=2, sharex=False, sharey=False)
g = g.map(sns.distplot, "value")
plt.show()
结果如下:
结果分析:由上图可以看出致使price呈现右偏和尖峰的主要原因可能是power。
数字特征相互之间的关系可视化如下:
sns.set()
columns = ['price', 'v_12', 'v_8' , 'v_0', 'power', 'v_5', 'v_2', 'v_6', 'v_1', 'v_14']
sns.pairplot(Train_data[columns],size = 2 ,kind ='scatter',diag_kind='kde')
plt.show()
结果如下:
6.2.3 多变量之间的关系可视化
6.3 类型特征分析
6.3.1 unique分布
特征nunique分布代码如下:
for cat_fea in categorical_features:
print(cat_fea + "的特征分布如下:")
print("{}特征有个{}不同的值".format(cat_fea, Train_data[cat_fea].nunique()))
print(Train_data[cat_fea].value_counts())
部分结果如下:
name的特征分布如下:
name特征有个99662不同的值
708 282
387 282
55 280
1541 263
203 233
...
5074 1
7123 1
11221 1
13270 1
174485 1
Name: name, Length: 99662, dtype: int64
注:也可根据此表画出可视化分布图并判断特殊值
6.3.2 类别特征可视化
6.3.2.1 箱形图可视化
代码如下:
for cat_fea in categorical_features:
print(cat_fea + "的特征分布如下:")
print("{}特征有个{}不同的值".format(cat_fea, Train_data[cat_fea].nunique()))
print(Train_data[cat_fea].value_counts())
部分结果如下:
6.3.2.2 小提琴图可视化
小提琴图 (Violin Plot)是用来展示多组数据的分布状态以及概率密度。这种图表结合了箱形图和密度图的特征,主要用来显示数据的分布形状。其和箱形图类似,但箱形图的所有绘图组件都对应于实际数据点,而小提琴形图具有底层分布的核密度估计。在数据量非常大不方便一个一个展示的时候小提琴图特别适用。
代码如下:
catg_list = categorical_features
target = 'price'
for catg in catg_list :
sns.violinplot(x=catg, y=target, data=Train_data)
plt.show()
部分结果如下:
6.3.2.2 柱形图可视化
代码如下:
def bar_plot(x, y, **kwargs):
sns.barplot(x=x, y=y)
x=plt.xticks(rotation=90)
f = pd.melt(Train_data, id_vars=['price'], value_vars=categorical_features)
g = sns.FacetGrid(f, col="variable", col_wrap=2, sharex=False, sharey=False, size=5)
g = g.map(bar_plot, "value", "price")
部分结果如下:
6.3.2.2 每个类别频数可视化(count_plot)
特征nunique分布代码如下:
def count_plot(x, **kwargs):
sns.countplot(x=x)
x=plt.xticks(rotation=90)
f = pd.melt(Train_data, value_vars=categorical_features)
g = sns.FacetGrid(f, col="variable", col_wrap=2, sharex=False, sharey=False, size=5)
g = g.map(count_plot, "value")
plt.show()
7.总数据概述
代码如下:
import pandas_profiling
pfr = pandas_profiling.ProfileReport(Train_data)
pfr.to_file("./example.html")
部分结果如下:
HBox(children=(FloatProgress(value=0.0, description='variables', max=29.0, style=ProgressStyle(description_wid…