Skip to content

Commit 1168aa9

Browse files
Create FM_train.py
1 parent 7547d4e commit 1168aa9

1 file changed

Lines changed: 182 additions & 0 deletions

File tree

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

0 commit comments

Comments
 (0)