如何从相似矩阵绘制 MDS?

How to plot a MDS from a similarity matrix?

我正在使用值介于 0 和 1 之间的相似度矩阵(1 表示元素相等),并且我正在尝试使用 python 和 scikit-learn 绘制 MDS。

我找到了多个示例,但我不确定将什么作为 mds.fit() 的输入。

现在,我的数据看起来像这样 (file.csv) :

  ;  A  ;  B  ;  C  ;  D  ; E
A ; 1   ; 0.1 ; 0.2 ; 0.5 ; 0.2
B ; 0.1 ; 1   ; 0.3 ; 1   ; 0
C ; 0.2 ; 0.3 ; 1   ; 0.8 ; 0.6
D ; 0.5 ; 1   ; 0.8 ; 1   ; 0.2
E ; 0.2 ; 0   ; 0.6 ; 0.2 ; 1

我目前正在使用此代码:

import pandas
from sklearn import manifold
import matplotlib.pyplot as plt

data = pandas.read_table("file.csv", ";", header=0, index_col=0)

mds = manifold.MDS(n_components=2, random_state=1, dissimilarity="precomputed")
mds.fit(data)
points = mds.embedding_

# Prepare axes
ax = plt.axes([0,0,2,2])
ax.set_aspect(aspect='equal')

# Plot points
plt.scatter(points[:,0], points[:,1], color='silver', s=150)
# Add labels
for i in range(data.shape[0]):
    ax.annotate(data.index[i], (points[i,0], points[i,1]), color='blue')

#plt.show() # Open display and show at screen
plt.savefig('out.png', format='png', bbox_inches='tight') # PNG
#plt.savefig('out.jpg', format='jpg', bbox_inches='tight') # JPG

我不确定 sklearn 在做什么。我读了很多例子,其中人们使用中间为 0(而不是 1)的“相异矩阵”。

  1. 要不要转型?或不 ?如果是,应该进行哪种转换? (我读到 there 一个简单的减法就足够了......但其他方法存在......我有点迷路:( )

  2. sklearn 和 MDS 会自动理解输入吗? (作为中间为 0 或 1 的相似或相异矩阵?) 还是使用距离矩阵? (这样的话,如何从相似度矩阵中得到呢?)

  3. 在这个 link 中,他们说相似度介于 1 和 -1 之间...我使用的相似度介于 0 和 1 之间...我想我应该转换我的数据?应该使用哪种转换?

我与 XLSTAT(一个 excel 扩展)进行了比较,以便尝试很多场景并比较如何做。

首先:我的输入矩阵是一个“相似性”矩阵,因为我可以将其解释为:“A 和 A 100% 相等”。 由于 MDS 将相异矩阵作为输入,我必须应用转换。

  1. 在文献Ricco Rakotomalala's french course on data science (p 208-209)中,简单的方法是将最大值减去每个单元格(进行“1 - 单元格”操作)。 所以你可以很容易地制作一个 python 程序,或者(因为我跟踪每个矩阵)一个 AWK pre-processing 程序:

similarity-to-dissimilarity-simple.awk

# We keep the tags around the CSV matrix
# X ; Word1 ; Word2 ; ...
# Header
NR == 1 {
    # First column is just "X" (or space)
    printf("%s", "X");

    # For each column, print the word
    for (i = 2; i <= NF; i++)
    {
    col = $i;
    printf("%s%s", OFS, col);
    }

    # End of line
    printf("\n");
}

# Other lines are processed
# WordN ; 1 ; 0.5 ; 0.2 ; ...
NR != 1 {
    # First column is the word/tag
    col = ;
    printf("%s", col);

    # For each column, process the number
    for (i = 2; i <= NF; i++)
    {
    # dissimilarity = (1 - similarity)
    NUM = $i;
    VAL = 1 - NUM;
    printf("%s%s", OFS, VAL);
    }

    printf("\n");
}

可以使用命令调用:

awk -F ";" -v OFS=";" -f similarity-to-dissimilarity-simple.awk input.csv > output-simple.csv
  1. 一种更复杂的计算方式(我找不到参考资料,抱歉 :( ) 是基于对每个单元格的另一个转换 :

(sii + si'i' - 2 * sii')^1/2

如果对角线不包含相同的值(我看到there一个co-occurrence矩阵......它应该适用于他的cas),这种方法似乎可以完美适应。 在我的例子中,由于对角线总是充满 1,我将其减少为:

(2 - 2 * sii')^1/2

因此进行此转换的 AWK 程序(由于我的数据,我实施了简化的程序)是:

similarity-to-dissimilarity-complex.awk

# Header
# X ; Word1 ; Word2 ; ...
NR == 1 {
    # First column is just "X" (or space)
    printf("%s", "X");

    # For each column, print the word
    for (i = 2; i <= NF; i++)
    {
    col = $i;
    printf("%s%s", OFS, col);
    }

    # End of line
    printf("\n");
}

# Other lines are processed
# WordN ; 1 ; 0.5 ; 0.2 ; ...
NR != 1 {
    # First column is the word
    col = ;
    printf("%s", col);

    # For each column, process the number
    for (i = 2; i <= NF; i++)
    {
    # dissimilarity = (2 - 2 * similarity)^-1/2
    NUM = $i;
    VAL = sqrt(2 - 2 * NUM);
    printf("%s%s", OFS, VAL);
    }

    printf("\n");
}

你可以用这个命令调用它:

awk -F ";" -v OFS=";" -f similarity-to-dissimilarity-complex.awk input.csv > output-complex.csv

当我使用 Kruskal 的压力来检查哪个版本更好时......在我的情况下,简单相似性与相异性(1 - 细胞)是最好的(我将压力保持在 0,34 和 0,32 之间... 这不好... 其中复数显示的值大于 0,34,这更糟)。