数据的探索性分析
本系列文章是为了记录Datawhale的《零基础入门数据挖掘》组队学习计划,此次学习计划以天池上的二手车交易价格预测这个项目为例,从数据的探索性分析(EDA)开始,到特征工程,再到建模和调参,最后是模型结果融合一整套的数据分析流程。本文为此系列的第一篇——数据的探索性分析(EDA)。
EDA的目的在于:
- 熟悉数据集,了解数据集,对数据集进行验证来确定所获得数据集可以用于接下来的机器学习或者深度学习使用。
- 了解变量间的相互关系以及变量与预测值之间的存在关系。
- 引导进入下一步的特征工程。
EDA一般有四个步骤,分别为:
- 数据搜集
- 数据清洗
- 数据预处理
- 数据可视化
下面以二手车交易价格这一数据集为例,具体说明下EDA的四个步骤。
数据搜集
数据收集是一个以既定的系统方式收集信息的过程,使人们能够很容易地测试假设和评估结果。
首先是导入数据
// 导入数据
Train_data = pd.read_csv('./used_car_train_20200313.csv', sep=' ')
Test_data = pd.read_csv('./used_car_testA_20200313.csv', sep=' ')
简略观察数据
pd.set_option('display.max_columns', None) #显示全部列
Train_data.head().append(Train_data.tail())
Test_data.head().append(Test_data.tail())
Train_data.shape
Test_data.shape
在获得数据之后我们需要检查数据的格式
Train_data.dtypes
Train_data.info
Test_data.dtypes
Test_data.info
再看看数据集的统计情况
Train_data.describe()
(150000, 31)
Test_data.describe()
(50000, 30)
数据搜集过程只是简略的看下数据格式和分布,没有对数据进行任何修改。
数据清洗
数据清洗主要是通过识别数据是否异常和判断数据是否缺失两个途径确保数据正确可用的过程。
判断数据缺失
Train_data.isnull().sum()
Test_data.isnull().sum()
# nan可视化
missing = Train_data.isnull().sum()
missing = missing[missing > 0]
missing.sort_values(inplace=True)
missing.plot.bar()
缺失值处理的几种方法,以fuelType列为例
- 忽略数据行
删除包含丢失数据或Nan数据的行。缺点很很明显,如果这些行的百分比很高,我们的性能就会很差。
#第一种 整行删除
Train_data.dropna(inplace = True)
查看效果
Train_data.shape
(135884, 31)
可以看出,直接删除的效果很差,把整个数据行都改变了,从150000行删减到135884行,而且这种删减会导致数据错位,这样肯定不行的。这种方式也可以用下语法来表示
Train_data.dropna(how='all') #删除所有NAN行
- 使用常量值来填充缺失值
之所以使用这种技术,是因为有时尝试并预测缺失的值是没有意义的。
#第二种 填充常量
Train_data.fillna(value=0, inplace=True)
这种方法比第一种稍微好点,没有删除行列,没有数据错位,但是离真实数据也很远。
- 使用FILLNA()填充缺失值
我们可以填充所有缺失的值,而不是删除Nan值或缺失的值。缺失的数据可以通过沿着序列向前或向后传播非nan值来填充。有时,如果下一个或上一个值不可用,或者它也是一个Nan值,那么即使在向前填充或向后填充之后,Nan值仍然是Nan。
#第三种 使用FILLNA()填充缺失值
Train_data.fillna(method='ffill')
Train_data.fillna(method = 'bfill')
这种方式对于前后数据相关的时间序列是有用的,但是对于我们这个数据集,每一行数据代表一个个体,这种填充方式是会混淆数据。
- 用平均值、中值和众数值代替
#第四种 用平均值、中值和模式值代替
# 平均值
train_data['fuelType'].fillna(train_data['fuelType'].median(), inplace = True)
#中值
train_data['fuelType'].fillna(train_data['fuelType'].mean(), inplace = True)
#众数
train_data['fuelType'].fillna(train_data['fuelType'].mode()[0], inplace = True)
以上就是数据缺失值的一般方法,其他的如回归插值、线性插值法等,每种方法都有自己的特色,没有哪种方法是通用的,这取决于我们的数据集结构以及之后要用的特征工程。
识别数据是否异常
这里的识别异常是粗略的检测下数据特征是否存在严重倾斜,这种一般不会对预测有什么帮助,就需要删除掉。
Train_data["seller"].value_counts()
Train_data["offerType"].value_counts()
删除这些数据特征
del Train_data["seller"]
del Train_data["offerType"]
del Test_data["seller"]
del Test_data["offerType"]
数据预处理
数据预处理是一种将原始数据转换成可理解格式的数据挖掘技术。它包括归一化和标准化、变换、特征提取和选择等。数据预处理的产物是最终的训练数据集。这将在下一章——特征工程中重点介绍。
数据可视化
数据可视化是信息和数据的图形化表示。它使用统计图形、绘图、信息图形和其他工具来清晰有效地传达信息。
以下是常用的seaborn可视化图:
- 散点图
- 箱型图
- 直方图
- 猫图
- 小提琴图
- 多变量图
- 联合图
- 热力图
我们的数据格式分为数字特征和类别特征,数字特征我们主要关注特征之间的相关性,特征与目标函数之间的相关性,前者关乎数据冗余,后者关乎关键特征,我们从定量和定性两方面考虑这两个问题。类别特征我们主要关心
#数字特征 类型特征划分
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',]
数字特征分析
#定量分析
#定义半热力图函数
def half_masked_corr_heatmap(dataframe,title=None,file=None):
plt.figure(figsize=(16,16))
sns.set(font_scale=1)
mask = np.zeros_like(dataframe.corr())
mask[np.triu_indices_from(mask)]=True
with sns.axes_style('white'):
sns.heatmap(dataframe.corr(),mask=mask,annot=True,cmap='coolwarm')
if title:plt.title(f'\n{title}\n',fontsize=18)
plt.xlabel('')
plt.ylabel('')
if file:plt.savefig(file,bbox_inches='tight')
plt.show();
ruturn
#查看变量间的相关性
half_masked_corr_heatmap(Train_data[numeric_features],'Variable correlations')
#定义特征与特定目标变量的相关性热力图
def corr_to_target(dataframe, target, title=None, file=None):
plt.figure(figsize=(4,6))
sns.set(font_scale=1)
sns.heatmap(dataframe.corr()[[target]].sort_values(target,
ascending=False)[1:],
annot=True,
cmap='coolwarm')
if title: plt.title(f'\n{title}\n', fontsize=18)
plt.xlabel('') # optional in case you want an x-axis label
plt.ylabel('') # optional in case you want a y-axis label
if file: plt.savefig(file, bbox_inches='tight')
plt.show();
return
#特征与特定目标变量的相关性热力图
numeric_features.append('price')
corr_to_target(Train_data[numeric_features], 'price',
' Corr to Price',
'corr_to_price.jpg'
)
看得出有些特征确实值得商讨,这需要在后期的特征工程中处理。
#定性分析
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()
最后推荐一款神器,一行代码生成数据分析报告——pandas_profiling.
#pandas_profiling函数演示
import pandas_profiling
df =Train_data
report = pandas_profiling.ProfileReport(df)
report