【问题标题】:Find sequences of words in sublists in Python在 Python 的子列表中查找单词序列
【发布时间】:2018-06-04 12:36:06
【问题描述】:

在一些 NLP 任务中,我有一个嵌套的字符串列表:

    [['Start', 'двигаться', 'другая', 'сторона', 'света', 'надолго', 'скоро'], 
     ['Start', 'двигаться', 'другая', 'сторона', 'света', 'чтобы', 'посмотреть'],
     ['Start', 'двигаться', 'новая', 'планета'],
     ['Start', 'двигаться', 'сторона', 'признание', 'суверенитет', 'израильский'],
     ['Start', 'двигаться', 'сторона', 'признание', 'высот', 'на'],
     ['Start', 'двигаться', 'сторона', 'признание', 'высот', 'оккупировать'],
     ['Start', 'двигаться', 'сторона', 'признание', 'высот', 'Голанский'],
     ['Start', 'двигаться', 'сторона', 'признание', 'и']]

我需要一种算法来找到两个或更多元素,这些元素对于两个或更多子列表很常见,并从中生成单个元素。在我的示例中,'Start', 'двигаться' 对所有元素都是通用的,因此它应该成为单个字符串。 'сторона', 'света', 'надолго' 对于两个元素是通用的,所以它变成了单个字符串。 'сторона', 'признание' 常见于 5 个元素,因此它变成单个字符串。如果没有剩余的公共元素,只需将其余元素添加为单个字符串。 期望的输出:

    [['Start двигаться', 'другая сторона света', 'надолго скоро'], 
     ['Start двигаться', 'другая сторона света', 'чтобы посмотреть'],
     ['Start двигаться', 'новая планета'],
     ['Start двигаться', 'сторона признание', 'суверенитет израильский'],
     ['Start двигаться', 'сторона признание', 'высот на'],
     ['Start двигаться', 'сторона признание', 'высот оккупировать'],
     ['Start двигаться', 'сторона признание', 'высот Голанский'],
     ['Start двигаться', 'сторона признание', 'и']]

到目前为止,我尝试了一些循环和元素比较:

for elem,next_elem in zip(lst, lst[1:]+[lst[0]]):
    if elem[0] == next_elem[0] and elem[1] == next_elem[1] and elem[2] == next_elem[2]:
        elem[0:3] = [' '.join(elem[0:3])]

    if elem[0] == next_elem[0] and elem[1] == next_elem[1]:
        elem[0:2] = [' '.join(elem[0:2])]

但我认为这不是正确的方法。集合也不是一种选择,因为子列表中的一个元素可以多次出现。 我检查了其他 LCS 主题,但没有找到解决方案。任何可以完成这项工作的工作算法都会很棒,目前效率并不重要。更多示例:

[[a,b,c,d],
 [a,b,d,e,f]]

应该变成:

[[ab,cd],
 [ab,def]]

由于a,b 是公共元素,而cd, def 只是成为单个元素。

[[a,b,c,d,e,g],
[a,b,c,d,g,h],
[a,b,h,h,i]]

应该变成:

[[ab,cd,eg],
 [ab,cd,gh],
 [ab,hhi]]

因为abcd 是两个或多个子列表的大炮

还有:

[[a,b,c],
 [a,b,d]] 

变成:

[[ab, c],
 [ab, d]]

由于c, d 不是常见元素

【问题讨论】:

  • here
  • 如果你有[[a, b], [a, b, c], [b, c]] 怎么办?还有,为什么'и'之前加入了字符串,而'высот'没有加入?
  • @tobias_k 感谢您的回复!在这种情况下,输出将是[[a b], [a b c], [b c]],因为“c”将是单个左侧元素,应该添加到前一个序列中,而“b c”是唯一元素。

标签: python python-3.x algorithm list lcs


【解决方案1】:

我建议你使用 hashmaps key:word, value: Integer 作为计数器,从 0 开始。(这是 python 中的字典)。对于每一行,散列每个值并增加计数器。最后,对于计数器为 2 或更多的每个单词,将它们连接起来。

我省略了代码和仅连接具有相同计数器的字符串的部分,以及重复,因为这似乎是家庭作业。

【讨论】:

    【解决方案2】:

    您可以先创建一个代表您的列表的prefix-tree

    lists = [['Start', 'двигаться', 'другая', 'сторона', 'света', 'надолго', 'скоро'], 
             ['Start', 'двигаться', 'другая', 'сторона', 'света', 'чтобы', 'посмотреть'],
             ['Start', 'двигаться', 'новая', 'планета'],
             ['Start', 'двигаться', 'сторона', 'признание'],
             ['Start', 'двигаться', 'сторона', 'признание', 'суверенитет', 'израильский'],
             ['Start', 'двигаться', 'сторона', 'признание', 'высот', 'на'],
             ['Start', 'двигаться', 'сторона', 'признание', 'высот', 'оккупировать'],
             ['Start', 'двигаться', 'сторона', 'признание', 'высот', 'Голанский'],
             ['Start', 'двигаться', 'сторона', 'признание', 'и']]
    
    tree = {}
    end = "END"
    for lst in lists:
        d = tree
        for x in lst:
            d = d.setdefault(x, {})
        d[end] = {}
    

    结果(这里,END 标记句子结束的位置):

    {'Start': {'двигаться': {'другая': {'сторона': {'света': {'надолго': {'скоро': {'END': {}}},
                                                              'чтобы': {'посмотреть': {'END': {}}}}}},
                             'новая': {'планета': {'END': {}}},
                             'сторона': {'признание': {'END': {},
                                                       'высот': {'Голанский': {'END': {}},
                                                                 'на': {'END': {}},
                                                                 'оккупировать': {'END': {}}},
                                                       'и': {'END': {}},
                                                       'суверенитет': {'израильский': {'END': {}}}}}}}}
    

    现在,您可以递归地遍历该树,并且只要一个节点只有一个子节点(只有一个元素的子字典),就加入这些节点。

    def join(d, pref=[]):
        if end in d:
            yield [' '.join(pref)] if pref else []
        for k, v in d.items():
            if len(v) == 1:
                for x in join(v, pref + [k]): # add node to prefix
                    yield x                   # yield next segment
            else:
                for x in join(v, []):         # reset prefix
                    yield [' '.join(pref + [k])] + x # yield node + prefix and next
    

    输出与您的问题中的完全不同,但非常接近。它将连接树中只有一个子节点的所有部分,即之后的段应该是最大的,而没有段是更长段的一部分。

    >>> for x in join(tree):
    ...     print(x)
    ...
    ['Start двигаться', 'другая сторона света', 'надолго скоро']
    ['Start двигаться', 'другая сторона света', 'чтобы посмотреть']
    ['Start двигаться', 'новая планета']
    ['Start двигаться', 'сторона признание']
    ['Start двигаться', 'сторона признание', 'суверенитет израильский']
    ['Start двигаться', 'сторона признание', 'высот', 'на']
    ['Start двигаться', 'сторона признание', 'высот', 'оккупировать']
    ['Start двигаться', 'сторона признание', 'высот', 'Голанский']
    ['Start двигаться', 'сторона признание', 'и']
    

    这是基于树的方法的示例。颜色表示没有将要合并的任何分支的部分;端节点是粗体的(不一定是叶节点)。

    【讨论】:

    • @AlexNikitin 谢谢,虽然我觉得join 函数比必要的复杂。以后再看……
    • 通过将новая планета更改为сторона планета来破坏算法:[['Start двигаться', 'другая сторона света', 'надолго скоро'], ['Start двигаться', 'другая сторона света', 'чтобы посмотреть'], ['Start двигаться', 'сторона планета'], ['Start двигаться', 'сторона', 'признание', 'суверенитет израильский'], ['Start двигаться', 'сторона', 'признание', 'высот на'], ['Start двигаться', 'сторона', 'признание', 'высот оккупировать'], ['Start двигаться', 'сторона', 'признание', 'высот Голанский'], ['Start двигаться', 'сторона', 'признание и']]
    • @AlexNikitin 有趣...我会看看那个。
    • @AlexNikitin 你能再检查一次吗?至少我不能再重现那个问题了。
    • 再次感谢,可视化真的很棒!树的构建似乎存在一些问题。如果我在输入中将'новая', 'планета' 更改为'сторона', 'планета''сторона', 'признание' 将成为输出中的分隔元素。可以重现类似的情况,我仔细检查了。
    猜你喜欢
    • 1970-01-01
    • 2022-01-13
    • 1970-01-01
    • 2013-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多