Factorization Machine算法

说明:本博客是学习《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 ---------

你可能感兴趣的:(机器学习实战)