本学习笔记为阿里云天池龙珠计划金融风控训练营的学习内容,学习链接为:https://tianchi.aliyun.com/specials/activity/promotion/aicampfr
一、学习知识点概要
1.逻辑回归模型
2.树模型
3.集成模型
4.模型调参
二、学习内容
1、逻辑回归模型
- 逻辑回归一种线性回归模型,它假设数据服从伯努利分布,通过极大似然函数的方法,运用梯度下降法来求解参数,进而大道二分类的目的。
- 逻辑回归,不是回归,而是分类器,二分类,多分类。
- 逻辑回归分类示例(线性判定边界):
数据在空间的分布,代码如下:
from numpy import loadtxt, where
from pylab import scatter, show, legend, xlabel, ylabel
#load the dataset
data = loadtxt('/home/HanXiaoyang/data/data1.txt', delimiter=',')
X = data[:, 0:2]
y = data[:, 2]
pos = where(y == 1)
neg = where(y == 0)
scatter(X[pos, 0], X[pos, 1], marker='o', c='b')
scatter(X[neg, 0], X[neg, 1], marker='x', c='r')
xlabel('Feature1/Exam 1 score')
ylabel('Feature2/Exam 2 score')
legend(['Fail', 'Pass'])
show()
计算sigmoid函数、代价函数、和梯度下降的程序:
def sigmoid(X):
'''Compute sigmoid function '''
den =1.0+ e **(-1.0* X)
gz =1.0/ den
return gz
def compute_cost(theta,X,y):
'''computes cost given predicted and actual values'''
m = X.shape[0]#number of training examples
theta = reshape(theta,(len(theta),1))
J =(1./m)*(-transpose(y).dot(log(sigmoid(X.dot(theta))))- transpose(1-y).dot(log(1-sigmoid(X.dot(theta)))))
grad = transpose((1./m)*transpose(sigmoid(X.dot(theta))- y).dot(X))
#optimize.fmin expects a single value, so cannot return grad
return J[0][0]#,grad
def compute_grad(theta, X, y):
'''compute gradient'''
theta.shape =(1,3)
grad = zeros(3)
h = sigmoid(X.dot(theta.T))
delta = h - y
l = grad.size
for i in range(l):
sumdelta = delta.T.dot(X[:, i])
grad[i]=(1.0/ m)* sumdelta *-1
theta.shape =(3,)
return grad
使用我们的判定边界对training data做一个预测,然后比对一下准确率:
def predict(theta, X):
'''Predict label using learned logistic regression parameters'''
m, n = X.shape
p = zeros(shape=(m,1))
h = sigmoid(X.dot(theta.T))
for it in range(0, h.shape[0]):
if h[it]>0.5:
p[it,0]=1
else:
p[it,0]=0
return p
#Compute accuracy on our training set
p = predict(array(theta), it)
print'Train Accuracy: %f'%((y[where(p == y)].size / float(y.size))*100.0)
计算出来的结果是89.2%
- 逻辑回归分类示例(非线性判定边界):
要对给定的两个feature做一个多项式特征的映射
def map_feature(x1, x2):
'''
Maps the two input features to polonomial features.
Returns a new feature array with more features of
X1, X2, X1 ** 2, X2 ** 2, X1*X2, X1*X2 ** 2, etc...
'''
x1.shape =(x1.size,1)
x2.shape =(x2.size,1)
degree =6
mapped_fea = ones(shape=(x1[:,0].size,1))
m, n = mapped_fea.shape
for i in range(1, degree +1):
for j in range(i +1):
r =(x1 **(i - j))*(x2 ** j)
mapped_fea = append(mapped_fea, r, axis=1)
return mapped_fea
mapped_fea = map_feature(X[:,0], X[:,1])
梯度下降和在数据点上画出判定边界后得到
2、树模型
- 创建决策树所需要用到的函数:
1、createDataSet():创建数据集
2、calShannoEnt(dataSet):计算香农熵
3、splitDataSet(dataSet,axis, value):根据特征划分数据集
4、chooseBestFeaturesToSplit(dataSet):选择最佳特征
5、majorityCnt(classList):确定类别
6、createTree(dataSet, labels, featLabels):创建决策树 - 创建数据集
def createDataSet():
dataSet = [
[0,0,0,0,'no'],
[0,0,0,1,'no'],
[0,1,0,1,'yes'],
[0,1,1,0,'yes'],
[0,0,0,0,'no'],
[1,0,0,0,'no'],
[1,0,0,1,'no'],
[1,1,1,1,'yes'],
[1,0,1,1,'yes'],
[1,0,1,2,'yes'],
[2,0,1,2,'yes'],
[2,0,1,1,'yes'],
[2,1,0,1,'yes'],
[2,1,0,2,'yes'],
[2,0,0,0,'no']
]
labels = ['年龄', '有工作', '有自己的房子', '信贷情况']
return dataSet,labels
- 计算香农熵
"""
函数说明:
计算数据集的香农熵
param :dataSet-数据集
return: shannonEnt-香农熵
"""
def calShannoEnt(dataSet):
numEntires = len(dataSet) #数据集行数
labelCounts = {} #该字典用于保存每个标签出现的次数
for featVec in dataSet:
currentLabel = featVec[-1] #for循环,来处理每一个数据的标签
if currentLabel not in labelCounts.keys(): #对字典进行初始化
labelCounts[currentLabel] = 0 #令两类初始值分别为0
labelCounts[currentLabel] += 1 #统计数据
shannonEnt = 0.0
for key in labelCounts: #根据公式,利用循环求香农熵
prob = float(labelCounts[key])/numEntires
shannonEnt -= prob*log(prob,2)
return shannonEnt
- 划分数据
def splitDataSet(dataSet,axis, value):
"""
函数说明:
对数据集根据某个特征进行划分
:param dataSet: 被划分的数据集
:param axis: 划分根据的特征
:param value: 需要返回的特征的值
:return: 无
"""
retDataSet = [] #建立空列表,存储返回的数据集
for featVec in dataSet: #遍历数据,一个对象一个对象的进行操作
if featVec[axis] == value: #找到axis特征,等于value值得数据
reducedFeatVec = featVec[:axis] #选出去除axis特征,只保留其他特征的数据
reducedFeatVec.extend(featVec[axis+1:]) #保留后面的
retDataSet.append(reducedFeatVec) #对数据进行连接,按照列表形式
return retDataSet #返回划分后被取出的数据集,即满足条件的数据
- 选择最佳分类属性
def chooseBestFeaturesToSplit(dataSet):
"""
函数说明:
选择最佳的分类属性
:param :dataSet-数据集
:return: bestFeature-最佳划分属性
"""
numFeatures = len(dataSet[0]) - 1 #特征数量,去除最后一个标签值
baseEntropy = calShannoEnt(dataSet) #计算原始数据的香农熵
bestInfoGain = 0.0 #信息增益初始化
bestFeature = -1 #最有特征索引
for i in range(numFeatures): #遍历所有特征
#该特征的所有值,组成的列表
featList = [example[i] for example in dataSet]
uniqueVals = set(featList) #创建集合,元素不可重复
newEntropy = 0.0 #经验条件熵
for value in uniqueVals: #计算信息增益
#根据第i特征,value值对数据进行划分
subDataSet = splitDataSet(dataSet, i, value)
#求划分后数据的经验条件熵
prob = len(subDataSet)/float(len(dataSet))
newEntropy += prob * calShannoEnt(subDataSet)
infoGain = baseEntropy - newEntropy #求划分前后的信息增益
print("第%d个特征的增益是%.3f" %(i,infoGain))
if(infoGain > bestInfoGain):
bestInfoGain = infoGain
bestFeature = i
return bestFeature
- 选择类别
def majorityCnt(classList):
"""
函数说明:
当划分结束,遍历所有特征,但是依然不能彻底划分数据时
将这多个类别中,出现次数最多的作为该类别
:param classList-类别列表
:return: sortedClassCount[0][0]-类别
"""
classCount = {}
for vote in classList:
if vote not in classCount.keys():
classCount[vote] = 0
classCount[vote] += 1 #统计出现各个类别出现的次数
#对类别列表进行排序
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse = True)
return sortedClassCount[0][0]
- 创建决策树
def createTree(dataSet, labels, featLabels):
"""
函数说明:
创建决策树
:param dataSet-训练集
:param labels-训练集数据标签
:param featLabels:
:return:
"""
classList = [example[-1] for example in dataSet] #取分类标签(是否放贷:yes or no)
#注意条件,对列表的某一类计数,若为列表长度,则类别完全相同
if classList.count(classList[0]) == len(classList): #如果类别完全相同则停止继续划分
return classList[0]
if len(dataSet[0]) == 1: #遍历完所有特征时返回出现次数最多的类标签
return majorityCnt(classList)
bestFeat = chooseBestFeaturesToSplit(dataSet) #最优特征
bestFeatLabel = labels[bestFeat] #最优特征的标签
featLabels.append(bestFeatLabel) #
myTree = {bestFeatLabel:{}} #根据最优特征的标签建立决策树
del(labels[bestFeat]) #删除已经使用的特征标签
#训练集中,最优特征所对应的所有数据的值
featValues = [example[bestFeat] for example in dataSet]
uniqueVals = set(featValues) #去掉重复特征
for value in uniqueVals: #遍历特征创建决策树
#通过此句实现字典的叠加
myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),labels,featLabels)
return myTree
3、集成模型
-
随机森林模型
-
Bagging即套袋法,其算法过程如下:
(A)从原始样本集中抽取训练集。每轮从原始样本集中使用Bootstraping的方法抽取n个训练样本(有放回的抽样)。共进行k轮抽取,得到k个训练集。(k个训练集之间是相互独立的)
(B)每次使用一个训练集得到一个模型,k个训练集共得到k个模型。
(C)对分类问题:将上步得到的k个模型采用投票的方式得到分类结果;对回归问题,计算上述模型的均值作为最后的结果。
-
XGBoost模型
我们把一个家庭的成员分成不同的叶子,并把他们分配到相应的叶子节点上。 CART 与 decision trees(决策树)有些许的不同,就是叶子只包含决策值。在 CART 中,每个叶子都有一个 real score(真实的分数).
使用多棵树预测
树的集成归根到底是Boosting模型,Boosting的实质是个加性模型。
-
更多介绍:https://blog.csdn.net/wuzhongqiang/article/details/104854890
-
LightGBM模型
-
使用了带有深度限制的按叶子生长 (leaf-wise)算法
-
下图右边叶子节点的含义是X=A或者X=C放到左孩子,其余放到右孩子。
-
更多介绍:https://blog.csdn.net/wuzhongqiang/article/details/105350579
-
CatBoost模型
只要告诉算法,哪些特征属于类别特征,它会自动帮你处理。代码如下所示:
categorical_features_indices = np.where(X_train.dtypes != np.float)[0]
model = CatBoostClassifier(iterations=100, depth=5,cat_features=categorical_features_indices,learning_rate=0.5, loss_function='Logloss',
logging_level='Verbose')
然后将数据进行训练,通过plot = True,还可以将损失函数可视化。
model.fit(X_train,y_train,eval_set=(X_validation, y_validation),plot=True)
训练结束后,通过model.feature_importances_属性,我们可以拿到这些特征的重要程度数据,特征的重要性程度可以帮助我们分析出一些有用的信息。
import matplotlib.pyplot as plt
fea_ = model.feature_importances_
fea_name = model.feature_names_
plt.figure(figsize=(10, 10))
plt.barh(fea_name,fea_,height =0.5)
4、模型调参
-
贪心调参
-
日常调参过程中常用的参数和调参顺序:
①:max_depth、num_leaves
②:min_data_in_leaf、min_child_weight
③:bagging_fraction、 feature_fraction、bagging_freq
④:reg_lambda、reg_alpha
⑤:min_split_gain -
网格搜索
-
sklearn 提供GridSearchCV用于进行网格搜索,只需要把模型的参数输进去,就能给出最优化的结果和参数。相比起贪心调参,网格搜索的结果会更优,但是网格搜索只适合于小数据集,一旦数据的量级上去了,很难得出结果。
-
贝叶斯调参
-
主要思想是:给定优化的目标函数(广义的函数,只需指定输入和输出即可,无需知道内部结构以及数学性质),通过不断地添加样本点来更新目标函数的后验分布(高斯过程,直到后验分布基本贴合于真实分布)。简单的说,就是考虑了上一次参数的信息,从而更好的调整当前的参数。
"""定义优化函数"""
def rf_cv_lgb(num_leaves, max_depth, bagging_fraction, feature_fraction, bagging_freq, min_data_in_leaf,
min_child_weight, min_split_gain, reg_lambda, reg_alpha):
# 建立模型
model_lgb = lgb.LGBMClassifier(boosting_type='gbdt', bjective='binary', metric='auc',
learning_rate=0.1, n_estimators=5000,
num_leaves=int(num_leaves), max_depth=int(max_depth),
bagging_fraction=round(bagging_fraction, 2), feature_fraction=round(feature_fraction, 2),
bagging_freq=int(bagging_freq), min_data_in_leaf=int(min_data_in_leaf),
min_child_weight=min_child_weight, min_split_gain=min_split_gain,
reg_lambda=reg_lambda, reg_alpha=reg_alpha,
n_jobs= 8
)
val = cross_val_score(model_lgb, X_train_split, y_train_split, cv=5, scoring='roc_auc').mean()
return val
"""定义优化参数"""
bayes_lgb = BayesianOptimization(
rf_cv_lgb,
{
'num_leaves':(10, 200),
'max_depth':(3, 20),
'bagging_fraction':(0.5, 1.0),
'feature_fraction':(0.5, 1.0),
'bagging_freq':(0, 100),
'min_data_in_leaf':(10,100),
'min_child_weight':(0, 10),
'min_split_gain':(0.0, 1.0),
'reg_alpha':(0.0, 10),
'reg_lambda':(0.0, 10),
}
)
"""开始优化"""
"""显示优化结果"""
bayes_lgb.max
{'target': 0.7282530196283977,
'params': {'bagging_fraction': 0.9815471914843896,
'bagging_freq': 96.14757648686668,
'feature_fraction': 0.6961281791730929,
'max_depth': 19.45450235568963,
'min_child_weight': 1.6266132496156782,
'min_data_in_leaf': 37.697878831472295,
'min_split_gain': 0.4184947943942168,
'num_leaves': 14.221122487200399,
'reg_alpha': 7.056502173310882,
'reg_lambda': 9.924023764203156}}
三、学习问题与解答
寻求解决方法
四、学习思考与总结
这一部分内容有点多,主要是对各种模型的了解,树模型跟之前数据结构学过的内容有点像,稍稍能够理解一点。逻辑回归模型跟之前学过的线性回归有关联,像是被掰弯的线性回归。集成模型的种类有点多,根据它们的思想分为几种类型,但是还是很难去理解它,总觉得和树模型有点像,跟之前学过的二叉树也有那么一点相似,总之,是非常的乱了……