说明:本博客是学习《python机器学习算法》赵志勇著的学习笔记,其图片截取也来源本书。
在逻辑回归算法的模型中使用的是特征的线性组合,最终得到的是分隔超平面属于线性模型,其只能处理线性可分的二分类问题。现实生活中的分类问题是多种多样的,存在大量的非线性可分的分类问题。
对逻辑回归算法的优化有两种:
1、对特征进行处理,如核函数方法,将非线性可分的问题转换成近似线性可分的问题;
2、对逻辑回归算法进行扩展,因子分解(factorization Machine)是对基本逻辑回归算法的扩展。
在因子分解机(Factorization machine,FM)模型中,不仅包含了逻辑回归模型中的线性项,还包含了非线性的交叉项,利用矩阵分解的方法对模型中的交叉项的系数学习,得到每一项的系数,而无需人工参与。
具体的FM模型参考:系列博客http://blog.csdn.net/itplus/article/details/40534885
import numpy as np
from random import normalvariate # 正态分布
'''导入训练数据
input: data(string)训练数据
output: dataMat(list)特征
labelMat(list)标签
'''
def loadDataSet(fileName):
dataMat = []
labelMat = []
fr = open(fileName)
for line in fr.readlines():
lines = line.strip().split("\t")
lineArr = []
for i in range(len(lines) -1):
lineArr.append(float(lines[i]))
dataMat.append(lineArr)
labelMat.append(float(lines[-1])*2-1) # 将标签值{0,1}转换成{-1,1}
fr.close()
return dataMat, labelMat
def sigmoid(inx):
return 1.0/(1+np.exp(-inx))
'''初始化交叉项
input: n(int)特征的个数
k(int)FM模型的交叉向量维度
output: v(mat):交叉项的系数权重
'''
def initialize_v(n,k):
v = np.mat(np.zeros((n,k)))
for i in range(n):
for j in range(k):
# 利用正态分布生成每一个权重
v[i,j] = normalvariate(0,0.2) # 均值为0,标准差为0.2
return v
'''计算预测准确性
input: predict(list)预测值
classLabels(list)标签
output: error(float)计算损失函数的值
'''
def getCost(predict,classLabels):
m = len(predict)
error = 0.0
for i in range(m):
error -= np.log(sigmoid(predict[i]*classLabels[i]))
return error
'''得到预测值
input: dataMatrix(mat)特征
w(int)常数项权重
w0(int)一次项权重
v(float)交叉项权重
output: result(list)预测的结果
'''
def getPrediction(dataMatrix,w0,w,v):
m = np.shape(dataMatrix)[0]
result = []
for i in range(m):
inter_1 = dataMatrix[i]*v
inter_2 = np.multiply(dataMatrix[i],dataMatrix[i])*np.multiply(v,v) # multiply对应元素相乘
# 完成交叉项
interaction = np.sum(np.multiply(inter_1,inter_1)-inter_2)/2.0
p = w0+dataMatrix[i]*w+interaction # 计算预测的输出
pre = sigmoid(p[0,0])
result.append(pre)
return result
'''利用随机梯度下降法训练FM模型
input: dataMatrix(mat)特征
classLabels(mat)标签
k(int)v的维数
max_iter(int)最大迭代次数
alpha(float)学习率
output: w0(float),w(mat),v(mat):权重
'''
# def stocGradAscent(dataMatrix,classLabels,k,max_iter,alpha):
# m,n = np.shape(dataMatrix)
# # 1、初始化参数
# w = np.zeros((n,1)) # 其中n是特征的个数
# w0 = 0 # 偏置项
# v = initialize_v(n,k) # 初始化V
# # 2、训练
# for it in range(max_iter):
# for i in range(m): # 随机优化,对每一个样本而言的
# inter_1 = dataMatrix[i]*v
# inter_2 = np.multiply(dataMatrix[i],dataMatrix[i])*np.multiply(v,v) # 随机优化,对每一个样本而言的
# # 完成交叉项
# interaction = np.sum(np.multiply(inter_1,inter_1)-inter_2)/2.
# p = w0 + dataMatrix[i]*w+interaction # 计算预测的输出
# print("p: ",p)
# loss = sigmoid(classLabels[i]*p[0,0]) -1
# w0 = w0-alpha*loss*classLabels[i]
# for j in range(n):
# if dataMatrix[i,j] != 0:
# w[j,0] = w[j,0] -alpha*loss*classLabels[i]*dataMatrix[i]*dataMatrix[i,j]
# for l in range(k):
# v[j,l] = v[j,l] -alpha*loss*classLabels[i]*(dataMatrix[i,j]*inter_1[0,l]- \
# v[j,l]*dataMatrix[i,j]*dataMatrix[i,j])
# # 计算损失函数的值
# if it % 1000 == 0:
# print("\t------- iter: ", it, " , cost: ", getCost(getPrediction(np.mat(dataMatrix),w0,w,v),classLabels))
# # 3、返回最终的FM模型的参数
# return w0,w,v
def stocGradAscent(dataMatrix, classLabels, k, max_iter, alpha):
'''利用随机梯度下降法训练FM模型
input: dataMatrix(mat)特征
classLabels(mat)标签
k(int)v的维数
max_iter(int)最大迭代次数
alpha(float)学习率
output: w0(float),w(mat),v(mat):权重
'''
m, n = np.shape(dataMatrix)
# 1、初始化参数
w = np.zeros((n, 1)) # 其中n是特征的个数
w0 = 0 # 偏置项
v = initialize_v(n, k) # 初始化V
# 2、训练
for it in range(max_iter):
for x in range(m): # 随机优化,对每一个样本而言的
inter_1 = dataMatrix[x] * v
inter_2 = np.multiply(dataMatrix[x], dataMatrix[x]) * \
np.multiply(v, v) # multiply对应元素相乘
# 完成交叉项
interaction = np.sum(np.multiply(inter_1, inter_1) - inter_2) / 2.
p = w0 + dataMatrix[x] * w + interaction # 计算预测的输出
loss = sigmoid(classLabels[x] * p[0, 0]) - 1
w0 = w0 - alpha * loss * classLabels[x]
for i in range(n):
if dataMatrix[x, i] != 0:
w[i, 0] = w[i, 0] - alpha * loss * classLabels[x] * dataMatrix[x, i]
for j in range(k):
v[i, j] = v[i, j] - alpha * loss * classLabels[x] * \
(dataMatrix[x, i] * inter_1[0, j] -\
v[i, j] * dataMatrix[x, i] * dataMatrix[x, i])
# 计算损失函数的值
if it % 1000 == 0:
print("\t------- iter: ", it, " , cost: ", getCost(getPrediction(np.mat(dataTrain), w0, w, v), classLabels))
# 3、返回最终的FM模型的参数
return w0, w, v
'''计算预测准确性
input: predict(list)预测值
classLabels(list)标签
output: float(error) / allItem(float)错误率
'''
def getAccuracy(predict,classLabels):
m = len(predict)
allItem = 0
error = 0
for i in range(m):
allItem += 1
if float(predict[i]) < 0.5 and classLabels[i] == 1.0:
error += 1
elif float(predict[i]) >= 0.5 and classLabels[i] == -1.0:
error += 1
else:
continue
return float(error)/allItem
'''保存训练好的FM模型
input: file_name(string):保存的文件名
w0(float):偏置项
w(mat):一次项的权重
v(mat):交叉项的权重
'''
def save_model(file_name, w0, w, v):
f = open(file_name, "w")
# 1、保存w0
f.write(str(w0) + "\n")
# 2、保存一次项的权重
w_array = []
m = np.shape(w)[0]
for i in range(m):
w_array.append(str(w[i, 0]))
f.write("\t".join(w_array) + "\n")
# 3、保存交叉项的权重
m1 , n1 = np.shape(v)
for i in range(m1):
v_tmp = []
for j in range(n1):
v_tmp.append(str(v[i, j]))
f.write("\t".join(v_tmp) + "\n")
f.close()
if __name__ == "__main__":
# 1、导入训练数据
print("---------- 1.load data ---------")
dataTrain, labelTrain = loadDataSet("C:\\Python-Machine-Learning-Algorithm-master\\Chapter_3 Factorization Machine\\data.txt")
print("---------- 2.learning ---------")
# 2、利用随机梯度训练FM模型
w0, w, v = stocGradAscent(np.mat(dataTrain), labelTrain, 2, 20000, 0.01)
predict_result = getPrediction(np.mat(dataTrain), w0, w, v) # 得到训练的准确性
print("----------training accuracy: %f" % (1 - getAccuracy(predict_result, labelTrain)))
print("---------- 3.save result ---------")
# 3、保存训练好的FM模型
save_model("weights", w0, w, v)
---------- 1.load data ---------
---------- 2.learning ---------
------- iter: 0 , cost: 158.796173961
------- iter: 1000 , cost: 111.929488191
------- iter: 2000 , cost: 108.266775004
------- iter: 3000 , cost: 106.791821312
------- iter: 4000 , cost: 105.840630819
------- iter: 5000 , cost: 105.138452992
------- iter: 6000 , cost: 104.59986198
------- iter: 7000 , cost: 104.176479137
------- iter: 8000 , cost: 103.835249697
------- iter: 9000 , cost: 103.553678878
------- iter: 10000 , cost: 103.316834383
------- iter: 11000 , cost: 103.114787121
------- iter: 12000 , cost: 102.940690281
------- iter: 13000 , cost: 102.789547554
------- iter: 14000 , cost: 102.657511909
------- iter: 15000 , cost: 102.541509108
------- iter: 16000 , cost: 102.439031567
------- iter: 17000 , cost: 102.348013997
------- iter: 18000 , cost: 102.266747941
------- iter: 19000 , cost: 102.193816664
----------training accuracy: 1.000000
---------- 3.save result ---------