使用余弦相似函数执行矩阵乘法
Perform matrix multiplication with cosine similarity function
我有两个列表:
list_1 = [['flavor', 'flavors', 'fruity_flavor', 'taste'],
['scent', 'scents', 'aroma', 'smell', 'odor'],
['mental_illness', 'mental_disorders','bipolar_disorder']
['romance', 'romances', 'romantic', 'budding_romance']]
list_2 = [['love', 'eating', 'spicy', 'hand', 'pulled', 'noodles'],
['also', 'like', 'buy', 'perfumes'],
['suffer', 'from', 'clinical', 'depression'],
['really', 'love', 'my', 'wife']]
我想计算上面两个列表之间的余弦相似度,其中列表 1 中的第一个子列表与列表 2 的所有子列表之间的余弦相似度是相互测量的。然后是同样的事情,但列表 1 中的第二个子列表和列表 2 中的所有子列表等
目标是通过 len(list_1) 创建一个 len(list_2) 矩阵,并且该矩阵中的每个条目都是余弦相似度分数。目前我是通过以下方式完成的:
import gensim
import numpy as np
from gensim.models import KeyedVectors
model = KeyedVectors.load_word2vec_format('./data/GoogleNews-vectors-negative300.bin.gz', binary=True)
similarity_mat = np.zeros([len(list_2), len(list_1)])
for i, L2 in enumerate(list_2):
for j, L1 in enumerate(list_1):
similarity_mat[i, j] = model.n_similarity(L2, L1)
但是,我想用矩阵乘法而不是 for 循环来实现它。
我的两个问题是:
- 有没有一种方法可以进行某种元素矩阵乘法,但使用
gensim's n_similiarity() method
来生成所需的矩阵?
- 使用当前方法或矩阵乘法会更高效、更快速吗?
我希望我的问题足够清楚,如果我能进一步澄清,请告诉我。
代码中有两个问题,倒数第二行和最后一行。
import gensim
import numpy as np
from gensim.models import KeyedVectors
model = KeyedVectors.load_word2vec_format('/root/input/GoogleNews-vectors-negative300.bin.gz', binary=True)
similarity_mat = np.zeros([len(list_2), len(list_1)])
for i, L2 in enumerate(list_2):
for j, L1 in enumerate(list_1):
similarity_mat[i, j] = model.n_similarity(L2, L1)
您问题的答案:
1.您已经在使用直接函数来计算首先转换为两个向量的两个句子(L1 和 L2)之间的相似度,然后计算这两个向量的余弦相似度。一切都已经在 n_similarity() 内部完成,因此您不能进行任何类型的矩阵乘法。
如果你想做自己的矩阵乘法,那么不要直接使用 n_similarity() 计算句子的向量,然后在计算余弦相似度时应用矩阵乘法。
2. 正如我在 (1) 中所说,一切都在 n_similarity() 中完成,gensim 的创建者在编写库时会注意效率,因此任何其他乘法方法很可能不会产生影响。
这是一种方法,但是从问题中看不清楚the underlying mechanics of the calculation,这可能会导致阻塞。
我更改了输入字符串以提供更精确的单词匹配,并为两个字符串提供了不同的维度以使其更清晰:
from sklearn.feature_extraction.text import CountVectorizer
import numpy as np
list_1 = [['flavor', 'flavors', 'fruity_flavor', 'taste'],
['scent', 'my', 'aroma', 'smell', 'odor'],
['mental_illness', 'mental_disorders','bipolar_disorder'],
['romance', 'romances', 'romantic', 'budding_romance']]
list_2 = [['love', 'eating', 'spicy', 'hand', 'pulled', 'noodles'],
['also', 'like', 'buy', 'perfumes'],
['suffer', 'from', 'clinical', 'depression'],
['really', 'love', 'my', 'wife'],
['flavor', 'taste', 'romantic', 'aroma', 'what']]
cnt = CountVectorizer()
# Combine each sublist into single str, and join everything into corpus
combined_lists = ([' '.join(item) for item in list_1] +
[' '.join(item) for item in list_2])
count_matrix = cnt.fit_transform(combined_lists).toarray()
# Split them again into list_1 and list_2 word counts
count_matrix_1 = count_matrix[:len(list_1),]
count_matrix_2 = count_matrix[len(list_1):,]
match_matrix = np.matmult(count_matrix_1, count_matrix_2.T)
match_matrix 的输出:
array([[0, 0, 0, 0, 2],
[0, 0, 0, 1, 1],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 1]], dtype=int64)
你可以看到list_1
中的第一个字符串与list_2
中的第5个字符串有2个匹配,依此类推。
所以计算的第一部分(点积)已经计算出来了。现在我们需要震级:
magnitudes = np.array([np.linalg.norm(count_matrix[i,:])
for i in range(len(count_matrix))])
现在我们可以使用矩阵乘法将其转换为除数矩阵(我们需要将大小重塑为 n x 1 和 1 x n 矩阵,以生成 n x n 矩阵:
divisor_matrix = np.matmul(magnitudes.reshape(len(magnitudes),1),
magnitudes.reshape(1,len(magnitudes)))
现在因为我们没有比较每个子列表,而只比较 list_1 和 list_2 子列表,我们需要取这个除数矩阵的一个子部分以获得正确的大小:
divisor_matrix = divisor_matrix[:len(list_1), len(list_1):]
输出:
array([[4.89897949, 4. , 4. , 4. , 4.47213595],
[5.47722558, 4.47213595, 4.47213595, 4.47213595, 5. ],
[4.24264069, 3.46410162, 3.46410162, 3.46410162, 3.87298335],
[4.89897949, 4. , 4. , 4. , 4.47213595]])
现在我们可以计算余弦相似度得分的最终矩阵:
cos_sim = match_matrix / divisor_matrix
输出:
array([[0. , 0. , 0. , 0. , 0.4472136],
[0. , 0. , 0. , 0.2236068, 0.2 ],
[0. , 0. , 0. , 0. , 0. ],
[0. , 0. , 0. , 0. , 0.2236068]])
请注意这些分数与给定的示例不同,因为在示例中每个余弦相似度分数都是 0。
我有两个列表:
list_1 = [['flavor', 'flavors', 'fruity_flavor', 'taste'],
['scent', 'scents', 'aroma', 'smell', 'odor'],
['mental_illness', 'mental_disorders','bipolar_disorder']
['romance', 'romances', 'romantic', 'budding_romance']]
list_2 = [['love', 'eating', 'spicy', 'hand', 'pulled', 'noodles'],
['also', 'like', 'buy', 'perfumes'],
['suffer', 'from', 'clinical', 'depression'],
['really', 'love', 'my', 'wife']]
我想计算上面两个列表之间的余弦相似度,其中列表 1 中的第一个子列表与列表 2 的所有子列表之间的余弦相似度是相互测量的。然后是同样的事情,但列表 1 中的第二个子列表和列表 2 中的所有子列表等
目标是通过 len(list_1) 创建一个 len(list_2) 矩阵,并且该矩阵中的每个条目都是余弦相似度分数。目前我是通过以下方式完成的:
import gensim
import numpy as np
from gensim.models import KeyedVectors
model = KeyedVectors.load_word2vec_format('./data/GoogleNews-vectors-negative300.bin.gz', binary=True)
similarity_mat = np.zeros([len(list_2), len(list_1)])
for i, L2 in enumerate(list_2):
for j, L1 in enumerate(list_1):
similarity_mat[i, j] = model.n_similarity(L2, L1)
但是,我想用矩阵乘法而不是 for 循环来实现它。
我的两个问题是:
- 有没有一种方法可以进行某种元素矩阵乘法,但使用
gensim's n_similiarity() method
来生成所需的矩阵? - 使用当前方法或矩阵乘法会更高效、更快速吗?
我希望我的问题足够清楚,如果我能进一步澄清,请告诉我。
代码中有两个问题,倒数第二行和最后一行。
import gensim
import numpy as np
from gensim.models import KeyedVectors
model = KeyedVectors.load_word2vec_format('/root/input/GoogleNews-vectors-negative300.bin.gz', binary=True)
similarity_mat = np.zeros([len(list_2), len(list_1)])
for i, L2 in enumerate(list_2):
for j, L1 in enumerate(list_1):
similarity_mat[i, j] = model.n_similarity(L2, L1)
您问题的答案:
1.您已经在使用直接函数来计算首先转换为两个向量的两个句子(L1 和 L2)之间的相似度,然后计算这两个向量的余弦相似度。一切都已经在 n_similarity() 内部完成,因此您不能进行任何类型的矩阵乘法。
如果你想做自己的矩阵乘法,那么不要直接使用 n_similarity() 计算句子的向量,然后在计算余弦相似度时应用矩阵乘法。
2. 正如我在 (1) 中所说,一切都在 n_similarity() 中完成,gensim 的创建者在编写库时会注意效率,因此任何其他乘法方法很可能不会产生影响。
这是一种方法,但是从问题中看不清楚the underlying mechanics of the calculation,这可能会导致阻塞。
我更改了输入字符串以提供更精确的单词匹配,并为两个字符串提供了不同的维度以使其更清晰:
from sklearn.feature_extraction.text import CountVectorizer
import numpy as np
list_1 = [['flavor', 'flavors', 'fruity_flavor', 'taste'],
['scent', 'my', 'aroma', 'smell', 'odor'],
['mental_illness', 'mental_disorders','bipolar_disorder'],
['romance', 'romances', 'romantic', 'budding_romance']]
list_2 = [['love', 'eating', 'spicy', 'hand', 'pulled', 'noodles'],
['also', 'like', 'buy', 'perfumes'],
['suffer', 'from', 'clinical', 'depression'],
['really', 'love', 'my', 'wife'],
['flavor', 'taste', 'romantic', 'aroma', 'what']]
cnt = CountVectorizer()
# Combine each sublist into single str, and join everything into corpus
combined_lists = ([' '.join(item) for item in list_1] +
[' '.join(item) for item in list_2])
count_matrix = cnt.fit_transform(combined_lists).toarray()
# Split them again into list_1 and list_2 word counts
count_matrix_1 = count_matrix[:len(list_1),]
count_matrix_2 = count_matrix[len(list_1):,]
match_matrix = np.matmult(count_matrix_1, count_matrix_2.T)
match_matrix 的输出:
array([[0, 0, 0, 0, 2],
[0, 0, 0, 1, 1],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 1]], dtype=int64)
你可以看到list_1
中的第一个字符串与list_2
中的第5个字符串有2个匹配,依此类推。
所以计算的第一部分(点积)已经计算出来了。现在我们需要震级:
magnitudes = np.array([np.linalg.norm(count_matrix[i,:])
for i in range(len(count_matrix))])
现在我们可以使用矩阵乘法将其转换为除数矩阵(我们需要将大小重塑为 n x 1 和 1 x n 矩阵,以生成 n x n 矩阵:
divisor_matrix = np.matmul(magnitudes.reshape(len(magnitudes),1),
magnitudes.reshape(1,len(magnitudes)))
现在因为我们没有比较每个子列表,而只比较 list_1 和 list_2 子列表,我们需要取这个除数矩阵的一个子部分以获得正确的大小:
divisor_matrix = divisor_matrix[:len(list_1), len(list_1):]
输出:
array([[4.89897949, 4. , 4. , 4. , 4.47213595],
[5.47722558, 4.47213595, 4.47213595, 4.47213595, 5. ],
[4.24264069, 3.46410162, 3.46410162, 3.46410162, 3.87298335],
[4.89897949, 4. , 4. , 4. , 4.47213595]])
现在我们可以计算余弦相似度得分的最终矩阵:
cos_sim = match_matrix / divisor_matrix
输出:
array([[0. , 0. , 0. , 0. , 0.4472136],
[0. , 0. , 0. , 0.2236068, 0.2 ],
[0. , 0. , 0. , 0. , 0. ],
[0. , 0. , 0. , 0. , 0.2236068]])
请注意这些分数与给定的示例不同,因为在示例中每个余弦相似度分数都是 0。