就拿决策树来说,比如如果一颗决策树效果不行,就用多颗决策树,这样就构成随机森林。
目的:让机器学习效果更好,单个不行,就用多个一起。
集成算法一、
bagging算法:并行训练多个M模型(如决策树)取平均或者其他方式汇总,如果就拿决策树来说,训练M颗决策树取预测数据,就会有M个结果,把这M个结果取平均来做最后的结果。
典型:“随机森林”,并行训练多个树,各个独立,各个树之间有些许差别,如预测一个人的成绩,把数据输入随机森林中,会有多个结果,最后去个平均来做最终预测的成绩。比如用来做分类,如做把数据把很多数据输入随机森林,发现大部分在a类,最终预测结果取a类。
森林的意思是有多颗决策树并行放在一起,随机的意思指数据采样随机(比如有100个数据去训练有三颗决策树随机森林,我们有放回的随机取60个取分别训练各个决策树),特征选择随机(比如每个数据都有十个特征,每颗数随机取6个特征)。
随机森林的优势:
1、它能够处理很高维度的数据(因为可以特征随机采样),并且不用做特征选择,因为特征很多的时候或许需要做降维处理,随机森林就有优势了。
2、训练完后,能够给出哪些特征比较重要。
随机森林之特征选择:
from sklearn.datasets import load_wine
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
import numpy as np
data=load_wine()
print(data.data.shape)#数据有178个,每个数据有13个特征
print(data.target.shape)#数据有178个
x_train,x_test,y_train,y_test=train_test_split(data.data,data.target,test_size=0.3,random_state=22)
forest=RandomForestClassifier(n_estimators=10,n_jobs=-1,random_state=9)#10颗数,-1表示适用于所有处理器,随机种子为9
forest.fit(x_train,y_train)
importances=forest.feature_importances_#随机森林特征的重要性
print('每个特征对应的重要性因子:\n',importances)
indices1 = np.argsort(importances)# a[::-1]让矩阵中数据逆序输出,np.argsort是按照importance中数据中数值从小到大排序
indices2 = np.argsort(importances)[::-1]# a[::-1]让矩阵中数据逆序输出,np.argsort是按照importance中数据中数值从大到小排序
print('特征重要程度从小到大排序的序号:\n',indices1)
print('特征重要程度从大到小排序的序号:\n',indices2)
most_import = indices2[:3]#取最总要的3个
print(x_train[:,most_import])
3、容易做成并行方法,速度比较快,比如可以用处理器的多个核并行训练。
4、可以进行可视化展示,便于分析。
集成算法二、
boosting算法:从弱学习器开始加强,通过加权来进行训练,串联的方法,多个树求和得来,每一次加入决策树都提升了原模型。
比如需要预测一个东西,这个东西为最好1000,比如我们分三棵树去预测,用主树去预测得出预测值为950,第二颗树拿1000-950去预测,结果为30,第三课树拿20去预测,结果为18,把这三个预测值加起来950+30+18=998得到最终总的预测值,这样的预测比只有一颗树预测值为950更好,因为第二颗树的在第一颗树的基础上再去预测,第三颗树在第二颗数的基础上再去预测,所以不能做并行处理,只能串行。
说白了就是先多第一步预测,看差多少,用第二个模型去预测残差,每次预测后再往里加一个模型。
典型代表:AdaBoost,Xgboost。
AdaBoost:会根据前一次的分类效果调整数据权重,比如有五棵1,2,3,4,5树模型,把样本平均分为五分,权重为0.2,0.2,0.2,0.2,0.2,分别取训练和预测,发现第1,2,4,5分类比较准确,第3分类不太准备,那我们调整样本权重,权重分别为0.1,0.1,0.6,0.1,01去训练,发现1,2,3树模型比较准确,4,5不太准确,再调整...最终训练出的每一颗决策树都是比较好。然后拿出最终的合体决策树取做最终预测。
其他说法:
实例:
以下例子先对特征进行人工分析,然后选择其中7个特征进行训练
import pandas as pd
from sklearn.model_selection import GridSearchCV
import numpy as np
def load_data_and_preprocessing():
train = pd.read_csv('./data/titanic_train.csv')
test = pd.read_csv('./data/test.csv')
print(train['Name'])
print(train.describe())
print(train.head())
print(train.info())
train_y = train['Survived']
selected_features = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked']#我们可以看到,舍弃了一些特征
train_x = train[selected_features]
train_x['Age'].fillna(train_x['Age'].mean(), inplace=True) # 以均值填充空缺值
print(train_x['Age'])
print(train_x['Embarked'].value_counts())
train_x['Embarked'].fillna('S', inplace=True)#空缺值用S填充
# print(train_x.info())
test_x = test[selected_features]
test_x['Age'].fillna(test_x['Age'].mean(), inplace=True)
test_x['Fare'].fillna(test_x['Fare'].mean(), inplace=True)
# print(test_x.info())
train_x.loc[train_x['Embarked'] == 'S', 'Embarked'] = 0
train_x.loc[train_x['Embarked'] == 'C', 'Embarked'] = 1
train_x.loc[train_x['Embarked'] == 'Q', 'Embarked'] = 2
train_x.loc[train_x['Sex'] == 'male', 'Sex'] = 0
train_x.loc[train_x['Sex'] == 'female', 'Sex'] = 1
print(train_x)
x_train = train_x.as_matrix()#转换为矩阵,也就是去除索引标签
print(x_train)
y_train = train_y.as_matrix()
test_x.loc[test_x['Embarked'] == 'S', 'Embarked'] = 0
test_x.loc[test_x['Embarked'] == 'C', 'Embarked'] = 1
test_x.loc[test_x['Embarked'] == 'Q', 'Embarked'] = 2
test_x.loc[test_x['Sex'] == 'male', 'Sex'] = 0
test_x.loc[test_x['Sex'] == 'female', 'Sex'] = 1
x_test = test_x
print(x_train)
return x_train, y_train, x_test
def logistic_regression():#用逻辑回归算法来预测
from sklearn.linear_model import LogisticRegression
x_train, y_train, x_test = load_data_and_preprocessing()
model = LogisticRegression()
paras = {'C': np.linspace(0.1, 10, 50)}#正则化强度逆
gs = GridSearchCV(model, paras, cv=5, verbose=3)
gs.fit(x_train, y_train)
print('best score:', gs.best_score_)
print('best parameters:', gs.best_params_)
def decision_tree():#用决策树来预测
from sklearn.tree import DecisionTreeClassifier
x_train, y_train, x_test = load_data_and_preprocessing()
model = DecisionTreeClassifier()
paras = {'criterion': ['gini', 'entropy'], 'max_depth': np.arange(5, 50, 5)}#参数是用基尼系数还是信息增益
gs = GridSearchCV(model, paras, cv=5, verbose=3)
gs.fit(x_train, y_train)
print('best score:', gs.best_score_)
print('best parameters:', gs.best_params_)
def random_forest():#用随机森林来预测
from sklearn.ensemble import RandomForestClassifier
x_train, y_train, x_test = load_data_and_preprocessing()
model = RandomForestClassifier()
paras = {'n_estimators': np.arange(10, 100, 10), 'criterion': ['gini', 'entropy'], 'max_depth': np.arange(5, 50, 5)}
gs = GridSearchCV(model, paras, cv=5, verbose=3)
gs.fit(x_train, y_train)
print('best score:', gs.best_score_)
print('best parameters:', gs.best_params_)
def gradient_boosting():
from sklearn.ensemble import GradientBoostingClassifier
x_train, y_train, x_test = load_data_and_preprocessing()
model = GradientBoostingClassifier()
paras = {'learning_rate': np.arange(0.1, 1, 0.1), 'n_estimators': range(80, 120, 10), 'max_depth': range(5, 10, 1)}#参数分别为学习速率,决策树的数目,树的最大深度
gs = GridSearchCV(model, paras, cv=5, verbose=3,n_jobs=2)#cv表交叉迭代数,verbose表显示训练过程,n_jobs表并行运算核数
gs.fit(x_train, y_train)
print('best score:', gs.best_score_)#平均交叉验证得分
print('best parameters:', gs.best_params_)
if __name__ == '__main__':
#logistic_regression() # 0.7979
# decision_tree()#0.813
# random_forest() # 0.836 {'criterion': 'entropy', 'max_depth': 10, 'n_estimators': 60}
gradient_boosting()#0.830 {'learning_rate': 0.1, 'max_depth': 5, 'n_estimators': 90}
数据:泰坦尼克号数据 提取码: wvmf
以下例子先对特征进行评估,然后选择合适的特征进行训练:
import pandas as pd
import numpy as np
from sklearn.model_selection import GridSearchCV
def feature_selection():
from sklearn.feature_selection import SelectKBest, f_classif
import matplotlib.pyplot as plt
train = pd.read_csv('./data/titanic_train.csv')
selected_features = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked']#特征的数量为7
train_x = train[selected_features]
train_y = train['Survived']
train_x['Age'].fillna(train_x['Age'].mean(), inplace=True) # 以均值填充
train_x['Embarked'].fillna('S', inplace=True)
train_x.loc[train_x['Embarked'] == 'S', 'Embarked'] = 0
train_x.loc[train_x['Embarked'] == 'C', 'Embarked'] = 1
train_x.loc[train_x['Embarked'] == 'Q', 'Embarked'] = 2
train_x.loc[train_x['Sex'] == 'male', 'Sex'] = 0
train_x.loc[train_x['Sex'] == 'female', 'Sex'] = 1
selector = SelectKBest(f_classif, k=5)#k为要选择特征的数量,默认第一个参数为f_classif
selector.fit(train_x, train_y)#拟合训练数据
scores = selector.scores_#给各个特征打分的分数
plt.bar(range(len(selected_features)), scores)
plt.xticks(range(len(selected_features)), selected_features,rotation='horizontal')
plt.show()
x_train = train_x[['Pclass', 'Sex', 'Fare']]#人工选择特征,从图像上可以看到这三个特征比较重要,所以我们选择这三个特征
y_train = train_y.as_matrix()
train_x = x_train.as_matrix()
return train_x, y_train
def logistic_regression():
from sklearn.linear_model import LogisticRegression
x_train, y_train= feature_selection()
model = LogisticRegression()
paras = {'C': np.linspace(0.1, 10, 50)}
gs = GridSearchCV(model, paras, cv=5, verbose=3)
gs.fit(x_train, y_train)
print('best score:', gs.best_score_)
print('best parameters:', gs.best_params_)
def decision_tree():
from sklearn.tree import DecisionTreeClassifier
x_train, y_train = feature_selection()
model = DecisionTreeClassifier()
paras = {'criterion': ['gini', 'entropy'], 'max_depth': np.arange(5, 50, 5)}
gs = GridSearchCV(model, paras, cv=5, verbose=3)
gs.fit(x_train, y_train)
print('best score:', gs.best_score_)
print('best parameters:', gs.best_params_)
def random_forest():
from sklearn.ensemble import RandomForestClassifier
x_train, y_train = feature_selection()
model = RandomForestClassifier()
paras = {'n_estimators': np.arange(10, 100, 10), 'criterion': ['gini', 'entropy'], 'max_depth': np.arange(5, 50, 5)}
gs = GridSearchCV(model, paras, cv=5, verbose=3)
gs.fit(x_train, y_train)
print('best score:', gs.best_score_)
print('best parameters:', gs.best_params_)
if __name__ == '__main__':
# feature_selection()
# logistic_regression()#0.783
# decision_tree()#0.814
random_forest()# 0.814
Xgboost:可以用来做回归,回归的意思是预测出来的不是一个类别,而是一个数。比如,下面用两个决策树来预测一个人是否喜欢打游戏,正数表示喜欢打游戏,负数表示不喜欢打游戏,对于同一个人如小男孩,两个相加后为2.9,说明小男孩打游戏。老爷爷两个预测结果相加为-0.1,说明老爷爷不打游戏。这种方法也是一种集成的方法。
算法过程:
1、第一个式子中w是权重,也就是叶子节点上的数值。
2、y帽子表示预测值。
3、目标函数表示真实值与预测值之间的误差。
4、最优函数解的方法表示所有样本的误差之和再求一个平均,也就成了误差期望,然后使用某种方法使得函数最小,这里的方法是加入决策树,使得目标函数下降。
5、集成算法的表示中K表示决策树,因为是集成算法,所有要把所有的决策树考虑进来。
6、算法核心思想,并不是一下子就加好多颗决策树进去的,因为不知道一下子这么多决策树效果是不是一定会很好,他的决策树的一次一次加的,比如先用一颗决策树来预测,发现效果不太好,然后我们再加一个决策树进去共同预测,若发现不太好可以再加,然后再调试。
举个例子:
开始没有模型,预测值为0,然后加入一颗决策树,构建模型后发现效果不太好,然后再加入决策树构建新的模型....加入模型的目的是使得目标函数下降,这个过程也就是优化的过程。
我们知道,如果叶子节点过多会导致过拟合,权重过多也会导致过拟合。所以我们加入惩罚项(惩罚叶子个数和权重的个数):
所以优化目标变成:
其中第一个圈表示决策树和的模型和惩罚项,圈里面包含之前的决策树和的模型和当前加入新的决策树的模型和惩罚项,常数表示计算中可能产生一些常数。
我们要做的是不断加入新的模型,使得目标函数越来越小。
7、xgboost融合了串联方法。
集成算法三、
堆叠模型:聚合多个分类或回归模型算法(可以分阶段来做)
堆叠的意思很暴力,拿一堆模型直接上,比如堆叠多种分类器,如SVM,KNN等。
分阶段:第一阶段选择四个算法,第二个阶段用第一个阶段的结果在预测。如下:第一个阶段1234个数据在各个模型做成预测值,第二个阶段把第一个阶段的结果再做一个逻辑回归,得到最终结果。
堆叠模型实例:
from suijitishenshu import load_data_and_preprocessing#这个是从另一个python文件中调用里面的函数
from sklearn.model_selection import KFold#K折交叉验证
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier#随机森林分类和boosting分类
def stacking():
s = 0
x_train, y_train, x_test = load_data_and_preprocessing()
kf = KFold(n_splits=5)#5折交叉验证
rfc = RandomForestClassifier(criterion='entropy', max_depth=10, n_estimators=60)
gbc = GradientBoostingClassifier(learning_rate=0.1, max_depth=5, n_estimators=90)
for train_index, test_index in kf.split(x_train):#因为是五折交叉验证(把数据平均分为5分,每次拿其中四份训练,另外一份做测试,循环五次,每一份都轮了一次用来测试),所以会循环五次,这里赋值过去的是索引,
# print(train_index)
#print(test_index)
train_x, test_x = x_train[train_index], x_train[test_index]
train_y, test_y = y_train[train_index], y_train[test_index]
rfc.fit(train_x, train_y)
rfc_pre = rfc.predict_proba(test_x)[:,1]#预测概率
print(rfc.predict_proba(test_x))#这个的结果有两列,分别为y = 0和y = 1的概率
print(rfc.predict_proba(test_x).shape)
print(rfc_pre)
print(rfc_pre.shape)
gbc.fit(train_x, train_y)
gbc_pre = gbc.predict_proba(test_x)[:,1]#预测概率
y_pre = ((rfc_pre+gbc_pre)/2 >= 0.5)*1#取值为1或者0
acc = sum((test_y == y_pre)*1)/len(y_pre)
s += acc
print(acc)
print('Accuracy: ',s/5)# 0.823对五次求出的精确度取个平均值
if __name__ == '__main__':
stacking()