数据挖掘经验
- 应用机器学习,千万不要上来就想做完美的模型,要先撸一个baseline的model出来,再进行分析提高。【后续分析可能包括模型的过/欠拟合、我们模型预测的bad case的产生原因等等,针对去分析】
- 大神们的experience:
1.【对数据的认识太重要了!】
2.【数据中的特殊点/离群点的分析和处理太重要了!】
3.【特征工程(feature engineering)太重要了!】
4.【要做模型融合(model ensemble)啊!】
项目实战
1.流程
1.初探数据
我们得先知道数据长啥样,大体都有哪些基本特征;
常用的函数:
train_data = pd.read_csv("./Train.csv") #读取路径
train_data.info() #大体特征浏览
train_data.describe() #数值型数据的一些分布
【对数据的认识太重要了!】
【对数据的认识太重要了!】
【对数据的认识太重要了!】
我们只看数据也不好分析出个啥,来把数据变成图吧
常用的函数:
import matplotlib.pyplot as plt
fig = plt.figure()
fig.set(alpha=0.2) # 设定图表颜色alpha参数
plt.subplot2grid((2,3),(0,0)) #第一个参数表示整个图片分成几块,第二个参数表示此子图所在的位置
data_train.Survived.value_counts().plot(kind='bar') #value_counts统计此特征不同类别出现的数量,kind表示打印图的种类
plt.xlabel(u"年龄") # x轴
plt.ylabel(u"密度") # y轴
plt.legend() #给图加说明
fig.tight_layout() #固定子图之间的界限
data_train.groupby() #可以用于统计指定类别对指定类别的影响
2.数据预处理
上个步骤对数据的情况大致看了一遍,对感兴趣的feature心中也有了数,下一步要处理这些数据,为建模做准备辽
【数据工程(feature engineering)太重要了!】
【数据工程(feature engineering)太重要了!】
【数据工程(feature engineering)太重要了!】
处理属性先从最突出的feature入手。
- 通常遇到缺值情况,会有几种常见的解决方法:
- 如果缺值的样本占总数比例极高,我们可能就直接舍弃了,作为特征加入的话,可能反倒带入noise,影响最后的结果了
- 如果缺值的样本比例适中,而该属性是非连续值特征属性(比如说类目属性),那就把NaN作为一个新类别,加到类别特征中
- 如果缺值的样本比例适中,而该属性为连续值特征属性,有时候我们会考虑给定一个step(比如这里的age,我们可以考虑每隔2、3岁为一个step),然后把它离散化,之后把NaN作为一个type加到属性类目中
- 有些情况下,缺失的值个数并不是特别多,那我们也可以试着根据已有的值,拟合数据补全(如随机森林等方法)
- 特征因子化:
将分类型特征因子化 - 处理特征值波动大的属性:
通过上述操作把所有特征的值都转成了数值型,但有的特征的值波动范围太大了,影响收敛速度甚至不收敛,利用scaler归一化
常用函数:
#1. 借助randomForest来拟合补全特征
from sklearn.ensemble import RandomForestRegressor
#训练rfr模型
rfr = RandomForestRegressor(random_state=0, n_estimators=2000, n_jobs=-1)
rfr.fit(X_train, y_train) #训练
prediction = rfr.predict(X_test) #预测
train_data.loc() #按指定维度提取或填充数据
#2. 借助get_dummies()函数因子化类目型特征
dummies_Cabin = pd.get_dummies(data_train['Cabin'], prefix= 'Cabin')
#3. 借助scaler()函数因子化类目型特征
import sklearn.preprocessing as preprocessing
scaler = preprocessing.StandardScaler()
data_train['Age_scaled'] = scaler.fit_transform(data_train['Age'].values.reshape(-1,1)) #fit_transform、fit、transform
3.建模
feature已经处理好了,接下来就是送入model中训练嘞!
#1. 提取需要的feature字段,filter函数
data_train.filter(regex = 'Survived|Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*')
data_train_feats = data_train.values #转成np格式
#2. 选择模型,进行训练
from sklearn import linear_model
from sklearn.ensemble import BaggingClassifier
#lg模型及训练
clf = linear_model.LogisticRegression(C=1.0, penalty='l2', tol=1e-6)
clf.fit(data_train_feats[:, 1:], data_train_feats[:, 0])
#bg模型及训练
bagging_clf = BaggingClassifier(clf, n_estimators=20, max_samples=0.8, max_features=1.0, bootstrap=True, bootstrap_features=False, n_jobs=-1)
bagging_clf.fit(data_train_feats[:, 1:], data_train_feats[:, 0])
至此我们的baseline撸好了,同样处理test的数据,送入模型中,查看结果
4.模型分析
4.1模型系数分析
我们刚刚训练好的baseline,但并不知道模型中每个feature对预测结果的影响有多大,所以我们先把得到的模型参数和feature对应起来,打印出来看看
pd.DataFrame({"columns":list(data_train.columns)[1:], "coef":list(clf.coef_.T)}
通过观看不同feature的权重,可以进一步去做出一定的分析与判断,来进一步的去做特征工程等
4.2交叉验证
【要做交叉验证(cross validation)!】
【要做交叉验证(cross validation)!】
【要做交叉验证(cross validation)!】
由于test集中的结果未知,不好让我们更好的去对我们模型产生的结果去分析,所以我们要做交叉验证!!!
交叉验证:我们通常将train集分出两部分,一部分用来训练模型,一部分用来预测结果
- 在小数据集上通常用cross_validate来查看打分情况
from sklearn.model_selection import cross_validate
print (cross_validate(clf, data_train_feats[:, 1:], data_train_feats[:, 0], cv=5))
- 我们把交叉验证里的bad case打印从出来,与我们所想的做对比,看看是不是哪个feature权重考虑错了,逐个分析看看
###利用交叉验证打印bad case
from sklearn.model_selection import train_test_split
#用分出的train去训练
split_train, split_cv = train_test_split(data_train, test_size=0.3, random_state=0)
split_train_filter = split_train.filter(regex='Survived|Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*')
clf_cv = linear_model.LogisticRegression(C=1.0, penalty='l2', tol=1e-6)
clf_cv.fit(split_train_filter.values[:,1:], split_train_filter.values[:,0])
#用分出的cv去测试
split_cv_filter = split_cv.filter(regex='Survived|Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*')
pre_cv = clf_cv.predict(split_cv_filter.values[:, 1:])
#打印出预测与真实不同的data
bad_case = data_train.loc[data_train['PassengerId'].isin(split_cv[pre_cv != split_cv_filter.values[:,0]]['PassengerId'].values)]
bad_case
通过bad case的实际情况和上节我们关于各feature权重对结果影响的猜想,可以进一步去分析挖掘。
4.3learning curves
利用learning curves曲线去分析我们模型的情况,针对不同的情况去做不同的调整:
1. 左上图片曲线收敛,但没达到预期效果——欠拟合,高偏差
解决方法:增加参数(如,增加feature的种类,model的复杂度);减少正则项
2. 右上图片曲线未收敛——过拟合,高方差
解决方法:增大训练集,减少参数(如,减少feature的数量,降低模型复杂度),增加正则项
3. 右下是理想情况,收敛且误差较小
# 绘制learning curve
from sklearn.model_selection import learning_curve
def plot_learning_curve(estimator, title, X, y, ylim=None, cv=None, n_jobs=1,
train_sizes=np.linspace(.05, 1., 20), verbose=0, plot=True):
"""
打印learning_curve
:param estimator: 模型
:param title: 图标的标题
:param X: 训练集的训练特征数据
:param y: 训练集的目标特征数据
:param ylim: 设置纵坐标点最高和最低点
:param cv: cv的k值
:param n_jobs: 并行任务数
:param train_sizes:
:param verbose:
:param plot:
"""
train_sizes, train_scores, test_scores = learning_curve(
estimator, X, y, cv=cv, n_jobs=n_jobs, train_sizes=train_sizes,verbose=verbose
)
train_scores_mean = np.mean(train_scores, axis=1)
train_scores_std = np.std(train_scores, axis=1)
test_scores_mean = np.mean(test_scores, axis=1)
test_scores_std = np.std(test_scores, axis=1)
if plot:
plt.figure()
plt.title(title)
if ylim is not None:
plt.ylim(*ylim)
plt.xlabel(u"训练样本数")
plt.ylabel(u"得分")
plt.gca().invert_yaxis() #将y轴的位置设置在左边
plt.grid() #设置网格
plt.fill_between(train_sizes, train_scores_mean - train_scores_std, train_scores_mean + train_scores_std,
alpha=0.1, color="b") #均值范围内加颜色
plt.fill_between(train_sizes, test_scores_mean - test_scores_std, test_scores_mean + test_scores_std,
alpha=0.1, color="r")
plt.plot(train_sizes, train_scores_mean, 'o-', color="b", label=u"训练集上得分")
plt.plot(train_sizes, test_scores_mean, 'o-', color="r", label=u"交叉验证集上得分")
plt.legend(loc="best")
plt.draw()
plt.show()
plt.gca().invert_yaxis()
#训练模型的train和test的差异
midpoint = ((train_scores_mean[-1] + train_scores_std[-1]) + (test_scores_mean[-1] - test_scores_std[-1])) / 2
diff = (train_scores_mean[-1] + train_scores_std[-1]) - (test_scores_mean[-1] - test_scores_std[-1])
return midpoint, diff
5.模型融合
机器学习、数据挖掘中的大杀器!
【模型融合(model ensemble)很重要!】
【模型融合(model ensemble)很重要!】
【模型融合(model ensemble)很重要!】
由于初入门数据挖掘,其他模型还不会,这里只用到了Bagging方法。
# fit到BaggingClassifier之中
from sklearn.ensemble import BaggingClassifier
clf = linear_model.LogisticRegression(C=1.0, penalty='l2', tol=1e-6)
bagging_clf = BaggingClassifier(clf, n_estimators=20, max_samples=0.9, max_features=1.0, bootstrap=True, bootstrap_features=False, n_jobs=-1)
bagging_clf.fit(data_train_filter_np[:, 1:], data_train_filter_np[:, 0])
predictions_bag = bagging_clf.predict(data_test_filter_np)
常规操作小知识
- jupyter notebook切换使用环境,需先在anaconda下激活
python -m ipykernel install --user --name 环境名称 --display-name "Python (环境名称)"
知识点
- 随机森林 参数讲解:https://blog.csdn.net/R18830287035/article/details/89257857
- bagging
- 回归与分类
- 过拟合与欠拟合:https://blog.csdn.net/aliceyangxi1987/article/details/73598857
参考:
- https://blog.csdn.net/han_xiaoyang/article/details/49797143
实现代码:
https://github.com/wangdepeng1/Titanic