使用numpy 2d数组对齐两个句子中的单词

使用numpy 2d数组对齐两个句子中的单词,numpy,numpy-ndarray,Numpy,Numpy Ndarray,给定两个句子,我需要根据这些句子中单词之间的最佳相似性匹配来对齐这些句子中的单词 例如,考虑2句: sent1 = "John saw Mary" # 3 tokens sent2 = "All the are grown by farmers" # 6 tokens 这里,对于sent1中的每个令牌,我需要在sent2中找到最相似的令牌。此外,如果sent2中的令牌已经与sent1中的令牌匹配,则它不能与sent1中的另一令牌匹配 为此,我使用了一个句

给定两个句子,我需要根据这些句子中单词之间的最佳相似性匹配来对齐这些句子中的单词

例如,考虑2句:

sent1 = "John saw Mary" # 3 tokens
sent2 = "All the are grown by farmers" # 6 tokens
这里,对于
sent1
中的每个令牌,我需要在
sent2
中找到最相似的令牌。此外,如果
sent2
中的令牌已经与
sent1
中的令牌匹配,则它不能与
sent1
中的另一令牌匹配

为此,我使用了一个句子中标记之间的相似矩阵,如下所示

cosMat = (array([[0.1656948 , 0.16653526, 0.13380264, 0.09286133, 0.16262592,
         0.14392284],
        [0.40876892, 0.46331584, 0.28574535, 0.34924293, 0.2480594 ,
         0.25846344],
        [0.15394737, 0.10269377, 0.12189645, 0.09426117, 0.09631223,
         0.10549664]], dtype=float32)
cosMat
是一个
2d大小的数组(3,6)
,包含两个句子中标记的余弦相似性分数

np.argmax
将提供以下数组作为输出

np.argmax(cosMat,axis=1)
 array([1, 1, 0]))
但是,这不是一个有效的解决方案,因为
sent1
的第一个和第二个标记与
sent2
的第二个标记对齐

相反,我选择执行以下操作:

sortArr = np.dstack(np.unravel_index(np.argsort(-cosMat.ravel()), cosMat.shape))

rowSet = set()
colSet = set()
matches = list()
for item in sortArr[0]:
    if item[1] not in colSet:
        if item[0] not in rowSet:
            matches.append((item[0],item[1],cosMat[item[0],item[1]]))
            colSet.add(item[1])
            rowSet.add(item[0])
matches
这将产生以下输出,这是理想的输出:

[(1, 1, 0.46331584), (0, 0, 0.1656948), (2, 2, 0.121896446)]

我的问题是,对于我使用上述代码所做的事情,是否有更有效的方法来实现?

这里有一个替代方案,它要求您复制初始相似性矩阵。每次找到最佳匹配时,您都会通过将复制的矩阵中对应的行和列替换为
0
来丢弃该对中的两个标记。这确保您不会在多个对中找到相同的令牌

res = []
mat = np.copy(cosMat)
for _ in range(mat.shape[0]):
    i, j = np.unravel_index(mat.argmax(), mat.shape)
    res.append((i, j, mat[i, j]))
    mat[i,:], mat[:,j] = 0, 0
将返回:

[(1, 1, 0.46331584), (0, 0, 0.1656948), (2, 2, 0.12189645)]
但是,考虑到您只使用了一次
np.argsort
。你的速度可能会更快


否则,为了简洁起见,我会将您的版本改写为:

sortArr = zip(*np.unravel_index(np.argsort(-cosMat.ravel()), cosMat.shape))

matches = []
rows, cols = set(), set()
for x, y in sortArr:
    if x not in cols and y not in rows:
        matches.append((x, y, cosMat[x, y]))
        cols.add(x)
        rows.add(y)

您可以使用一个集合而不是两个集合,方法是为索引使用某种前缀来区分行和列。在这里,我也不确定这样做会有什么好处:

matches = []
matched = set()
for x, y in sortArr:
    if 'i%i'%x not in matched and 'j%i'%y not in matched:
        matches.append((x, y, cosMat[x, y]))
        matched.update(['i%s'%x, 'j%s'%y])

所以这里的答案是
saw-->the
John-->All
Mary-->都是
?@swag2198-是的,你是对的