3.2、Factorization Machine实践

1、在上一篇博客中我们构建度为二的因子分解机模型,这篇博客对这个模型进行实践

下图为准备的数据集:

完整代码为:

  1 # -*- coding: UTF-8 -*-
  2 # date:2018/6/6
  3 # User:WangHong
  4 import numpy as np
  5 from random import normalvariate  # 正态分布
  6 
  7 def loadDataSet(data):
  8     '''导入训练数据
  9     input:  data(string)训练数据
 10     output: dataMat(list)特征
 11             labelMat(list)标签
 12     '''
 13     dataMat = []
 14     labelMat = []   
 15     fr = open(data)  # 打开文件  
 16     for line in fr.readlines():
 17         lines = line.strip().split("\t")
 18         lineArr = []
 19         
 20         for i in range(len(lines) - 1):
 21             lineArr.append(float(lines[i]))
 22         dataMat.append(lineArr)
 23         
 24         labelMat.append(float(lines[-1]) * 2 - 1)  # 转换成{-1,1}
 25     fr.close()
 26     return dataMat, labelMat
 27 
 28 def sigmoid(inx):
 29     return 1.0 / (1 + np.exp(-inx))
 30 
 31 def initialize_v(n, k):
 32     '''初始化交叉项
 33     input:  n(int)特征的个数
 34             k(int)FM模型的超参数
 35     output: v(mat):交叉项的系数权重
 36     '''
 37     v = np.mat(np.zeros((n, k)))
 38     
 39     for i in range(n):
 40         for j in range(k):
 41             # 利用正态分布生成每一个权重
 42             v[i, j] = normalvariate(0, 0.2)
 43     return v
 44 
 45 def stocGradAscent(dataMatrix, classLabels, k, max_iter, alpha):
 46     '''利用随机梯度下降法训练FM模型
 47     input:  dataMatrix(mat)特征
 48             classLabels(mat)标签
 49             k(int)v的维数
 50             max_iter(int)最大迭代次数
 51             alpha(float)学习率
 52     output: w0(float),w(mat),v(mat):权重
 53     '''
 54     m, n = np.shape(dataMatrix)
 55     # 1、初始化参数
 56     w = np.zeros((n, 1))  # 其中n是特征的个数
 57     w0 = 0  # 偏置项
 58     v = initialize_v(n, k)  # 初始化V
 59     
 60     # 2、训练
 61     for it in range(max_iter):
 62         for x in range(m):  # 随机优化,对每一个样本而言的
 63             inter_1 = dataMatrix[x] * v
 64             inter_2 = np.multiply(dataMatrix[x], dataMatrix[x]) * \
 65              np.multiply(v, v)  # multiply对应元素相乘
 66             # 完成交叉项
 67             interaction = np.sum(np.multiply(inter_1, inter_1) - inter_2) / 2.
 68             p = w0 + dataMatrix[x] * w + interaction  # 计算预测的输出
 69             loss = sigmoid(classLabels[x] * p[0, 0]) - 1
 70         
 71             w0 = w0 - alpha * loss * classLabels[x]
 72             for i in range(n):
 73                 if dataMatrix[x, i] != 0:
 74                     w[i, 0] = w[i, 0] - alpha * loss * classLabels[x] * dataMatrix[x, i]
 75                     
 76                     for j in range(k):
 77                         v[i, j] = v[i, j] - alpha * loss * classLabels[x] * \
 78                         (dataMatrix[x, i] * inter_1[0, j] -\
 79                           v[i, j] * dataMatrix[x, i] * dataMatrix[x, i])
 80         
 81         # 计算损失函数的值
 82         if it % 1000 == 0:
 83             print ("\t------- iter: ", it, " , cost: ", \
 84             getCost(getPrediction(np.mat(dataMatrix), w0, w, v), classLabels))
 85     
 86     # 3、返回最终的FM模型的参数
 87     return w0, w, v
 88 
 89 def getCost(predict, classLabels):
 90     '''计算预测准确性
 91     input:  predict(list)预测值
 92             classLabels(list)标签
 93     output: error(float)计算损失函数的值
 94     '''
 95     m = len(predict)
 96     error = 0.0
 97     for i in range(m):
 98         error -=  np.log(sigmoid(predict[i] * classLabels[i] ))  
 99     return error
100 
101 def getPrediction(dataMatrix, w0, w, v):
102     '''得到预测值
103     input:  dataMatrix(mat)特征
104             w(int)常数项权重
105             w0(int)一次项权重
106             v(float)交叉项权重
107     output: result(list)预测的结果
108     '''
109     m = np.shape(dataMatrix)[0]   
110     result = []
111     for x in range(m):
112         
113         inter_1 = dataMatrix[x] * v
114         inter_2 = np.multiply(dataMatrix[x], dataMatrix[x]) * \
115          np.multiply(v, v)  # multiply对应元素相乘
116         # 完成交叉项
117         interaction = np.sum(np.multiply(inter_1, inter_1) - inter_2) / 2.
118         p = w0 + dataMatrix[x] * w + interaction  # 计算预测的输出        
119         pre = sigmoid(p[0, 0])        
120         result.append(pre)        
121     return result
122 
123 def getAccuracy(predict, classLabels):
124     '''计算预测准确性
125     input:  predict(list)预测值
126             classLabels(list)标签
127     output: float(error) / allItem(float)错误率
128     '''
129     m = len(predict)
130     allItem = 0
131     error = 0
132     for i in range(m):
133         allItem += 1
134         if float(predict[i]) < 0.5 and classLabels[i] == 1.0:
135             error += 1
136         elif float(predict[i]) >= 0.5 and classLabels[i] == -1.0:
137             error += 1
138         else:
139             continue
140     return float(error) / allItem      
141 
142 def save_model(file_name, w0, w, v):
143     '''保存训练好的FM模型
144     input:  file_name(string):保存的文件名
145             w0(float):偏置项
146             w(mat):一次项的权重
147             v(mat):交叉项的权重
148     '''
149     f = open(file_name, "w")
150     # 1、保存w0
151     f.write(str(w0) + "\n")
152     # 2、保存一次项的权重
153     w_array = []
154     m = np.shape(w)[0]
155     for i in range(m):
156         w_array.append(str(w[i, 0]))
157     f.write("\t".join(w_array) + "\n")
158     # 3、保存交叉项的权重
159     m1 , n1 = np.shape(v)
160     for i in range(m1):
161         v_tmp = []
162         for j in range(n1):
163             v_tmp.append(str(v[i, j]))
164         f.write("\t".join(v_tmp) + "\n")
165     f.close()
166      
167    
168 if __name__ == "__main__":
169     # 1、导入训练数据
170     print ("---------- 1.load data ---------")
171     dataTrain, labelTrain = loadDataSet("data_1.txt")
172     print( "---------- 2.learning ---------")
173     # 2、利用随机梯度训练FM模型
174     w0, w, v = stocGradAscent(np.mat(dataTrain), labelTrain, 3, 10000, 0.01)
175     predict_result = getPrediction(np.mat(dataTrain), w0, w, v)  # 得到训练的准确性
176     print( "----------training accuracy: %f" % (1 - getAccuracy(predict_result, labelTrain)))
177     print ("---------- 3.save result ---------")
178     # 3、保存训练好的FM模型
179     save_model("weights", w0, w, v)
View Code

 最终训练过程为:

训练的过程比较慢,我用来将近有一分半

得到的权值文件为:

最终分隔得到的超平面为:

2、对新的数据进行预测:

预测的全部代码为:

 1 # -*- coding: UTF-8 -*-
 2 # date:2018/6/6
 3 # User:WangHong
 4 
 5 import numpy as np
 6 
 7 from FM_train import getPrediction
 8 
 9 def loadDataSet(data):
10     '''导入测试数据集
11     input:  data(string)测试数据
12     output: dataMat(list)特征
13     '''
14     dataMat = []
15     fr = open(data)  # 打开文件  
16     for line in fr.readlines():
17         lines = line.strip().split("\t")
18         lineArr = []
19         
20         for i in range(len(lines)):
21             lineArr.append(float(lines[i]))
22         dataMat.append(lineArr)
23         
24     fr.close()
25     return dataMat
26 
27 def loadModel(model_file):
28     '''导入FM模型
29     input:  model_file(string)FM模型
30     output: w0, np.mat(w).T, np.mat(v)FM模型的参数
31     '''
32     f = open(model_file)
33     line_index = 0
34     w0 = 0.0
35     w = []
36     v = []
37     for line in f.readlines():
38         lines = line.strip().split("\t")
39         if line_index == 0:  # w0
40             w0 = float(lines[0].strip())
41         elif line_index == 1:  # w
42             for x in lines:
43                 w.append(float(x.strip()))
44         else:
45             v_tmp = []
46             for x in lines:
47                 v_tmp.append(float(x.strip()))
48             v.append(v_tmp)
49         line_index += 1     
50     f.close()
51     return w0, np.mat(w).T, np.mat(v)
52 
53 def save_result(file_name, result):
54     '''保存最终的预测结果
55     input:  file_name(string)需要保存的文件名
56             result(mat):对测试数据的预测结果
57     '''
58     f = open(file_name, "w")
59     f.write("\n".join(str(x) for x in result))
60     f.close()
61 
62 if __name__ == "__main__":
63     # 1、导入测试数据
64     dataTest = loadDataSet("test_data.txt")
65     # 2、导入FM模型
66     w0, w , v = loadModel("weights")
67     # 3、预测
68     result = getPrediction(dataTest, w0, w, v)
69     # 4、保存最终的预测结果
70     save_result("predict_result", result)
71     
72     
View Code

最终测试结果得到一个predict_result.txt文件

猜你喜欢

转载自www.cnblogs.com/wanshuai/p/9202139.html
3.2
今日推荐