2.2.4 可视化数据分布
下面以可视化方式对数据特征、数据分布等进行探索分析。
1. 箱形图
首先绘制训练集中特征变量V0 的箱形图:
fig = plt.figure(figsize=(4, 6)) # 指定绘图对象的宽度和高度
sns.boxplot(train_data['V0'],orient="v", width=0.5)
运行结果:
从图中可以看出有偏离值,许多数据点位于下四分位点以下。
然后绘制训练集中变量V0~V37 的箱形图:
column = train_data.columns.tolist()[:39] # 列表头
fig = plt.figure(figsize=(80, 60), dpi=75) # 指定绘图对象的宽度和高度
for i in range(38):
plt.subplot(7, 8, i + 1) # 7 行8 列子图
sns.boxplot(train_data[column[i]], orient="v", width=0.5) #箱式图
plt.ylabel(column[i], fontsize=36)
plt.show()
运行结果:
从图中发现数据存在许多偏离较大的异常值,可以考虑移除。
2. 获取异常数据并画图
此方法是采用模型预测的形式找出异常值,可在看完模型训练和验证的理论讲解后,再回来仔细查看下面的代码。
获取异常数据的函数,代码如下:
# function to detect outliers based on the predictions of a model
def find_outliers(model, X, y, sigma=3):
# predict y values using model
try:
y_pred = pd.Series(model.predict(X), index=y.index)
# if predicting fails, try fitting the model first
except:
model.fit(X,y)
y_pred = pd.Series(model.predict(X), index=y.index)
# calculate residuals between the model prediction and true y values
resid = y - y_pred
mean_resid = resid.mean()
std_resid = resid.std()
# calculate z statistic, define outliers to be where |z|>sigma
z = (resid - mean_resid)/std_resid
outliers = z[abs(z)>sigma].index
# print and plot the results
print('R2=',model.score(X,y))
print("mse=",mean_squared_error(y,y_pred))
print('---------------------------------------')
print('mean of residuals:',mean_resid)
print('std of residuals:',std_resid)
print('---------------------------------------')
print(len(outliers),'outliers:')
print(outliers.tolist())
plt.figure(figsize=(15,5))
ax_131 = plt.subplot(1,3,1)
plt.plot(y,y_pred,'.')
plt.plot(y.loc[outliers],y_pred.loc[outliers],'ro')
plt.legend(['Accepted','Outlier'])
plt.xlabel('y')
plt.ylabel('y_pred');
ax_132=plt.subplot(1,3,2)
plt.plot(y,y-y_pred,'.')
plt.plot(y.loc[outliers],y.loc[outliers]-y_pred.loc[outliers],'ro')
plt.legend(['Accepted','Outlier'])
plt.xlabel('y')
plt.ylabel('y - y_pred');
ax_133=plt.subplot(1,3,3)
z.plot.hist(bins=50,ax=ax_133)
z.loc[outliers].plot.hist(color='r',bins=50,ax=ax_133)
plt.legend(['Accepted','Outlier'])
plt.xlabel('z')
plt.savefig('outliers.png')
return outliers
通过岭回归模型找出异常值,并绘制其分布,代码如下:
from sklearn.linear_model import Ridge
from sklearn.metrics import mean_squared_error
X_train=train_data.iloc[:,0:-1]
y_train=train_data.iloc[:,-1]
outliers = find_outliers(Ridge(), X_train, y_train)
运行结果:
R2= 0.8890858938210386
mse= 0.10734857773123635
---------------------------------------
mean of residuals: 7.686602970006927e-17
std of residuals: 0.3276976673193503
---------------------------------------
31 outliers:
[321, 348, 376, 777, 884, 1145, 1164, 1310, 1458, 1466, 1484, 1523, 1704,
1874, 1879, 1979, 2002, 2279, 2528, 2620, 2645, 2647, 2667, 2668, 2669, 2696,
2767, 2769, 2807, 2842, 2863]
说明:也可以采用其他回归模型代替岭回归模型。
3. 直方图和Q-Q 图
Q-Q 图是指数据的分位数和正态分布的分位数对比参照的图,如果数据符合正态分布,则所有的点都会落在直线上。首先,通过绘制特征变量V0 的直方图查看其在训练集中的统计分布,并绘制Q-Q 图查看V0 的分布是否近似于正态分布。
绘制变量V0 的直方图和Q-Q 图,代码如下:
plt.figure(figsize=(10,5))
ax=plt.subplot(1,2,1)
sns.distplot(train_data['V0'],fit=stats.norm)
ax=plt.subplot(1,2,2)
res = stats.probplot(train_data['V0'], plot=plt)
运行结果:
可以看到,训练集中特征变量V0 的分布不是正态分布。
然后,绘制训练集中所有变量的直方图和Q-Q 图。
train_cols = 6
train_rows = len(train_data.columns)
plt.figure(figsize=(4*train_cols,4*train_rows))
i=0
for col in train_data.columns:
i+=1
ax=plt.subplot(train_rows,train_cols,i)
sns.distplot(train_data[col],fit=stats.norm)
i+=1
ax=plt.subplot(train_rows,train_cols,i)
res = stats.probplot(train_data[col], plot=plt)
plt.tight_layout()
plt.show()
篇幅所限,这里只展示一部分结果:
从数据分布图可以发现,很多特征变量(如V1,V9,V24,V28 等)的数据分布不是正态的,数据并不跟随对角线分布,后续可以使用数据变换对其进行处理。
4. KDE 分布图
KDE(Kernel Density Estimation,核密度估计)可以理解为是对直方图的加窗平滑。通过绘制KDE 分布图,可以查看并对比训练集和测试集中特征变量的分布情况,发现两个数据集中分布不一致的特征变量。
首先对比同一特征变量V0 在训练集和测试集中的分布情况,并查看数据分布是否一致。
plt.figure(figsize=(8,4),dpi=150)
ax = sns.kdeplot(train_data['V0'], color="Red", shade=True)
ax = sns.kdeplot(test_data['V0'], color="Blue", shade=True)
ax.set_xlabel('V0')
ax.set_ylabel("Frequency")
ax = ax.legend(["train","test"])
运行结果:
可以看到,V0 在两个数据集中的分布基本一致。
然后,对比所有变量在训练集和测试集中的KDE 分布。
dist_cols = 6
dist_rows = len(test_data.columns)
plt.figure(figsize=(4 * dist_cols, 4 * dist_rows))
i = 1
for col in test_data.columns:
ax = plt.subplot(dist_rows, dist_cols, i)
ax = sns.kdeplot(train_data[col], color="Red", shade=True)
ax = sns.kdeplot(test_data[col], color="Blue", shade=True)
ax.set_xlabel(col)
ax.set_ylabel("Frequency")
ax = ax.legend(["train", "test"])
i += 1
plt.show()
运行结果(这里只展示部分结果):
图1-2-12 分布不一致的特征
5. 线性回归关系图
线性回归关系图主要用于分析变量之间的线性回归关系。首先查看特征变量V0 与target变量的线性回归关系。
fcols = 2
frows = 1
plt.figure(figsize=(8,4),dpi=150)
ax=plt.subplot(1,2,1)
sns.regplot(x='V0', y='target', data=train_data, ax=ax,
scatter_kws={'marker':'.','s':3,'alpha':0.3},
line_kws={'color':'k'});
plt.xlabel('V0')
plt.ylabel('target')
ax=plt.subplot(1,2,2)
sns.distplot(train_data['V0'].dropna())
plt.xlabel('V0')
plt.show()
运行结果:
然后查看所有特征变量与target 变量的线性回归关系。
fcols = 6
frows = len(test_data.columns)
plt.figure(figsize=(5*fcols,4*frows))
i=0
for col in test_data.columns:
i+=1
ax=plt.subplot(frows,fcols,i)
sns.regplot(x=col, y='target', data=train_data, ax=ax,
scatter_kws={'marker':'.','s':3,'alpha':0.3},
line_kws={'color':'k'});
plt.xlabel(col)
plt.ylabel('target')
i+=1
ax=plt.subplot(frows,fcols,i)
sns.distplot(train_data[col].dropna())
plt.xlabel(col)
运行结果: