简单易学的机器学习算法——因子分解机(Factorization Machine)

简单易学的机器学习算法——因子分解机(Factorization Machine)

一、因子分解机FM的模型          因子分解机(Factorization Machine, FM)是由Steffen Rendle提出的一种基于矩阵分解的机器学习算法。

1、因子分解机FM的优势

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

对于因子分解机FM来说,最大的特点是对于稀疏的数据具有很好的学习能力。现实中稀疏的数据很多,例如作者所举的推荐系统的例子便是一个很直观的具有稀疏特点的例子。

2、因子分解机FM的模型          对于度为2的因子分解机FM的模型为:

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

其中,参数

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

表示的是两个大小为

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

的向量

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

和向量

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

的点积:

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

其中,

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

表示的是系数矩阵

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

的第

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

维向量,且

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

称为超参数。在因子分解机FM模型中,前面两部分是传统的线性模型,最后一部分将两个互异特征分量之间的相互关系考虑进来。        因子分解机FM也可以推广到高阶的形式,即将更多互异特征分量之间的相互关系考虑进来。

二、因子分解机FM算法       因子分解机FM算法可以处理如下三类问题:

  1. 回归问题(Regression)
  2. 二分类问题(Binary Classification)
  3. 排序(Ranking) 在这里主要介绍回归问题和二分类问题。

1、回归问题(Regression)       在回归问题中,直接使用

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

作为最终的预测结果。在回归问题中使用最小均方误差(the least square error)作为优化的标准,即

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

其中,

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

表示样本的个数。

2、二分类问题(Binary Classification)       与Logistic回归类似,通过阶跃函数,如Sigmoid函数,将

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

映射成不同的类别。在二分类问题中使用logit loss作为优化的标准,即

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

其中,

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

表示的是阶跃函数Sigmoid。具体形式为:

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

三、因子分解机FM算法的求解过程

1、交叉项系数       在基本线性回归模型的基础上引入交叉项,如下:

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

若是这种直接在交叉项

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

的前面加上交叉项系数

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

的方式在稀疏数据的情况下存在一个很大的缺陷,即在对于观察样本中未出现交互的特征分量,不能对相应的参数进行估计。        对每一个特征分量

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

引入辅助向量

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

,利用

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

对交叉项的系数

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

进行估计,即

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

这就对应了一种矩阵的分解。对

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

值的限定,对FM的表达能力有一定的影响。

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

2、模型的求解

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

这里要求出

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

,主要采用了如公式

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

求出交叉项。具体过程如下:

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

3、基于随机梯度的方式求解

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

对于回归问题:

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

对于二分类问题:

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

四、实验(求解二分类问题)

1、实验的代码:

#coding:UTF-8

from __future__ import division
from math import exp
from numpy import *
from random import normalvariate#正态分布
from datetime import datetime

trainData = 'E://data//diabetes_train.txt'
testData = 'E://data//diabetes_test.txt'
featureNum = 8

def loadDataSet(data):
    dataMat = []
    labelMat = []
    
    fr = open(data)#打开文件
    
    for line in fr.readlines():
        currLine = line.strip().split()
        #lineArr = [1.0]
        lineArr = []
        
        for i in xrange(featureNum):
            lineArr.append(float(currLine[i + 1]))
        dataMat.append(lineArr)
        
        labelMat.append(float(currLine[0]) * 2 - 1)
    return dataMat, labelMat

def sigmoid(inx):
    return 1.0 / (1 + exp(-inx))

def stocGradAscent(dataMatrix, classLabels, k, iter):
    #dataMatrix用的是mat, classLabels是列表
    m, n = shape(dataMatrix)
    alpha = 0.01
    #初始化参数
    w = zeros((n, 1))#其中n是特征的个数
    w_0 = 0.
    v = normalvariate(0, 0.2) * ones((n, k))
    
    for it in xrange(iter):
        print it
        for x in xrange(m):#随机优化,对每一个样本而言的
            inter_1 = dataMatrix[x] * v
            inter_2 = multiply(dataMatrix[x], dataMatrix[x]) * multiply(v, v)#multiply对应元素相乘
            #完成交叉项
            interaction = sum(multiply(inter_1, inter_1) - inter_2) / 2.
            
            p = w_0 + dataMatrix[x] * w + interaction#计算预测的输出
        
            loss = sigmoid(classLabels[x] * p[0, 0]) - 1
            print loss
        
            w_0 = w_0 - alpha * loss * classLabels[x]
            
            for i in xrange(n):
                if dataMatrix[x, i] != 0:
                    w[i, 0] = w[i, 0] - alpha * loss * classLabels[x] * dataMatrix[x, i]
                    for j in xrange(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])
        
    
    return w_0, w, v

def getAccuracy(dataMatrix, classLabels, w_0, w, v):
    m, n = shape(dataMatrix)
    allItem = 0
    error = 0
    result = []
    for x in xrange(m):
        allItem += 1
        inter_1 = dataMatrix[x] * v
        inter_2 = multiply(dataMatrix[x], dataMatrix[x]) * multiply(v, v)#multiply对应元素相乘
        #完成交叉项
        interaction = sum(multiply(inter_1, inter_1) - inter_2) / 2.
        p = w_0 + dataMatrix[x] * w + interaction#计算预测的输出
        
        pre = sigmoid(p[0, 0])
        
        result.append(pre)
        
        if pre < 0.5 and classLabels[x] == 1.0:
            error += 1
        elif pre >= 0.5 and classLabels[x] == -1.0:
            error += 1
        else:
            continue
        
    
    print result
    
    return float(error) / allItem
        
   
if __name__ == '__main__':
    dataTrain, labelTrain = loadDataSet(trainData)
    dataTest, labelTest = loadDataSet(testData)
    date_startTrain = datetime.now()
    print "开始训练"
    w_0, w, v = stocGradAscent(mat(dataTrain), labelTrain, 20, 200)
    print "训练准确性为:%f" % (1 - getAccuracy(mat(dataTrain), labelTrain, w_0, w, v))
    date_endTrain = datetime.now()
    print "训练时间为:%s" % (date_endTrain - date_startTrain)
    print "开始测试"
    print "测试准确性为:%f" % (1 - getAccuracy(mat(dataTest), labelTest, w_0, w, v))  

2、实验结果:

www.zeeklog.com  - 简单易学的机器学习算法——因子分解机(Factorization Machine)

五、几点疑问       在传统的非稀疏数据集上,有时效果并不是很好。在实验中,我有一点处理,即在求解Sigmoid函数的过程中,在有的数据集上使用了带阈值的求法:

def sigmoid(inx):
    #return 1.0 / (1 + exp(-inx))
    return 1. / (1. + exp(-max(min(inx, 15.), -15.))) 


欢迎更多的朋友一起讨论这个算法。

参考文章   1、Rendle, Factorization Machines.    2、Factorization Machines with libFM

Read more

深入理解 Proxy 和 Object.defineProperty

在JavaScript中,对象是一种核心的数据结构,而对对象的操作也是开发中经常遇到的任务。在这个过程中,我们经常会使用到两个重要的特性:Proxy和Object.defineProperty。这两者都允许我们在对象上进行拦截和自定义操作,但它们在实现方式、应用场景和灵活性等方面存在一些显著的区别。本文将深入比较Proxy和Object.defineProperty,包括它们的基本概念、使用示例以及适用场景,以帮助读者更好地理解和运用这两个特性。 1. Object.defineProperty 1.1 基本概念 Object.defineProperty 是 ECMAScript 5 引入的一个方法,用于直接在对象上定义新属性或修改已有属性。它的基本语法如下: javascript 代码解读复制代码Object.defineProperty(obj, prop, descriptor); 其中,obj是目标对象,prop是要定义或修改的属性名,descriptor是一个描述符对象,用于定义属性的特性。 1.2 使用示例 javascript 代码解读复制代码//

By Ne0inhk

Proxy 和 Object.defineProperty 的区别

Proxy 和 Object.defineProperty 是 JavaScript 中两个不同的特性,它们的作用也不完全相同。 Object.defineProperty 允许你在一个对象上定义一个新属性或者修改一个已有属性。通过这个方法你可以精确地定义属性的特征,比如它是否可写、可枚举、可配置等。该方法的使用场景通常是需要在一个对象上创建一个属性,然后控制这个属性的行为。 Proxy 也可以用来代理一个对象,但是相比于 Object.defineProperty,它提供了更加强大的功能。使用 Proxy 可以截获并重定义对象的基本操作,比如访问属性、赋值、函数调用等等。在这些操作被执行之前,可以通过拦截器函数对这些操作进行拦截和修改。因此,通过 Proxy,你可以完全重写一个对象的默认行为。该方法的使用场景通常是需要对一个对象的行为进行定制化,或者需要在对象上添加额外的功能。 对比 以下是 Proxy 和 Object.defineProperty 的一些区别对比: 方面ProxyObject.defineProperty语法使用 new Proxy(target,

By Ne0inhk