文章目录
相关阅读:
- 【机器学习竞赛+笔记干货】工业蒸汽量预测:赛题理解篇(一)
- 【机器学习竞赛+笔记干货】工业蒸汽量预测:数据探索篇(二)
- 【机器学习竞赛+笔记干货】工业蒸汽量预测:特征工程篇(三)
- 【机器学习竞赛+笔记干货】工业蒸汽量预测:模型训练篇(四)
- 【机器学习竞赛+笔记干货】工业蒸汽量预测:模型验证篇(五)
- 【机器学习竞赛+笔记干货】工业蒸汽量预测:特征优化篇(六)
- 【机器学习竞赛+笔记干货】工业蒸汽量预测:模型融合篇(七)
比赛地址:工业蒸汽量预测_学习赛_天池大赛
2 数据探索
2.1 理论知识
2.1.2 变量分析
1. 单变量分析
(1)连续型变量
需要统计数据的中心分布趋势和变量的分布。
(2)类别型变量
一般使用频次或占比表示每一个类别的分布情况,对应的衡量指标分别是类别变量的频次(次数)和频率(占比),可以用柱形图来表示可视化分布情况。
2. 双变量分析
使用双变量分析可以发现变量之间的关系。
(1)连续型与连续型
- 绘制散点图:散点图的形状可以反映变量之间的关系是线性还是非线性。
- 计算相关性:相关性可以对变量之间的关系进行量化分析。
C
o
r
r
e
l
a
t
i
o
n
=
C
o
v
a
r
i
a
n
c
e
(
X
,
Y
)
V
a
r
(
X
)
∗
V
a
r
(
Y
)
Correlation=\frac{Covariance(X,Y)}{\sqrt{Var(X)*Var(Y)}}
Correlation=Var(X)∗Var(Y)Covariance(X,Y)
取值区间为 [ − 1 , 1 ] [-1,1] [−1,1].
计算X与Y的相关系数:
import numpy as np
X=np.array([1,2,3,4,5])
Y=np.array([6,7,8,9,0])
np.corrcoef(X,Y)
一般来说,在取绝对值后,00.09为没有相关性,0.10.3为弱相关,0.30.5为中等相关,0.51.0为强相关。
(2)类别型与类别型
-
双向表:通过建立频次(次数)和频率(占比)的双向表来分析变量之间的关系。行和列分别表示一个变量。
-
堆叠柱状图:比双向表更加直观。
-
卡方检验:主要用于两个和两个以上样本率(构成比)及两个二值型离散变量的关联性分析,即比较理论频次和实际频次的吻合程度或拟合优度。
以iris数据集为例,在sklearn库中使用卡方检验筛选与目标变量相关的特征,代码如下:
from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
iris=load_iris()
X,y=iris.data,iris.target
chiValues=chi2(X,y)
X_new=SelectKBest(chi2,k=2).fit_transform(X,y)
(3)类别型与连续型
- 绘制小提琴图(Violin Plot):可以分析类别变量在不同类别时,另一个连续变量的分布情况。
小提琴图结合了箱形图和密度图的相关特征信息,可以直观、清晰地显示数据的分布,常用于展示多组数据的分布及相关地概率密度。
建议使用Seaborn包中的violinplot()函数。
2.1.3 缺失值处理
1. 缺失值的产生原因和分类
缺失值的产生原因主要分为机械原因和人为原因。
从缺失的分布来看,缺失值主要分为以下四类:
- 完全随机丢失:对于所有的观察结果,丢失的概率是相同的。
- 随即丢失:变量的值随即丢失并且丢失的概率会因为其他输入变量的值或级别不同而变化。
- 不可预测因子导致的缺失:数据不是随机缺失,而是受一切潜在因子的影响。
- 取决于自身的缺失:发生缺失的概率受缺失值本身的影响。
2. 缺失值的处理方法
(1)删除
- 成列删除(List Wise Deletion)(PS:删除一整行)
- 成对删除(Pair Wise Deletion)(PS:删除单个值)
说明:当缺失数据性质为“完全随机丢失”时,删除缺失值可能会让模型的输出产生偏离。
(2)平均值、众数、中值填充
利用从有效数据集中识别出的关系来评估缺失值,然后用计算的该变量所有已知值的平均值或终止(定量属性)或众数(定性属性)来替换给定属性的缺失值。
- 一般填充:用该变量下所有非缺失值的平均值或中值来填补缺失值。
- 相似样本填充:利用具有相似特征的样本的值或者近似值进行填充。
(3)预测模型填充
通过简历预测模型来填补缺失值。
把数据集分成两份:一份是没有缺失值的,用作训练集;另一份是有缺失值的,用作测试集。此时可以使用回归、分类的方法来完成填充。
不足之处在于,预测出来的值往往更加“规范”;其次,如果变量之间不存在关系,则得到的缺失值会不准确。
2.1.4 异常值处理
通常将远远偏离整个样本总体的观测值成为异常值。
1. 异常值的产生原因和影响
异常值对模型和预测分析的影响主要有增加错误方差,降低模型的拟合能力;异常值的非随机分布会降低正态性;与真实值可能存在偏差;影响回归、方差分析德国统计模型的基本假设。
2. 异常值的检测
一般可以采用可视化的方法进行异常值的检测,常用工具包括箱线图、直方图、散点图等。
利用箱线图检测异常值的原则:
-
不在-1.5* IQR和1.5* IQR之间的样本点认为是异常值。
-
使用封顶方法在第5和第95百分位数范围之外的任何值都是异常值。
-
距离平均值为三倍标准差或更大的数据点可以被认为是异常值。
说明:由于异常值只是对有影响的特殊数据点进行检测,因此它的选择也取决于对业务的理解。
有可能通过箱线图观察单变量的分布,没有找到任何异常值,但是通过散点图看双变量分布,会观察到异常值。
3. 异常值的处理方法
- 删除:如果是由输入误差、数据处理误差引起的异常值,或者异常值很小,则可以直接将其删除。
- 转换:数据转换可以消除异常值。如对数据取对数会减轻由极值引起的变化。
- 填充:利用平均、中值或其他一些填补方法。如果异常值不是自然形成的,而是人为造成的,则可以进行填充处理。
- 区别对待:如果存在大量的异常值,则应该在统计模型中区别对待。例如将数据分为异常值和非异常值两组分别建立模型,最后合并输出。
2.1.5 变量转换
1. 变量转换的目的
在使用直方图、核密度估计等工具对特征分布进行分析的过程中,一些变量的取值分布不均匀,这将会极大影响估计。因此需要对变量的取值区间进行转换,使其分布落在合理的区间内。
2. 变量转换的方法
主要包括缩放比例或标准化、非线性关系转化为线性、使倾斜分布对称、变量分组等。
- 对数变换:对变量取对数,更改变量的分布形状。通常应用于向右倾斜的分布,缺点是不能用于含有零或负值的变量。
- 取平方根或立方根:对其分布有波形的影响。
- 变量分组:对变量进行分类。如可以基于原始值、百分比或频率等对变量分类。
2.1.6 新变量生成
1. 变量生成的目的
生成的新变量可能与目标变量有着更好地相关性,有助于进行数据分析。
2. 变量生成的方法
(1)创建派生变量
使用一组函数或不同方法从现有变量创建新变量。
(2)创建哑变量
可将类别型变量转化为数值型变量。
2.2 赛题数据探索
2.2.4 可视化数据分布
以可视化方式对数据特征、数据分布等进行探索分析。
1. 箱形图
绘制训练集中各变量的箱形图。
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)
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):
# predit y values using model
try:
y_pred=pd.Series(model.predit(X),index=y.index)
# if predicting fails, trying fitting the model first
except:
model.fit(X,y)
y_pred=pd.Series(model.predit(X),index=y.index)
# calculate residuals between the model orediction 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 plotthe 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','Qutlier'])
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)
plot.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)
说明:也可以采用其他回归模型代替岭回归模型。
3. 直方图和Q-Q图
Q-Q图是指数据的分位数和正态分布的分位数对比参照的图,如果数据符合正态分布,则所有的点都会落在直线上。
绘制训练集中所有变量的直方图和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()
对于分布不是正态的,并不跟随对角线分布的数据,后续可以使用数据变换对其进行处理。
4. KDE分布图
KDE(Kernel Density Estimation,核密度估计)可以理解为是对直方图的加窗平滑。
通过KDE分布图,可以查看并对比训练集和测试集中特征变量的分布情况,发现两个数据集中分布不一致的特征变量。
对比所有变量在训练集和测试集中的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()
在训练集和测试集中分布不一致的变量,会导致模型的泛化能力变差,需要删除此类特征。
5. 线性回归关系图
线性回归关系图主要用于分析变量之间的线性回归关系。
查看所有特征变量与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={'market':'.','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)
2.2.5 查看特征变量的相关性
可以发现特征变量和目标变量及特征变量之间的关系,为在特征工程中提取特征做准备。
1. 计算相关系数
在删除训练集和测试集中分布不一致的特征变量之后,计算剩余特征变量及target变量的相关性系数。
pd.set_option('display.max_columns',10)
pd.set_option('display.max_rows',10)
data_train1=train_data.drop(['V5','V9','V11','V17','V22','V28'],axis=1)
train_corr=data_train1.corr()
# 为了便于分析,将相关系数的结果以热力图的形式显示。
ax=plt.subplots(figsize=(20,16))
ax=sns.heatmap(train_corr,vmax=.8,square=True,annot=True)
3. 根据相关系数筛选特征变量
寻找K个与target变量最相关的特征变量:
k=0
cols=train_corr.nlargest(k,'target')['target'].index
cm=np.corrcoef(train_data[cols].values.T)
hm=plt.subplots(figsize=(10,10))
hm=sns.heatmap(train_data[cols].corr(),annot=True,square=True)
plt.show()
找出与target变量的相关系数大于0.5的特征变量:
threshold=0.5
corrmat=train_data.corr()
top_corr_features=corrmat.index[abs(corrmat['target'])>threshold]
plt.figure(figsize=(10,10))
g=sns.heatmap(train_data[top_corr_features].corr(),annot=True,cmap='RdY1Gn')
说明:相关性选择主要用于判别线性相关,对于target变量如果存在更复杂的函数形式的影响,则建议使用树模型的特征重要性去选择。
用相关系数阈值移除相关特征:
threshold=0.5
corr_matrix=data_train1.corr().abs()
drop_col=corr_matrix[corr_matrix['target']<threshold].index
data_all.drop(drop_col,axis=1,inplace=True)
4. Box-Cox变换
由于线性回归是基于正态分布的,在进行统计分析时,需要将数据转换使其符合正态分布。
Box-Cox变换:统计建模中常用的一种数据转换方法,适用于不满足正态分布的连续的响应变量。
- 可以使线性回归模型在满足线性、正态性、独立性及方差齐性的同时,又不丢失信息。
- 可以在一定程度上减小不可观测的误差和预测变量的相关性,这有利于线性模型的拟合及分析出特征的相关性。
在做Box-Cox变换前,需要对数据做归一化预处理。
如果在线下分析建模,可以在归一化时,对数据进行合并操作,是训练数据和测试数据一致。
drop_columns=['V5','V9','V11','V17','V22','V28']
# 合并数据集
train_x=train_data.drop(['target'],axis=1)
data_all=pd.concat([train_x,test_data])
data_all.drop(drop_columns,axis=1,inplace=True)
对合并后的每列数据进行归一化:
cols_numeric=list(data_all.columns)
def scale_minmax(col):
return (col-col.min())/(col.max()-col.min())
data_all[cols_numeric]=data_all[col_numeric].apply(scale_minmax,axis=0)
data_all[col_numeric].describe()
若分开对训练数据和测试数据进行归一化处理,需要建立在两者分布一致的前提下,建议在数据量大的情况下使用(一般分布比较一致),能加快归一化的速度。
train_data_process=train_data[cols_numeric]
train_data_process=train_data_process[col_numeric].apply(scale_minmax,axis=0)
test_data_process=test_data[cols_numeric]
test_data_process=test_data_process[col_numeric].apply(scale_minmax,axis=0)
在数据分析和线下建模中应该将数据统一归一化。
对特征变量做Box-Cox变换后,计算分位数并画图展示(基于正态分布),显示特征变量与target变量的线性关系。
cols_numeric_left=cols_numeric[0:13]
cols_numeric_right=cols_numeric[13:]
train_data_process=pd.concat([train_data_process,train_data['target']],axis=0)
fcols=6
frows=len(cols_numeric_left)
plt.figure(figsize=(4*fcols,4*frows))
i=0
for var in cols_numeric_left:
dat=train_data_process[[var,'target']].dropna()
i+=1
plt.subplot(frows,fcols,i)
sns.distplot(dat[var],fit=stats.norm)
plt.title(var+'Original')
plt.xlabel('')
i+=1
plt.subplot(frows,fcols,i)
_=stats.probplot(dat[var],plot=plt)
plt.title('skew='+'{:.4f}'.format(stats.skew(dat[var])))
plt.xlabel('')
plt.ylabel('')
i+=1
plt.subplot(frows,fcols,i)
plt.plot(dat[var],dat['target'],'.',alpha=0.5)
plt.title('corr='+'(:.2f}'.format(np.corrcoef(dat[var],dat['target'])[0][1]))
i+=1
plt.subplot(frows,fcols,i)
trans_var,lambda_var=stats.boxcox(dat[var].dropna()+1)
trans_var=scale_minmax(trans_var)
sns.distplot(trans_var,fit=stats.norm)
plt.title(var+' Tramsformed'),
plt.xlabel('')
i+=1
plt.subplot(frows,fcols,i)
_=stats.probplot(trans_var,plot=plt)
plt.title('skew='+'{:.4f}'.format(stats.skew(trans_var)))
plt.xlabe1('')
plt.ylabel('')
i+=1
plt.subplot(frows,fcols,i)
plt.plot(trans_var,dat['target'],'.',alpha=0.5)
plt.title('corr='+'{:.2f}'.format(np.corrcoef(trans var,dat['target'])[0][1]))
经过变换后,变量分布更接近正态分布。