首页 > 代码库 > 尝试神经网络用于电影评分

尝试神经网络用于电影评分

在之前的随笔《非对称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=http://www.mamicode.com/[[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= http://www.mamicode.com/tt_data[:350]  # movie id=0
 78     fi.close()
 79 
 80     fi=open(train.dat,r)
 81     data=http://www.mamicode.com/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=http://www.mamicode.com/[]
 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=http://www.mamicode.com/[]
 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

 

尝试神经网络用于电影评分