fm 简单实现

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

在了解fm 的原理以后,如果不懂的话,请移步,我从github下载了一个简单的fm_python实现。代码链接为github

我将这个源码的解读在于有两个部分,一个是处理数据部分。其实大家仔细看就两个部分,一个是对数据的处理,将我们要的数据(标准化)。将标准负类改成 -1,正类为1. 我将所有的难点解析的都在代码里面一步一步在代码里面用中文解释了。

#coding:UTF-8

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

trainData = 'diabetes_train.txt'
testData = 'diabetes_test.txt'
featureNum = 8
max_list = []
min_list = []

def normalize(x_list,max_list,min_list):
    index = 0
    scalar_list = []
    for x in x_list:
        x_max = max_list[index]
        x_min = min_list[index]
        if x_max == x_min:
            x = 1.0    
        else:
            x = round((x-x_min)/(x_max-x_min),4)
        scalar_list.append(x)
        index += 1
    return scalar_list

def loadTrainDataSet(data):
    global max_list
    global min_list
    dataMat = []
    labelMat = []
    
    fr = open(data)#打开文件
    
    for line in fr.readlines():
#使用,将每一行隔开生成列表,其实currLine是列表:
        currLine = line.strip().split(',')
        #lineArr = [1.0]
        lineArr = []
        #选择所需要的特征个数
        for i in xrange(featureNum):
#列表里面添加每一列的特征值
            lineArr.append(float(currLine[i]))
#变成dataframe()形式
        dataMat.append(lineArr)
        #将分类改成为-1和1
        labelMat.append(float(currLine[-1]) * 2 - 1)
    
    data_array = np.array(dataMat)
#获取每一列的最大值和最小值
    max_list = np.max(data_array,axis=0)
    min_list = np.min(data_array,axis=0)
#将获得的特征归一化
    scalar_dataMat = []
    for row in dataMat:
#将最大值和最小值代入进行标准化(归一化)操作
        scalar_row = normalize(row,max_list,min_list)
        scalar_dataMat.append(scalar_row)
    return scalar_dataMat, labelMat
#这里主要重复操作,进行归一化操作
def loadTestDataSet(data):
    global max_list
    global min_list
    dataMat = []
    labelMat = []
    
    fr = open(data)#打开文件
    
    for line in fr.readlines():
        currLine = line.strip().split(',')
        lineArr = []
        
        for i in xrange(featureNum):
            lineArr.append(float(currLine[i]))

        dataMat.append(lineArr)
        
        labelMat.append(float(currLine[-1]) * 2 - 1)
    
    data_array = np.array(dataMat)

    scalar_dataMat = []
    for row in dataMat:
        scalar_row = normalize(row,max_list,min_list)
        scalar_dataMat.append(scalar_row)
    return scalar_dataMat, labelMat

第二部分是设计fm 和 计算损失函数。并将反向迭代参数解答。并最终在main 函数实现,相关数据文件我放pan分享一下哈

链接:https://pan.baidu.com/s/1LRlSJTrrald4WHj933Ea7w 密码:4pj0。

相信有一些同学不懂multiply的用法。其实就是相同的结构进行相乘而已,那你一定好奇不一样的结构怎么办呢,python是会自动补全的哦。再不懂的话问我或者百度哦。

 

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

def stocGradAscent(dataMatrix, classLabels, k, iter):
    #dataMatrix用的是mat, classLabels是列表
#找到dataMatrix的shape长宽
    m, n = shape(dataMatrix)
#学习率
    alpha = 0.01
    #初始化参数
    #w = random.randn(n, 1)#其中n是特征的个数
#w初始化为n行,1列
    w = zeros((n, 1))
    w_0 = 0.
#偏值生成0,0.2的正态分布行数n ,列长K
    v = normalvariate(0, 0.2) * ones((n, k))
    
    for it in xrange(iter):
        print it
#每一行的数据乘以一个n,k
        for x in xrange(m):#随机优化,对每一个yang本而言的
            inter_1 = dataMatrix[x] * v #每一行的dataMatrix为(1,n) v为(n,k)。二者*为(1,k)
#
            inter_2 = multiply(dataMatrix[x], dataMatrix[x]) * multiply(v, v)#multiply对应元素相乘
            #inter_2的平方。1行,n列 * v的平方的n行,k列。所以最终是1行k列。
            #完成交叉项
            interaction = sum(multiply(inter_1, inter_1) - inter_2) / 2.#这里mutiply inter_1则为(1的##平方,n的平方):其实还是(1,k)这样的结构:1行,k列.最终通过sum操作将
            
            p = w_0 + dataMatrix[x] * w + interaction#计算预测的输出
            #print "y: ",p 
            loss = sigmoid(classLabels[x] * p[0, 0]) - 1
            #print "loss: ",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 = loadTrainDataSet(trainData)
    dataTest, labelTest = loadTestDataSet(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))  

简单的fm实现,就可以了,不懂的随时联系我哦。接下来我将解析ffm源码

转载于:https://my.oschina.net/xtzggbmkk/blog/1937384

你可能感兴趣的:(fm 简单实现)