结合个人学习及网上参考资料,先将从数据集加载、预处理、建模流程总结如下,文中参考了很多现有资料,该文仅供自身学习与学术交流。
import numpy as np
import pandas as pd
import pandas as pd
train = pd.read_csv("train.csv")
test = pd.read_csv("test.csv")
def loadDataSet(fileName):
"""
加载文件数据
:param fileName:
:return:
"""
numFeat = len(open(fileName).readline().split('\t')) - 1
dataMat = []; labelMat = []
fr = open(fileName)
for line in fr.readlines():
lineArr =[]
curLine = line.strip().split('\t')
for i in range(numFeat):
lineArr.append(float(curLine[i]))
dataMat.append(lineArr)
labelMat.append(float(curLine[-1]))
return dataMat,labelMat
通过对数据进行探索,我们可以对数据的基本特征有一个全局的大致了解。
train.head() #可以查看(默认)前5行数据信息。
train.tail() #可以查看后10行数据信息。
train.columns
train.describe()
train["feature"].describe()
import seaborn as sns
sns.distplot(train["feature"])
import matplotlib.pyplot as plt
output,var,var1,var2 = 'SalePrice','GrLivArea','TotalBsmtSF','OverallQual'
fig,axis = plt.subplots(1,3,figsize=(16,5))
train.plot.scatter(x=var,y=output,ylim=(MIN_VALUE,MAX_VALUE),ax=axis[0])
train.plot.scatter(x=var1,y=output,ylim=(MIN_VALUE,MAX_VALUE),ax=axis[1])
train.plot.scatter(x=var2,y=output,ylim=(MIN_VALUE,MAX_VALUE),ax=axis[2])
import matplotlib.pyplot as plt
import seaborn as sns
var_set = ["feature1","feature2","feature3","feature4","feature5","feature6"]
sns.set(font_scale=1.25) #设置坐标轴的字体大小
sns.pairplot(train[var_set]) ## 可在kind和diag_kind参数下设置不同的显示类型,此处分别为散点图和直方图,还可以设置每个图内的不同类型的显示
plt.show()
import matplotlib.pyplot as plt
import seaborn as sns
corrmat = train.corr()
f,axis = plt.subplot(figsize=(14,12))
sns.heatmap(corrmat,vmax=0.8,square=True,ax=axis)
plt.show()
import matplotlib.pyplot as plt
import seaborn as sns
corrmat = train.corr()
k = 10
top10_attr = corrmat.nlargest(k,output).index #output代表的是目标变量
top10_mat = corrmat.loc[top10_attr,top10_attr]
fig,axis = plt.subplots(figsize=(14,10))
sns.set(font_scale=1.25)
sns.heatmap(top10_mat,annot=True,annot_kws={"size":12},square=True)
plt.show()
def anova(data,columns):
anv = pd.DataFrame()
anv["feature"] = columns
pvals = []
for c in columns:
samples = []
for cls in data[c].unique():
s = data[data[c]==cls]['SalePrice'].values
samples.append(s) #某特征下不同取值对应的房价组合形成的二维列表
pval = stats.f_oneway(*samples)[1] #一元方差分析得到 F,P,要的是 P,P越小,对方差的影响越大。
pvals.append(pval)
anv['pval'] = pvals
return anv.sort_values('pval')
a = anova(train,category_feature)
a['disparity'] = np.log(1./a['pval'].values)
fig,axis = plt.subplots(figsize=(14,12))
sns.barplot(data = a ,x = 'feature',y='disparity')
#选择x轴变量名的位置
x = plt.xticks(rotation=90)
plt.show()
对数据的预处理主要分为以下几个方面:
缺失值处理有两种方案: 一种是分析含缺失值的特征对任务有没有用,没有的特征直接删除,有用的特征依据缺失量,少则删除样本,多则用mean,median,mode补全。 另一种是分析这些缺失值缺失的原因,并用一定方法将其转换为一类数据(成为类型变量的一个类型)。
na_count = train.isnull().sum().sort_values(ascending = False)
na_count = na_count[na_count.values>0]
na_rate = na_count/len(train)
na_data = pd.concat([na_count,na_rate],axis = 1,keys = ["count",'ratio'])
接下来我们就可以根据统计结果来对不同的特征缺失值做不同的处理。
一般的,如果某一特征的数据缺失量达到15%以上,我们应该删除这些特征(当然具体还要看特征对目标变量的影响)。
原作者博文是 15%,个人不敢苟同,缺失值 10% ~ 15% 以内,可以采用删除,但是高于 15% 不见得就要删除,其缺失信息可能代表着一种信息,如表明用户是不活跃用户等,可以结合考虑将其归为单独一类。
对于缺失量很小的特征,我们可以直接删除缺失值的那些样本即可。(个人推荐 10% 之内)
还有一些特征可能代表的是某一种相同的信息,或者和已存在的某些特征具有较强的相关性,这样的话我们可以删除此类特征,保留一个有效特征即可。
train.drop()
#类型变量特征集合
category_feature = [attr for attr in train.columns if train.columns[attr]=='object']
#数值变量特征集合
number_feature = [attr for attr in train.columns if train.columns[attr]!='object']
类型变量特征缺失值补全(对于类型变量特征的缺失值,一般用样本中最多的,或者 Missing 填充。具情况而定)
#使用 Missing 填充
train[feature].fillna("Missing",inplace = True)
#使用样本中最多的填充
train[feature].fillna(train[feature].mode()[0],inplace = True)
数值变量特征缺失值补全(对于数值型变量特征我们一般使用 mean , median, mode或者0。具情况而定)
train[feature].fillna(0.,inplace = True)
train[feature].fillna(train[feature].mean(),inplace = True) #平均值
train[feature].fillna(train[feature].median(),inplace = True) #中位数
train[feature].fillna(train[feature].mode()[0],inplace = True) #众数
一般的我们可以使用 One-Hot编码来处理类别型特征。
train = pd.get_dummies(train)
# df['B'] = df.replace({'a':0,'b':1,'c':2}) 自定义替换
但在我们的特征中,有些类别特征明显与目标变量有较强的线性关系,对于此类特征,我们应将其转化为数值特征。
所有类型变量,依照各个类型变量的不同取值对应的样本集内房价的均值,按照房价均值高低对此变量的当前取值确定其相对数值1,2,3,4等等,相当于对类型变量赋值使其成为连续变量。
此方法采用了与 One-Hot 编码不同的方法来处理离散数据,值得学习!
def encode(data,feature,test):
ordering = pd.DataFrame()
ordering['val'] = data[feature].unique()
ordering.index = ordering.val
# groupby()操作可以将某一feature下同一取值的数据整个到一起,结合mean()可以直接得到该特征不同取值的房价均值
ordering['price_mean'] = data[[feature,'SalePrice']].groupby(feature).mean()
ordering = ordering.sort_values('price_mean')
ordering['order'] = range(1,ordering.shape[0]+1)
ordering = ordering['order'].to_dict()
for attr, score in ordering.items():
data.loc[data[feature] == attr, feature+'_E'] = score
test.loc[test[feature] == attr, feature+'_E'] = score
for feature in category_feature:
encode(train,feature,test)
train.drop(category_feature,axis=1,inplace=True)
test.drop(category_feature,axis=1,inplace=True)
def spearman(train, features):
'''
采用“斯皮尔曼等级相关”来计算变量与房价的相关性(可查阅百科)
此相关系数简单来说,可以对encoder()处理后的等级变量及其它与房价的相关性进行更好的评价(特别是对于非线性关系)
'''
spr = pd.DataFrame()
spr['feature'] = features
spr['corr'] = [train[f].corr(train['SalePrice'], 'spearman') for f in features]
spr = spr.sort_values('corr')
plt.figure(figsize=(6, 0.25*len(features)))
sns.barplot(data=spr, y='feature', x='corr', orient='h')
features = train.columns
spearman(train, features)
features = train.columns #此时的 train 是已经把类别特征转换成数值特征的数据集
category_E= []
for q in category_feature:
category_E.append(q+"_E")
plt.figure(1,figsize=(12,9)) # 连续型变量相关图
corr = train3[number_feature+['SalePrice']].corr()
sns.heatmap(corr)
plt.figure(2,figsize=(12,9)) # 类别型变量相关图(离散型和伪数值型变量均已被概括为等级型变量)
corr = train3[category_E+['SalePrice']].corr('spearman')
sns.heatmap(corr)
plt.figure(3,figsize=(12,9)) # 连续型变量-类别型变量相关图
corr = pd.DataFrame(np.zeros([len(number_feature)+1, len(category_E)+1]),
index=number_feature+['SalePrice'], columns=category_E+['SalePrice'])
for q1 in number_feature+['SalePrice']:
for q2 in category_E+['SalePrice']:
corr.loc[q1, q2] = train3[q1].corr(train3[q2], 'spearman')
sns.heatmap(corr)
同上面相反,如果有些数值特征和我们的目标变量没有明显的线性关系,对于此类特征,我们应该将其转化为类别特征
train[feature1] = train[feature1].astype(str)
train[feature2] = train[feature2].astype(str)
train[feature3] = train[feature3].astype(str)
train[feature4] = train[feature4].astype(str)
注:上述方法太暴力,其中数值型变量往往取值较多,若是按照上述做法,等于为每一种取值都设定为一个单独类别;
事实上,更实用的方法往往是通过分桶策略实现,其中分桶策略简单包含等频分桶和等距分桶,也有通过树模型进行分桶,分桶策略先mark一下,后续总结一篇新的博文专门介绍。
我们可以通过散点图发现那些离散点,进而删除该样本点。
#绘制散点图
import matplotlib.pyplot as plt
output,var,var1,var2 = 'SalePrice','GrLivArea','TotalBsmtSF','OverallQual'
fig,axis = plt.subplots(1,3,figsize=(16,5))
train.plot.scatter(x=var,y=output,ylim=(MIN_VALUE,MAX_VALUE),ax=axis[0])
train.plot.scatter(x=var1,y=output,ylim=(MIN_VALUE,MAX_VALUE),ax=axis[1])
train.plot.scatter(x=var2,y=output,ylim=(MIN_VALUE,MAX_VALUE),ax=axis[2])
#删除离散样点
train.drop(train[(train['Feature']>4000)&(train['Target']<300000)].index,inplace=True)
我们要根据项目的实际情况选择合适的模型,然后对模型超差调优,交叉验证,最后可以尝试融合多个模型。
#交叉验证
from sklearn import model_selection
cvSplit = model_selection.KFold(10)
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression()
param = {"C":[0.1,0.5,0.8,1,10],"max_iter":[100,200,300]}
#自动选择最优参数
clf = model_selection.GridSearchCV(lr,param,scoring="roc_auc",cv=cvSplit)
clf.fit(X_train,Y_train)
#打印最佳得分和最佳参数
print(clf.best_score_,clf.best_params_)
#预测结果
clf_pre = clf.predict(X_test)
clf_sub = pd.DataFrame({"PassengerId":test_df["PassengerId"],"Survived": clf_pre})
clf_sub.to_csv("../data/clf_sub.csv", index=False)
#保存模型
from sklearn.externals import joblib
joblib.dump(clf,"clf.m")
#恢复模型
rf_load = joblib.load("clf.m")
from sklearn.ensemble import VotingClassifier
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression(C=0.5,max_iter=100)
import xgboost as xgb
xgb_model = xgb.XGBClassifier(max_depth=6,n_estimators=100)
from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier(n_estimators=200,min_samples_leaf=2,max_depth=6,oob_score=True)
from sklearn.ensemble import GradientBoostingClassifier
gbdt = GradientBoostingClassifier(learning_rate=0.1,min_samples_leaf=2,max_depth=6,n_estimators=100)
vot = VotingClassifier(estimators=[('lr',lr),('rf',rf),('gbdt',gbdt),('xgb',xgb_model)],voting='hard')
vot.fit(X_train,Y_train)
print(round(vot.score(X_train,Y_train)*100,2))
vot_pre = vot.predict(X_test)
vot_sub = pd.DataFrame({"PassengerId":test_df["PassengerId"],"Survived":vot_pre})
vot_sub.to_csv("../data/vot_sub.csv",index=False)
from sklearn.linear_model import LogisticRegression
import xgboost as xgb
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import GradientBoostingClassifier
clfs = [LogisticRegression(C=0.5, max_iter=100),
xgb.XGBClassifier(max_depth=6, n_estimators=100, num_round=5),
RandomForestClassifier(n_estimators=100, max_depth=6, oob_score=True),
GradientBoostingClassifier(learning_rate=0.3, max_depth=6, n_estimators=100)]
clf2 = LogisticRegression(C=0.5,max_iter=100)
#==========================StackingClassifier====================================#
from mlxtend.classifier import StackingClassifier,StackingCVClassifier
sclf = StackingClassifier(classifiers=clfs,meta_classifier=clf2)
sclf.fit(X_train,Y_train)
print(sclf.score(X_train,Y_train))
sclf_pre = sclf.predict(X_test)
sclf_sub = pd.DataFrame({"PassengerId":test_df["PassengerId"],"Survived":sclf_pre})
sclf_sub.to_csv("../data/sclf_sub.csv",index=False)
#========================StackingCVClassifier===================================#
sclf2 = StackingCVClassifier(classifiers=clfs,meta_classifier=clf2,cv=5)
x = np.array(X_train)
y = np.array(Y_train).flatten()
sclf2.fit(x,y)
print(sclf2.score(x,y))
sclf2_pre = sclf2.predict(np.array(X_test))
sclf2_sub = pd.DataFrame({"PassengerId": test_df["PassengerId"], "Survived": sclf2_pre})
http://www.dehong.space/MachineLearning-Data