SVD矩阵分解

import numpy as np

class SVD:
    def __init__(self,x):
        self.x = np.array(x)

    def get_r_rv(self,x):
        x = np.array(x)
        s_matrix = x.T.dot(x)
        r_list, r_v = np.linalg.eig(s_matrix)
        return r_list,r_v

    def get_matrix_rank(self):
        return np.linalg.matrix_rank(self.x)

    def get_V_M(self,x):
        r_list, r_v = self.get_r_rv(x)
        index_rank = np.argsort(-r_list)
        r_list = r_list[index_rank]
        r_list_ = r_list[r_list > 0]
        r_max = len(r_list_)
        V = r_v[:,index_rank]
        m = np.zeros((r_max,r_max))
        U = np.zeros((self.x.shape[0],r_max))
        for i in range(r_max):
            m[i][i] = np.sqrt(r_list_[i])
            U[:,i] = (np.dot(self.x, V[:, i]) / np.sqrt(r_list_[i])).T
        V = V[:, :r_max]
        return V,m,U

    def svd(self,way='norm',k=None):
        V,m,U= self.get_V_M(self.x)

        if way == 'norm':
            return V,m,U

        if way == 'truncated':
            r = self.get_matrix_rank()
            if k < r and k > 0:
                return V[:, :k], m[:k, :k], U[:, :k]
            else:
                return V, m, U

def main():
    x = np.array([[0,20,5,0,0],
                  [10,0,0,3,0],
                  [0,0,0,0,1],
                  [0,0,0,1,0]])
    svd = SVD(x)
    V, m, U = svd.svd()
    print(V)
    print(m)
    print(U)

    x = np.array([[0,20,5,0,0],
                  [10,0,0,3,0],
                  [0,0,0,0,1],
                  [0,0,0,1,0]])
    svd = SVD(x)
    V, m, U = svd.svd(way='truncated',k=2)
    print(V)
    print(m)
    print(U)

if __name__ == '__main__':
    main()

#------result--------------
[[ 0.          0.95709203  0.          0.28978415]
 [ 0.9701425   0.          0.          0.        ]
 [ 0.24253563  0.          0.          0.        ]
 [ 0.          0.28978415  0.         -0.95709203]
 [ 0.          0.          1.          0.        ]]
 
[[20.61552813  0.          0.          0.        ]
 [ 0.         10.44429362  0.          0.        ]
 [ 0.          0.          1.          0.        ]
 [ 0.          0.          0.          0.95746064]]
 
[[ 1.          0.          0.          0.        ]
 [ 0.          0.99961501  0.          0.02774569]
 [ 0.          0.          1.          0.        ]
 [ 0.          0.02774569  0.         -0.99961501]]
 
[[0.         0.95709203]
 [0.9701425  0.        ]
 [0.24253563 0.        ]
 [0.         0.28978415]
 [0.         0.        ]]
 
[[20.61552813  0.        ]
 [ 0.         10.44429362]]
 
[[1.         0.        ]
 [0.         0.99961501]
 [0.         0.        ]
 [0.         0.02774569]]

结果解释

所分解的矩阵是各个消费者对各个网页的URL点击次数
[[0,20,5,0,0],
[10,0,0,3,0],
[0,0,0,0,1],
[0,0,0,1,0]]

分解结果:
V:
[[ 0. 0.95709203 0. 0.28978415]
[ 0.9701425 0. 0. 0. ]
[ 0.24253563 0. 0. 0. ]
[ 0. 0.28978415 0. -0.95709203]
[ 0. 0. 1. 0. ]]
可以视作各个URL在不同特征维度上的特征值(4个维度)
如URL1的第二个特征较强,URL2的第一个特征较强

U:
[[ 1. 0. 0. 0. ]
[ 0. 0.99961501 0. 0.02774569]
[ 0. 0. 1. 0. ]
[ 0. 0.02774569 0. -0.99961501]]
可以看作用户对URL各个特征维度的偏好
如果用户1对特征1强的URL更加喜欢 因此查询V表发现URL2的特征1维度强
可以解释用户1对URL2的点击高达20次之多
同理用户2对特征2偏好较强,查询V表发现URL1的特征2较强,
可以解释用户2对URL1的点击高达10次之多

m:
[[20.61552813 0. 0. 0. ]
[ 0. 10.44429362 0. 0. ]
[ 0. 0. 1. 0. ]
[ 0. 0. 0. 0.95746064]]
可以视作各个URL特征的决定性作用或重要性,可以发现URL的前两个特征的重要性明显高于其他两个特征
因此我们对SVD分解结果进行截断得到结果:
V:
[[0. 0.95709203]
[0.9701425 0. ]
[0.24253563 0. ]
[0. 0.28978415]
[0. 0. ]]

U:
[[1. 0. ]
[0. 0.99961501]
[0. 0. ]
[0. 0.02774569]]
仅通过V,U两个矩阵我们就可以获得原用户点击URL矩阵的绝大多数信息,具有较强的解释性。这也是SVD矩阵分解的压缩的性质。

但至于URL的各个特征具体是指什么,这里无法体现,仅能表示用户偏好与URL属性之间的关系,可以用于推荐算法。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐