二手车EDA
EDA目标:
EDA的价值主要在于熟悉数据集,了解数据集,对数据集进行验证来确定所获得数据集可以用于接下来的机器学习或者深度学习使用。
当了解了数据集之后我们下一步就是要去了解变量间的相互关系以及变量与预测值之间的存在关系。
引导数据科学从业者进行数据处理以及特征工程的步骤,使数据集的结构和特征集让接下来的预测问题更加可靠。
完成对于数据的探索性分析,并对于数据进行一些图表或者文字总结并打卡。
代码部分:
首先读取数据
data=pd.read_csv('D:/迅雷下载/二手车数据/used_car_train_20200313.csv',sep=' ')
data_test=pd.read_csv('D:/迅雷下载/二手车数据/used_car_test_20200313.csv',sep=' ')
data.head()
data_test.head()
查看一下有没有缺失值
data.isnull().sum()
标签的类型:
data.info()
看一下每一列数据所代表的意义:
SaleID - 销售样本ID
name - 汽车编码
regDate - 汽车注册时间
model - 车型编码
brand - 品牌
bodyType - 车身类型
fuelType - 燃油类型
gearbox - 变速箱
power - 汽车功率
kilometer - 汽车行驶公里
notRepairedDamage - 汽车有尚未修复的损坏
regionCode - 看车地区编码
seller - 销售方
offerType - 报价类型
creatDate - 广告发布时间
price - 汽车价格
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’ 【匿名特征,包含v0-14在内15个匿名特征】
整体看看数据啥规模:
当前目标是预测汽车价格,我们可以看一下汽车价格的整体走势:
可以看到价格不满足正太分布,所以在进行回归之前,它必须进行转换。来观察一下它的偏度值和峰值
#skewness and kurtosis
print("Skewness: %f" % data['price'].skew())
print("Kurtosis: %f" % data['price'].kurt())
Skewness: 3.346487
Kurtosis: 18.995183
data['price']
data['price'].value_counts()
查看预测值的具体频数:
plt.hist(data['price'], orientation = 'vertical',histtype = 'bar', color ='red')
plt.show()
查看频数, 大于20000得值极少,其实这里也可以把这些当作特殊得值(异常值)直接用填充或者删掉,再前面进行
# log变换 z之后的分布较均匀,可以进行log变换进行预测
sns.distplot(np.log(data['price']), color ='red')
plt.show()
通过图中可以发现,在3000元左右的时候是二手车销量最高的价格点,价格越高二手车的销量越差。
通过查看数据,在notRepairedDamage中有大量的空缺值-数据,统计一下。
data['notRepairedDamage'].value_counts()
在很多模型中对nan有直接的处理,这里我们先不做处理,先替换成nan
data['notRepairedDamage'].replace('-', np.nan, inplace=True)
data['notRepairedDamage'].value_counts()
data.isnull().sum()
以下两个类别特征严重倾斜,一般不会对预测有什么帮助,故这边先删掉
data["seller"].value_counts()
data["seller"].value_counts()
del data["seller"]
del data["offerType"]
在数据挖掘领域,数据的属性分为四种:
标称属性(norminal),比如name,modle
布尔属性(binary) 这里不考虑
序数属性(ordinary)
数值属性(numeric),比如kilometer,price,匿名特征
特征分为类别特征和数字特征,并对类别特征查看unique分布
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',]
#特征i探索
for cat_fea in categorical_features:
print(cat_fea + "的特征分布如下:")
print("{}特征有个{}不同的值".format(cat_fea, data[cat_fea].nunique()))
print(data[cat_fea].value_counts())
对标签特征进行分析:
一般卖车与汽车的品牌有一定的关系,那先看一下brand与销量的关系,从图中可以发现0,4,14,10,1,6,9这几个品牌的车卖的比较好,那price?
sns.distplot(data['brand'])
plt.show()
plt.figure(figsize=(15, 18))
ax=sns.violinplot(x='brand',y='price',data=data)
ax.set_yticks(list(range(0,100000,6000)))
小提琴图其实是箱线图与核密度图的结合,箱线图展示了分位数的位置,小提琴图则展示了任意位置的密度,通过小提琴图可以知道哪些位置的密度较高,白点是中位数
从图中可以发现,2,15,33,24,37这几个brand的价格要比其他的高一些,大部分的价格都相对较低一些在6000以下,3500左右
bodyType,fuelType,gearbox,notRepairedDamage 缺失率分别为3%,5.7%,3.9%,15.6%,画图看一下
cols = ['bodyType',
'fuelType',
'gearbox',
'notRepairedDamage']
for c in cols:
data[c] = data[c].astype('category')
if data[c].isnull().any():
data[c] = data[c].cat.add_categories(['MISSING'])
data[c] = data[c].fillna('MISSING')
def boxplot(x, y, **kwargs):
sns.boxplot(x=x, y=y)
x=plt.xticks(rotation=90)
f = pd.melt(data, id_vars=['price'], value_vars=cols)
g = sns.FacetGrid(f, col="variable", col_wrap=2, sharex=False, sharey=False, size=5)
g = g.map(boxplot, "value", "price")
接下来看看数值特征
numeric_features.append('price')
numeric_features
## 1) 相关性分析
price_numeric = data[numeric_features]
correlation = price_numeric.corr()
print(correlation['price'].sort_values(ascending = False),'\n')
f, ax = plt.subplots(figsize=(10, 8))
plt.title('Correlation of Numeric Features with Price',y=1,size=16)
sns.heatmap(correlation, square=True,cmap='YlGnBu');
#number of variables for heatmap
sns.heatmap(correlation,annot=True,cmap='RdYlGn',linewidths=0.2) #data.corr()-->correlation matrix
fig=plt.gcf()
fig.set_size_inches(18,18)
plt.show()
特征相关性的热度图 首先要注意的是,只有数值特征进行比较
正相关:如果特征A的增加导致特征b的增加,那么它们呈正相关。值1表示完全正相关。
负相关:如果特征A的增加导致特征b的减少,则呈负相关。值-1表示完全负相关。
现在让我们说两个特性是高度或完全相关的,所以一个增加导致另一个增加。这意味着两个特征都包含高度相似的信息,并且信息很少或没有变化。这样的特征对我们来说是没有价值的!
那么你认为我们应该同时使用它们吗?。在制作或训练模型时,我们应该尽量减少冗余特性,因为它减少了训练时间和许多优点。
现在,从上面的图,我们可以看到,特征不显著相关
来看一下各个数值特征跟price的相关性。汽车已行驶公里数(kilometer)也还行,应该可以理解为跑的路程越多,车就越旧,价格就越低;匿名特征里面的v_0、v_3、v_8、v_12看起来跟price的相关性很高,原因就不知道了。除了跟price的相关性,还可以发现有些特征跟特征之间的相关性也很高,比如v_1跟v_6、v_2跟v_7、v_3跟v_8、v_4跟v_9等,这些特征之间可能存在冗余现象,训练的时候可以依据效果尝试去掉一部分,或者拆分成两部分,做模型融合。
del price_numeric['price']
#查看几个特征得 偏度和峰值
for col in numeric_features:
print('{:15}'.format(col),
'Skewness: {:05.2f}'.format(data[col].skew()) ,
' ' ,
'Kurtosis: {:06.2f}'.format(data[col].kurt())
)
#每个数字特征得分布可视化
f = pd.melt(data, value_vars=numeric_features)
g = sns.FacetGrid(f, col="variable", col_wrap=2, sharex=False, sharey=False)
g = g.map(sns.distplot, "value")
#数字特征相互之间的关系可视化
sns.set()
columns = ['price', 'v_12', 'v_8' , 'v_0', 'power', 'v_5', 'v_2', 'v_6', 'v_1', 'v_14']
sns.pairplot(data[columns],size = 2 ,kind ='scatter',diag_kind='kde')
plt.show()
标签中还有两个日期标签。把日期列处理一下,提取年、月、日、星期等信息。这里有些日期异常的样本,月份出现了0,因此需要开个函数单独处理一下。
date_cols =['regDate', 'creatDate']
from tqdm import tqdm
def date_proc(x):
m = int(x[4:6])
if m == 0:
m = 1
return x[:4] + '-' + str(m) + '-' + x[6:]
for f in tqdm(date_cols):
data[f] = pd.to_datetime(data[f].astype('str').apply(date_proc))
data[f + '_year'] = data[f].dt.year
data[f + '_month'] = data[f].dt.month
data[f + '_day'] = data[f].dt.day
data[f + '_dayofweek'] = data[f].dt.dayofweek
plt.figure()
plt.figure(figsize=(16, 6))
i = 1
for f in date_cols:
for col in ['year', 'month', 'day', 'dayofweek']:
plt.subplot(2, 4, i)
i += 1
v = data[f + '_' + col].value_counts()
fig = sns.barplot(x=v.index, y=v.values)
for item in fig.get_xticklabels():
item.set_rotation(90)
plt.title(f + '_' + col)
plt.tight_layout()
plt.show()
来看一下各个数值特征跟price的相关性。跟price相关性比较高的有汽车注册年份(regDate_year),应该可以理解为车越新,价格越高
上一篇: 移动web开发小记(布局视口)(视觉视口)(理想视口)
下一篇: 数据结构_栈及其应用