第二次打卡(3月22日-3月24日)
菜鸡的学习之路^__^(自己学习,复习使用)
Task2:数据的探索性分析(EDA)
1.1 EDA要做什么
首先我们需要明白EDA要做什么:
- 了解数据大致表达了什么
- 挖掘数据结构(结构化;图像化)
- 初步分理处一些重要特征
- 挖掘离群数据和异常数据
- 初步确定可以用那些模型
1.2 具体内容
- 载入各种数据科学以及可视化库:
- 数据科学库 pandas、numpy、scipy;
- 可视化库 matplotlib、seabon;
- 其他;
- 载入数据:
- 载入训练集和测试集;
- 简略观察数据(head()+shape);
- 数据总览:
- 通过describe()来熟悉数据的相关统计量
- 通过info()来熟悉数据类型
- 判断数据缺失和异常:
- 查看每列的存在nan情况
- 异常值检测
- 了解预测值的分布:
- 总体分布概况(无界约翰逊分布等)
- 查看skewness and kurtosis
- 查看预测值的具体频数
- 特征分为类别特征和数字特征,并对类别特征查看unique分布
- 数字特征分析:
- 相关性分析
- 查看几个特征得
- 偏度和峰值
- 每个数字特征得分布可视化
- 数字特征相互之间的关系可视化
- 多变量互相回归关系可视化
- 类型特征分析:
- unique分布
- 类别特征箱形图可视化
- 类别特征的小提琴图可视化
- 类别特征的柱形图可视化类别
- 特征的每个类别频数可视化(count_plot)
- 用pandas_profiling生成数据报告
2.3 代码
载入数据科学以及可视化库
import numpy as np
import pandas as pd
import warnings
import os,sys
project_path = os.path.dirname(os.path.abspath("__file__"))
# 设置动态路径
# 获取当前文件路径的上一级目录
warnings.filterwarnings('ignore')
pd.set_option('display.max_columns', None) # 设置DataFrame的输出显示,显示所有列
# 载入数据集
train_data = pd.read_csv(project_path + r'used_car_train_20200313.csv', sep=' ')
test_data = pd.read_csv(project_path + r'used_car_testA_20200313.csv', sep=' ')
print('train_data_shape:', train_data.shape)
print('test_data_shape:', test_data.shape)
train_data_shape: (150000, 31)
test_data_shape: (50000, 30)
train_data.head()
train_data.describe()
# price一列
# 均值:5923
# 标准差:7501
# 最小值: 11
# 最大值:99999,偏离程度有点大
首先把训练集读取进来看看各列的情况,主要看一下预测目标price的情况,发现均值在5900左右,标准差在7500左右,然而最大值居然有99999,可以看出事情并不简单,回归问题最怕离群点。(心里仿佛受到一万点打击。。。。)
# 画图看看
import matplotlib.pyplot as plt
import seaborn as sns
plt.figure()
sns.distplot(train_data['price'])
plt.figure()
train_data['price'].plot.box()
plt.show()
直接画图看一下,发现事情并不简单,可以看出数据的分布并不是标准的正态分布,远处的离群点看起来并不少,训练起来估计误差会很大,训练的时候可以考虑把这些离群点去掉。但如果测试集也有类似的点,那就没办法了,回归场景里面,一个离群点带来的误差可能会拖垮整个数据集上的指标分数。
import gc
print(test_data.shape)
print(train_data.shape)
(50000, 30)
(150000, 31)
df = pd.concat([train_data, test_data], axis=0, ignore_index=True)
del train_data, test_data
gc.collect()
df.head()
把测试集也读进来看看全数据情况
# 把特征分为3类
date_cols = ['regDate', 'creatDate']
category_cols = [
'name', 'model', 'brand', 'bodyType', 'fuelType', 'gearbox',
'notRepairedDamage', 'regionCode', 'seller', 'offerType'
]
number_cols = ['power', 'kilometer'] + ['v_{}'.format(i) for i in range(15)]
cols = date_cols + category_cols + number_cols
tmp = pd.DataFrame()
tmp['count'] = df[cols].count().values # 每一个特征样本数目统计
tmp['missing_rate'] = (df.shape[0] - tmp['count']) / df.shape[0] # 每一个特征样本缺失率
tmp['nunique'] = df[cols].nunique().values # 每一个特征不同取值数目
tmp['max_value_counts'] = [df[f].value_counts().values[0]
for f in cols] # 每个特征最大值出现次数
tmp['max_value_counts_prop'] = tmp['max_value_counts'] / df.shape[
0] # 每个特征最大值出现率
tmp['max_value_counts_value'] = [df[f].value_counts().index[0]
for f in cols] # 每个特征最大值
tmp.index = cols # 修改index
tmp
# seller, offerType两个特征可以删除了,就1个值,没啥用
把特征分成三部分,分别是日期特征、类别特征、数值特征。然后看看每一维特征的缺失率、n unique等信息,可以发现seller、offerType这两个特征可以删掉了,所有样本就一个取值,没什么用。从这里还可以发现匿名特征里面的v_0到v_4、v_10到v_14感觉长的有点像,貌似有很多相似的地方。
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):
df[f] = pd.to_datetime(df[f].astype('str').apply(date_proc))
df[f + '_year'] = df[f].dt.year
df[f + '_month'] = df[f].dt.month
df[f + '_day'] = df[f].dt.day
df[f + '_dayofweek'] = df[f].dt.dayofweek
把日期列处理一下,提取年、月、日、星期等信息。这里有些日期异常的样本,月份出现了0,因此需要开个函数单独处理一下。
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 = df[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()
看一下这些日期相关的特征的分布,可以看出汽车上线时间的年份(creatDate_year)基本上都是2016年,这个特征也没什么用了。creatDate_month基本上只有3、4两个月的,可以暂且保留,不过这种情况还是挺奇怪的,难道大家都热衷于在3月份卖车么?也可能跟行业有关吧,不懂。
# 进行特征删改
category_cols.remove('seller')
category_cols.remove('offerType')
date_cols = [
'regDate_year', 'regDate_month', 'regDate_day', 'regDate_dayofweek',
'creatDate_month', 'creatDate_day', 'creatDate_dayofweek'
]
# 看一下各个数值特征跟price的相关性
corr1 = abs(df[~df['price'].isnull()][['price'] + date_cols + number_cols].corr())
plt.figure(figsize=(10, 10))
sns.heatmap(corr1, linewidths=0.1, cmap=sns.cm.rocket_r)
看一下各个数值特征跟price的相关性。跟price相关性比较高的有汽车注册年份(regDate_year),应该可以理解为车越新,价格越高;汽车已行驶公里数(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等,这些特征之间可能存在冗余现象,训练的时候可以依据效果尝试去掉一部分,或者拆分成两部分,做模型融合。
# 看看15维匿名特征在训练集和测试集上的分布
plt.figure()
plt.figure(figsize=(15, 15))
i = 1
for f in number_cols[2:]:
plt.subplot(5, 3, i)
i += 1
sns.distplot(df[~df['price'].isnull()][f],
label='train',
color='y',
hist=False)
sns.distplot(df[df['price'].isnull()][f],
label='test',
color='g',
hist=False)
plt.tight_layout()
plt.show()
看看15维匿名特征分别在训练集和测试集上的分布,如果发现分布不一致的,可以尝试处理。但是貌似这15维特征在训练集和测试集上的分布基本上都挺一致的,无论多奇怪的分布,两个数据集上都挺一致。
plt.figure()
plt.figure(figsize=(20, 18))
i = 1
for f in category_cols + date_cols + number_cols:
if df[f].nunique() <= 50:
plt.subplot(5, 3, i)
i += 1
v = df[~df['price'].isnull()].groupby(f)['price'].agg({f + '_price_mean': 'mean'}).reset_index()
fig = sns.barplot(x=f, y=f + '_price_mean', data=v)
for item in fig.get_xticklabels():
item.set_rotation(90)
plt.tight_layout()
plt.show()
简单看几个nunique比较小的特征上面的price的均值的分布。可以发现regDate_year和kilometer的趋势变化很明显,这也对应了上面的相关性分布,这两个特征跟price的相关性都挺高。kilometer应该是被离散化过的,只保留了整数。
2.4 总结
数据探索在机器学习中我们一般称为EDA(Exploratory Data Analysis):
是指对已有的数据(特别是调查或观察得来的原始数据)在尽量少的先验假定下进行探索,通过作图、制表、方程拟合、计算特征量等手段探索数据的结构和规律的一种数据分析方法。
数据探索有利于我们发现数据的一些特性,数据之间的关联性,对于后续的特征构建是很有帮助的。
-
对于数据的初步分析(直接查看数据,或.sum(), .mean(),.descirbe()等统计函数)可以从:样本数量,训练集数量,是否有时间特征,是否是时许问题,特征所表示的含义(非匿名特征),特征类型(字符类似,int,float,time),特征的缺失情况(注意缺失的在数据中的表现形式,有些是空的有些是”NAN”符号等),特征的均值方差情况。
-
分析记录某些特征值缺失占比30%以上样本的缺失处理,有助于后续的模型验证和调节,分析特征应该是填充(填充方式是什么,均值填充,0填充,众数填充等),还是舍去,还是先做样本分类用不同的特征模型去预测。
-
对于异常值做专门的分析,分析特征异常的label是否为异常值(或者偏离均值较远或者事特殊符号),异常值是否应该剔除,还是用正常值填充,是记录异常,还是机器本身异常等。
-
对于Label做专门的分析,分析标签的分布情况等。
-
进步分析可以通过对特征作图,特征和label联合做图(统计图,离散图),直观了解特征的分布情况,通过这一步也可以发现数据之中的一些异常值等,通过箱型图分析一些特征值的偏离情况,对于特征和特征联合作图,对于特征和label联合作图,分析其中的一些关联性。
参考内容:
- Datawhale 零基础入门数据挖掘-Task2 数据分析
- 详解seaborn中的kdeplot、rugplot、distplot与jointplot
- 机器学习实战:基于Scikit-Learn和TensorFlow
- 【机器学习】菜菜的sklearn课堂
关于Datawhale:
Datawhale是一个专注于数据科学与AI领域的开源组织,汇集了众多领域院校和知名企业的优秀学习者,聚合了一群有开源精神和探索精神的团队成员。Datawhale 以“for the learner,和学习者一起成长”为愿景,鼓励真实地展现自我、开放包容、互信互助、敢于试错和勇于担当。同时 Datawhale 用开源的理念去探索开源内容、开源学习和开源方案,赋能人才培养,助力人才成长,建立起人与人,人与知识,人与企业和人与未来的联结。
在此特别感谢DataWhale提供的学习机会,为其开源精神点赞,希望自己能在自己的努力下不断进步,很幸运能遇到DataWhale这么优秀的平台。加油加油!!!!