Datawhale 零基础入门数据挖掘-Task2 数据分析
二、 EDA-数据探索性分析
2.1 EDA目标
-
弄清楚数据的结构以及数据能够表达出的东西
-
尝试结合题目的描述锁定一些重要的特征
-
找出一些离群的值、异常值
-
找出一个适用于该赛题的模型
2.2 内容介绍
- 载入各种数据科学以及可视化库:
- 数据科学库 pandas、numpy、scipy;
- 可视化库 matplotlib、seabon;
- 其他;
- 载入数据:
- 载入训练集和测试集;
- 简略观察数据(head()+shape);
- 数据总览:
- 通过describe()来熟悉数据的相关统计量
- 通过info()来熟悉数据类型
- 判断数据缺失和异常(箱型图 )
- 查看每列的存在nan情况
- 异常值检测
- 了解预测值的分布
- 总体分布概况(无界约翰逊分布等)
- 查看skewness and kurtosis
- 查看预测值的具体频数
- 特征分为类别特征和数字特征,并对类别特征查看unique分布
- 数字特征分析
- 相关性分析
- 查看几个特征得 偏度和峰值
- 每个数字特征得分布可视化
- 数字特征相互之间的关系可视化
- 多变量互相回归关系可视化
- 类型特征分析
- unique分布
- 类别特征箱形图可视化
- 类别特征的小提琴图可视化
- 类别特征的柱形图可视化类别
- 特征的每个类别频数可视化(count_plot)
- 用pandas_profiling生成数据报告
2.3 代码示例
2.3.1 载入各种数据科学以及可视化库、导入数据
import pandas as pd import numpy as np from tqdm import tqdm import datetime import time import warnings import missingno as msno
import matplotlib.pyplot as plt from sklearn.preprocessing import LabelEncoder,OneHotEncoder %matplotlib inline # raw = pd.read_csv("./used_car_train_20200313.csv", parse_dates=['regDate']) train_data = pd.read_csv("./used_car_train_20200313.csv",sep=' ',parse_dates=['regDate']) test_data = pd.read_csv("./used_car_testA_20200313.csv",sep=' ',parse_dates=['regDate']) warnings.filterwarnings("ignore")
所有特征集均脱敏处理(方便大家观看)
- 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个匿名特征】
2.3.2 总览数据概况
- describe种有每列的统计量,个数count、平均值mean、方差std、最小值min、中位数25% 50% 75% 、以及最大值 看这个信息主要是瞬间掌握数据的大概的范围以及每个值的异常值的判断,比如有的时候会发现999 9999 -1 等值这些其实都是nan的另外一种表达方式,有的时候需要注意下
- info 通过info来了解数据每列的type,有助于了解是否存在除了nan以外的特殊符号异常
## 1) 通过describe()来熟悉数据的相关统计量 Train_data.describe()
## 2) 通过info()来熟悉数据类型 Train_data.info()
2.3.3 判断数据缺失和异常
## 1) 查看每列的存在nan情况 Train_data.isnull().sum()
# nan可视化 missing = Train_data.isnull().sum() missing = missing[missing > 0] missing.sort_values(inplace=True) missing.plot.bar()
通过以上两句可以很直观的了解哪些列存在 “nan”, 并可以把nan的个数打印,主要的目的在于 nan存在的个数是否真的很大,如果很小一般选择填充,如果使用lgb等树模型可以直接空缺,让树自己去优化,但如果nan存在的过多、可以考虑删掉
# 可视化看下缺省值 msno.matrix(Train_data.sample(250))
msno.bar(Train_data.sample(1000))
## 非nan异常值检测 (数值型变量不在预设范围之内,object有一些没有意义的值) Train_data['notRepairedDamage'].value_counts()
可以看出来‘ - ’也为空缺值,因为很多模型对nan有直接的处理,这里我们先不做处理,先替换成nan
## 对于严重倾斜的类别型变量一般来说对预测没有什么帮助,可以考虑删除 Train_data["seller"].value_counts()
2.3.4 了解预测值的分布
## 1) 总体分布概况(无界约翰逊分布等) 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)
价格不服从正态分布,所以在进行回归之前,它必须进行转换。虽然对数变换做得很好,但最佳拟合是无界约翰逊分布。
## 2) 查看skewness and kurtosis sns.distplot(Train_data['price']); print("Skewness: %f" % Train_data['price'].skew()) print("Kurtosis: %f" % Train_data['price'].kurt())
## 3) 查看预测值的具体频数 plt.hist(Train_data['price'], orientation = 'vertical',histtype = 'bar', color ='red') plt.show()
# # log变换 z之后的分布较均匀,可以进行log变换进行预测,这也是预测问题常用的trick plt.hist(np.log(train_data['price']), orientation = 'vertical',histtype = 'bar', color ='red') plt.show()
2.3.5 特征分为类别特征和数字特征,并对类别特征查看unique分布
# 分离label即预测值 Y_train = train_data['price'] 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',] # 特征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())
2.3.6 数字特征分析
## 1) 相关性分析 (注意是对数值性进行的) numeric_features.append('price') price_numeric = train_data[numeric_features] correlation = price_numeric.corr() print(correlation['price'].sort_values(ascending = False),' ')
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)
## 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()) )
## 这里的话 没有一个特别的严格的标准,不过如果有某个特征的偏度和峰值有点离谱的话,就需要注意了
## 3) 每个数字特征得分布可视化 # melt 转化为长数据集 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")
(图省略一些...)
## 4) 数字特征相互之间的关系可视化 # 只管的看各个变量的关系 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()
## 5) 多变量互相回归关系可视化 fig, ((ax1, ax2), (ax3, ax4), (ax5, ax6), (ax7, ax8), (ax9, ax10)) = plt.subplots(nrows=5, ncols=2, figsize=(24, 20)) # ['v_12', 'v_8' , 'v_0', 'power', 'v_5', 'v_2', 'v_6', 'v_1', 'v_14'] v_12_scatter_plot = pd.concat([Y_train,train_data['v_12']],axis = 1) sns.regplot(x='v_12',y = 'price', data = v_12_scatter_plot,scatter= True, fit_reg=True, ax=ax1) v_8_scatter_plot = pd.concat([Y_train,train_data['v_8']],axis = 1) sns.regplot(x='v_8',y = 'price',data = v_8_scatter_plot,scatter= True, fit_reg=True, ax=ax2) v_0_scatter_plot = pd.concat([Y_train,train_data['v_0']],axis = 1) sns.regplot(x='v_0',y = 'price',data = v_0_scatter_plot,scatter= True, fit_reg=True, ax=ax3) power_scatter_plot = pd.concat([Y_train,train_data['power']],axis = 1) sns.regplot(x='power',y = 'price',data = power_scatter_plot,scatter= True, fit_reg=True, ax=ax4) v_5_scatter_plot = pd.concat([Y_train,train_data['v_5']],axis = 1) sns.regplot(x='v_5',y = 'price',data = v_5_scatter_plot,scatter= True, fit_reg=True, ax=ax5) v_2_scatter_plot = pd.concat([Y_train,train_data['v_2']],axis = 1) sns.regplot(x='v_2',y = 'price',data = v_2_scatter_plot,scatter= True, fit_reg=True, ax=ax6) v_6_scatter_plot = pd.concat([Y_train,train_data['v_6']],axis = 1) sns.regplot(x='v_6',y = 'price',data = v_6_scatter_plot,scatter= True, fit_reg=True, ax=ax7) v_1_scatter_plot = pd.concat([Y_train,train_data['v_1']],axis = 1) sns.regplot(x='v_1',y = 'price',data = v_1_scatter_plot,scatter= True, fit_reg=True, ax=ax8) v_14_scatter_plot = pd.concat([Y_train,train_data['v_14']],axis = 1) sns.regplot(x='v_14',y = 'price',data = v_14_scatter_plot,scatter= True, fit_reg=True, ax=ax9) v_13_scatter_plot = pd.concat([Y_train,train_data['v_13']],axis = 1) sns.regplot(x='v_13',y = 'price',data = v_13_scatter_plot,scatter= True, fit_reg=True, ax=ax10)
2.3.7 类别特征分析
## 1) nunique分布 for fea in categorical_features: print(train_data[fea].nunique())
unique()是以 数组形式(numpy.ndarray)返回列的所有唯一值(特征的所有唯一值)。nunique() 返回的是唯一值的个数。
## 2) 类别特征箱形图可视化 # 因为 name和 regionCode的类别太稀疏了,这里我们把不稀疏的几类画一下 categorical_features = ['model', 'brand', 'bodyType', 'fuelType', 'gearbox', 'notRepairedDamage'] for c in categorical_features: train_data[c] = train_data[c].astype('category') if train_data[c].isnull().any(): train_data[c] = train_data[c].cat.add_categories(['MISSING']) train_data[c] = train_data[c].fillna('MISSING') def boxplot(x, y, **kwargs): sns.boxplot(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(boxplot, "value", "price")
## 3) 类别特征的小提琴图可视化 catg_list = categorical_features target = 'price' for catg in catg_list : sns.violinplot(x=catg, y=target, data=train_data) plt.show()
categorical_features = ['model', 'brand', 'bodyType', 'fuelType', 'gearbox', 'notRepairedDamage'] ## 4) 类别特征的柱形图可视化 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")
## 5) 类别特征的每个类别频数可视化(count_plot) 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")
主要学习部分:(系统的观察数据的方式,一些可视化工具的学习)
主要参考:https://tianchi.aliyun.com/notebook-ai/detail?spm=5176.12586969.1002.12.1cd8593aw4bbL5&postId=95457