在之前的随笔《非对称SVD电影推荐系统》中应用SVD,得到还不错的结果。
此次尝试将BP神经网络应用于预测用户评分,由于同类用户不同电影评分差异巨大,神经网络输出神经元不易设置。
仅取movie id=0 的用户作为测试数据(350 条记录),这样只需要5个输出神经元。考虑到movie id 共有三千多个,方法无操作性。
得到的最佳rmse=0.588,预测(左)和实际试评分(右)如下(评分已减1)。单独这个电影,用户实际评分比较接近,结果没有参考价值。
[(3, 3.0), (3, 4.0), (3, 3.0), (3, 4.0), (4, 3.0), (3, 4.0), (3, 3.0), (4, 4.0), (3, 4.0), (3, 4.0), (4, 3.0), (3, 3.0), (3, 4.0), (3, 3.0), (4, 4.0), (3, 3.0), (3, 3.0), (3, 2.0), (3, 3.0), (4, 4.0), (4, 4.0), (4, 4.0), (4, 4.0), (3, 4.0), (3, 3.0), (4, 4.0), (3, 2.0), (3, 4.0), (3, 4.0), (3, 3.0), (3, 4.0), (3, 3.0), (3, 4.0), (3, 0.0), (3, 2.0), (3, 4.0), (3, 3.0), (3, 4.0), (3, 3.0), (3, 2.0), (3, 4.0), (3, 3.0), (4, 4.0), (4, 4.0), (4, 3.0), (4, 4.0), (3, 4.0), (3, 3.0), (4, 3.0), (3, 2.0), (3, 4.0), (4, 3.0), (3, 4.0), (3, 3.0), (4, 3.0), (3, 3.0), (3, 3.0), (4, 3.0), (4, 4.0), (3, 4.0), (4, 3.0), (4, 4.0), (4, 2.0), (3, 3.0), (4, 3.0), (3, 4.0), (3, 3.0), (3, 2.0), (4, 4.0), (4, 4.0), (3, 2.0), (4, 4.0), (3, 2.0), (3, 4.0), (3, 4.0), (2, 4.0), (3, 4.0), (3, 4.0), (3, 1.0), (4, 4.0), (3, 4.0), (3, 3.0), (3, 4.0), (3, 3.0), (4, 3.0), (3, 0.0), (3, 2.0), (3, 2.0), (3, 4.0), (3, 3.0), (4, 3.0), (3, 4.0), (3, 4.0), (4, 4.0), (3, 3.0), (3, 2.0), (3, 4.0), (3, 3.0), (3, 3.0), (3, 3.0), (4, 2.0), (3, 3.0), (3, 2.0), (3, 3.0), (3, 4.0), (3, 3.0), (4, 4.0), (3, 4.0), (3, 1.0), (4, 4.0), (3, 4.0), (3, 4.0), (4, 4.0), (3, 3.0), (3, 1.0), (4, 3.0), (4, 4.0), (3, 1.0), (3, 4.0), (3, 4.0), (3, 4.0), (4, 4.0), (4, 4.0), (3, 2.0), (3, 3.0), (3, 2.0), (3, 3.0), (3, 2.0), (3, 3.0), (3, 3.0), (3, 3.0), (3, 3.0), (4, 3.0), (3, 4.0), (4, 4.0), (3, 3.0), (3, 2.0), (4, 3.0), (4, 3.0), (4, 3.0), (3, 4.0), (3, 4.0), (3, 2.0), (3, 3.0), (4, 4.0), (4, 2.0), (3, 4.0), (4, 3.0), (3, 4.0), (4, 3.0), (4, 3.0), (3, 2.0), (3, 1.0), (3, 3.0), (3, 3.0), (4, 3.0), (3, 4.0), (3, 1.0), (4, 4.0), (3, 3.0), (4, 2.0), (3, 2.0), (3, 3.0), (3, 4.0), (4, 2.0), (4, 4.0), (3, 3.0), (3, 3.0), (3, 1.0), (3, 4.0), (4, 3.0), (3, 3.0), (4, 3.0), (3, 2.0), (3, 4.0), (4, 4.0), (3, 3.0), (3, 3.0), (3, 2.0), (4, 4.0), (4, 4.0), (3, 1.0), (3, 2.0), (3, 2.0), (3, 4.0), (4, 3.0), (4, 3.0), (3, 3.0), (4, 4.0), (3, 3.0), (3, 3.0), (4, 4.0), (3, 4.0), (4, 4.0), (4, 3.0), (3, 4.0), (3, 3.0), (3, 3.0), (3, 4.0), (3, 4.0), (4, 4.0), (4, 4.0), (3, 3.0), (3, 2.0), (3, 4.0), (3, 3.0), (3, 2.0), (3, 1.0), (4, 4.0), (4, 4.0), (3, 3.0), (3, 3.0), (3, 4.0), (3, 4.0), (4, 4.0), (3, 3.0), (4, 3.0), (3, 4.0), (4, 4.0), (3, 3.0), (3, 4.0), (3, 4.0), (3, 3.0), (3, 4.0), (4, 3.0), (3, 3.0), (4, 3.0), (4, 3.0), (3, 3.0), (4, 2.0), (2, 3.0), (3, 4.0), (4, 4.0), (3, 4.0), (3, 1.0), (4, 4.0), (3, 3.0), (4, 3.0), (3, 4.0), (3, 2.0), (3, 2.0), (4, 3.0), (3, 4.0), (3, 4.0), (3, 4.0), (4, 3.0), (4, 2.0), (3, 3.0), (3, 4.0), (3, 4.0), (3, 2.0), (3, 2.0), (3, 3.0), (3, 3.0), (3, 4.0), (3, 3.0), (3, 4.0), (4, 4.0), (4, 2.0), (4, 3.0), (3, 3.0), (3, 3.0), (3, 3.0), (4, 4.0), (3, 3.0), (3, 4.0), (4, 3.0), (4, 3.0), (3, 2.0), (3, 4.0), (4, 3.0), (4, 0.0), (3, 3.0), (4, 3.0), (3, 4.0), (3, 2.0), (3, 4.0), (4, 3.0), (4, 2.0), (3, 4.0), (3, 2.0), (3, 4.0), (3, 3.0), (3, 4.0), (3, 2.0), (3, 3.0), (3, 2.0), (3, 0.0), (3, 3.0), (4, 3.0), (3, 3.0), (3, 4.0), (3, 4.0), (3, 3.0), (3, 4.0), (3, 3.0), (3, 3.0), (4, 4.0), (3, 4.0), (3, 3.0), (3, 2.0), (4, 3.0), (3, 4.0), (3, 4.0), (3, 1.0), (4, 4.0), (3, 4.0), (3, 4.0), (3, 1.0), (3, 2.0), (4, 4.0), (3, 2.0), (3, 4.0), (3, 3.0), (3, 4.0), (4, 3.0), (4, 4.0), (3, 3.0), (3, 2.0), (4, 2.0), (3, 2.0), (3, 0.0), (3, 4.0), (3, 3.0), (3, 3.0), (4, 4.0), (3, 4.0), (3, 3.0), (3, 4.0), (3, 4.0), (3, 0.0), (3, 2.0), (3, 3.0), (4, 3.0), (4, 4.0), (3, 4.0), (4, 3.0), (3, 3.0), (3, 2.0), (3, 4.0), (4, 4.0), (3, 3.0), (3, 0.0), (4, 4.0), (3, 3.0), (3, 2.0), (3, 2.0), (4, 4.0), (4, 4.0), (3, 4.0)]
1 # coding:utf8 2 import cPickle 3 import numpy as np 4 5 6 class Network(object): 7 def __init__(self, sizes): 8 self.num_layers = len(sizes) 9 self.sizes = sizes 10 self.biases = [np.random.randn(y, 1) for y in sizes[1:]] # L(n-1)->L(n) 11 self.weights = [np.random.randn(y, x) 12 for x, y in zip(sizes[:-1], sizes[1:])] 13 14 def feedforward(self, a): 15 for b_, w_ in zip(self.biases, self.weights): 16 a = self.sigmoid(np.dot(w_, a)+b_) 17 return a 18 19 def SGD(self, training_data, test_data,epochs, mini_batch_size, eta=1.0): 20 n_test = len(test_data) 21 n = len(training_data) 22 for j in xrange(epochs): 23 np.random.shuffle(training_data) # shuffle 24 for k in xrange(0, n, mini_batch_size): 25 mini_batch = training_data[k:k+mini_batch_size] 26 self.update_mini_batch(mini_batch, eta) 27 rmse=np.sqrt(self.evaluate(test_data)/1000.0) 28 print "Epoch {0}: {1} / {2}".format( 29 j, rmse, n_test) 30 31 def update_mini_batch(self, mini_batch, eta): 32 for x, y in mini_batch: 33 delta_b, delta_w = self.backprop(x, y) 34 self.weights -= eta/len(mini_batch)*delta_w 35 self.biases -= eta/len(mini_batch)*delta_b 36 37 def backprop(self, x, y): 38 b=np.zeros_like(self.biases) 39 w=np.zeros_like(self.weights) 40 a_ = x 41 a = [x] 42 for b_, w_ in zip(self.biases, self.weights): 43 a_ = self.sigmoid(np.dot(w_, a_)+b_) 44 a.append(a_) 45 for l in xrange(1, self.num_layers): 46 if l==1: 47 delta= self.sigmoid_prime(a[-1])*(a[-1]-y) # O(k)=a[-1], t(k)=y 48 else: 49 sp = self.sigmoid_prime(a[-l]) # O(j)=a[-l] 50 delta = np.dot(self.weights[-l+1].T, delta) * sp 51 b[-l] = delta 52 w[-l] = np.dot(delta, a[-l-1].T) 53 return (b, w) 54 55 def evaluate(self, test_data): 56 test_results = [(np.argmax(self.feedforward(x)), y) 57 for (x, y) in test_data] 58 print test_results 59 return sum((x- y)**2 for (x, y) in test_results) 60 61 def sigmoid(self,z): 62 return 1.0/(1.0+np.exp(-z)) 63 64 def sigmoid_prime(self,z): 65 return z*(1-z) 66 67 if __name__ == ‘__main__‘: 68 69 def get_label(i): 70 c=np.zeros((5,1)) 71 c[i]=1 72 return c 73 74 fi=open(‘test.dat‘,‘r‘) 75 tt_data=[[int(line.split(‘::‘)[0])-1,int(line.split(‘::‘)[1])-1,float(line.split(‘::‘)[2])] for line in fi] 76 tt_data.sort(key=lambda x:x[1]) 77 t_data= tt_data[:350] # movie id=0 78 fi.close() 79 80 fi=open(‘train.dat‘,‘r‘) 81 data=np.zeros((6040,3952)) 82 for line in fi: 83 content=line.split(‘::‘) 84 user=int(content[0])-1 85 item=int(content[1])-1 86 rating=float(content[2]) 87 data[user][item]=rating 88 fi.close() 89 90 train_data=[] 91 for a in data: 92 if a[0]>0: 93 label=int(a[0]-1) 94 a[0]=0 95 train_data.append([np.reshape(a,(3952,1)),get_label(label)]) 96 test_data=[] 97 for t in t_data: 98 label=t[2]-1 99 test_data.append([np.reshape(data[t[0]],(3952,1)),label]) 100 101 net = Network([3952, 30, 5]) 102 net.SGD(train_data,test_data,10,10,3.0) # 0.588