zoukankan      html  css  js  c++  java
  • 数据降维之多维缩放MDS(Multiple Dimensional Scaling)

    网上看到关于数据降维的文章不少,介绍MDS的却极少,遂决定写一写。

    考虑一个这样的问题。我们有n个样本,每个样本维度为m。我们的目标是用不同的新的k维向量(k<<m)替代原来的n个m维向量,使得在新的低维空间中,所有样本相互之间的距离等于(或最大程度接近)原空间中的距离(默认欧氏距离)。

    举个栗子:原来有3个4维样本(1,0,0,3),(8,0,0,5),(2,0,0,4),显然我们可以用三个新的二维样本(1,3),(8,5),(2,4)来保持维度变小并相互之间距离不变。

    那么问题来了,如果不是这么明显的数据该如何来处理?降维后的距离一定会相等吗?

    MDS算法给出了在给定k值条件下的最优解决方案。

    首先我们计算所有原空间中样本相互之间的距离平方矩阵Dist[][],显然这是一非负对称实数矩阵。至此,其实我们要维护的就是Dist不变,与原样本已经无关了。

    接下来我们要根据Dist推算出目标降维后内积矩阵B,B[i][j]就是降维后第i,j个向量的内积。关于推导过程可以看相关书籍,这里给出一个优美的结论。

      B[i][j]=-0.5(Dist[i][j] - avg(Disti[i]) - avg(Distj[j]) + avg_Dist)

    有了B,只需要对B分解成B=U*UT的形式就达到我们的目标了。

    对B做特征分解(奇异分解也一样),B=V*diag*VT。

    我们可以取最大的k个特征值及其对应的特征向量构成diagk和Vk

    此时U=Vk*diagk0,5就是我们降维后的n个行向量组成的矩阵了。

    如果还有疑惑,下面的代码运行试试就明白了。

    召唤算法君:

    import numpy as np
    
    # run this to get a test matrix
    # A = np.random.randint(1,100,(5,20))
    # np.save('mat.npy', A)
    # exit()
    
    A = np.load('mat.npy')
    
    n,m = A.shape
    Dist = np.zeros((n,n))
    B = np.zeros((n,n))
    for i in range(n):
        for j in range(n):
            Dist[i][j] = sum((ix-jx)**2 for ix,jx in zip(A[i], A[j]))
    
    disti2 = np.array([0]*n)
    distj2 = np.array([0]*n)
    
    for x in range(n):
        disti2[x] = np.mean([Dist[x][j] for j in range(n)])
        distj2[x] = np.mean([Dist[i][x] for i in range(n)])
    
    distij2 = np.mean([Dist[i][j] for i in range(n) for j in range(n)])
    
    for i in range(n):
        for j in range(n):
            B[i][j] = -0.5*(Dist[i][j] - disti2[i] - distj2[j] + distij2)
    
    w,v = np.linalg.eig(B)
    
    v=v.transpose()
    
    U = [{'eVal':w[i], 'eVec':v[i]} for i in range(n)]
    
    U.sort(key = lambda obj:obj.get('eVal'), reverse = True)
    k=4
    w=np.array([0]*k)
    v=np.zeros((k,n))
    
    for i in range(k):
        w[i] = U[i].get('eVal')**0.5
        v[i] = U[i].get('eVec')
    
    ans = np.dot(v.transpose(), np.diag(w))
    
    ans_dist = np.zeros((n,n))
    for i in range(n):
        ans_str=""
        for j in range(n):
            ans_dist[i][j] = sum((ix-jx)**2 for ix,jx in zip(ans[i], ans[j]))
    
    print("Orign dis[][] is :")
    print Dist
    print("MDS dis[][] is :")
    print(ans_dist)
  • 相关阅读:
    vue——学习笔记
    工作笔记——上传图片
    前端调试利器——BrowserSync
    工作笔记——一些常用函数的封装
    【html、CSS、javascript-3】几个基本元素
    【html、CSS、javascript-2】CSS基础
    【html、CSS、javascript-1】html基础
    【python之路37】with上下文管理
    【python之路36】进程、线程、协程相关
    【python之路35】FTP文件断电续传作业
  • 原文地址:https://www.cnblogs.com/lochan/p/6627511.html
Copyright © 2011-2022 走看看