为带有单词的列表列表生成唯一的ID

时间:2019-01-16 15:22:31

标签: python python-3.x

我有一对带有单词对的列表,想在id上描述单词。编号应介于0到len(set(words))之间。现在,列表如下所示:

[['pluripotent', 'Scharte'],
 ['Halswirbel', 'präventiv'],
 ['Kleiber', 'Blauspecht'],
 ['Kleiber', 'Scheidung'],
 ['Nillenlutscher', 'Salzstangenlecker']]    

结果应具有相同的格式,但应使用ID。例如:

[[0, 1],
 [2, 3],
 [4, 5],
 [4, 6],
 [7, 8]]

到目前为止,我已经有了这个,但是它没有给我正确的输出:

def words_to_ids(labels):
  vocabulary = []
  word_to_id = {}
  ids = []
  for word1,word2 in labels:
      vocabulary.append(word1)
      vocabulary.append(word2)

  for i, word in enumerate(vocabulary):
      word_to_id [word] = i
  for word1,word2 in labels:
      ids.append([word_to_id [word1], word_to_id [word1]])
  print(ids)

输出:

[[0, 0], [2, 2], [6, 6], [6, 6], [8, 8]]

在有唯一单词的地方重复ID。

2 个答案:

答案 0 :(得分:2)

您有两个错误。首先,您在这里有一个简单的错字:

for word1,word2 in labels:
    ids.append([word_to_id [word1], word_to_id [word1]])

您要在此添加word1 两次的ID。更正第二个word1来查找word2

接下来,您不会测试您是否曾经看过一个单词,因此对于'Kleiber',您首先为其指定ID 4,然后在下一次迭代时使用6覆盖该条目。您需要提供唯一单词编号,而不是所有单词:

counter = 0
for word in vocabulary:
    if word not in word_to_id:
        word_to_id[word] = counter
        counter += 1

,或者如果您已经列出该单词,则根本无法在vocabulary中添加一个单词。顺便说一下,您在这里实际上不需要单独的vocabulary列表。单独的循环不会为您带来任何好处,因此以下方法也可以:

word_to_id = {}
counter = 0
for words in labels:
    for word in words:
        word_to_id [word] = counter
        counter += 1

通过使用defaultdict objectitertools.count()提供默认值,可以大大简化代码:

from collections import defaultdict
from itertools import count

def words_to_ids(labels):
    word_ids = defaultdict(count().__next__)
    return [[word_ids[w1], word_ids[w2]] for w1, w2 in labels]

每次调用count()时,__next__对象都会为您提供序列中的下一个整数值,并且每次您尝试访问未访问的键时,defaultdict()都会调用该整数值。尚未存在于字典中。它们共同确保了每个唯一单词的唯一ID。

答案 1 :(得分:1)

有两个问题:

  1. 您通过在word1中重复搜索word_to_id来打错了字。
  2. 构造word_to_id字典时,您只需要考虑唯一值即可。

例如,在Python 3.7+中,您可以利用插入顺序字典:

for i, word in enumerate(dict.fromkeys(vocabulary)):
    word_to_id[word] = i

for word1, word2 in labels:
    ids.append([word_to_id[word1], word_to_id[word2]])

3.7版之前的替代方法是使用collections.OrderedDictitertools unique_everseen recipe

如果没有订购要求,则只需使用set(vocabulary)