【问题标题】:Python: Splitting composite words to known words (from dictionary)Python:将复合词拆分为已知词(来自字典)
【发布时间】:2018-06-07 21:08:36
【问题描述】:

我需要一个非常有效的算法来执行以下操作:

我必须分隔任何语言的复合词。以英语为例。

但是当一个单词由共享最后一个和第一个字母的两个单词组成时,就会出现问题。

即第一个单词以第二个单词开头的字母结尾。

所以,我们有一个包含所有可能单词的字典,请简短:

假设我们想用这个示例性的 dict 拆分“lightshow”这个词:

d = {"light": "Noun, S, N",
    "lights": "Noun, P, N",
    "how": "Q",
    "show": "Noun, S, N",
    ...}

我的算法现在将单词分块分成两个列表:

left = []; right = []
for x in range(len(word)-1, 1, -1):
    ls = word[:x]; rs = word[x:]
    if ls.lower() in d: left.append(ls)
    if rs.lower() in d: right.append(rs)

然后我找到左边最长的单词和右边列表中最长的单词。

所以,我知道这个词由哪些词组成,以及它们在复合词中的开始和结束位置。

现在不用担心单词不在字典中,单词不匹配等过度杀伤的情况,我只是想向您介绍这个想法以及这种方法的最大问题。

在整个算法结束时使用这种方法,结果将是:

["lights", "how"]

代替:

["light", "show"]

什么是你可以想象的不可接受的。

哦,是的,我可以使用以下命令检查 dict 中是否存在单词 show:

l = ["lights", "how"]
if l[0][-1]+l[1] in d: <repair the list>

但这是不切实际的,我的算法也递归处理由两个以上单词组成的单词。

它还处理因大小写等不同而分开的单词。

这就是为什么我没有将其全部发布的原因,因为它很大且经过优化,因此需要阅读很多不重要的代码。

哦,是的,我可以做一些改进,让最后一个词成为主要。或者在选择哪个先行时比较长度等。

但并不总是可以通过这些操作做出正确的决定。例如,如果发现最长的单词与多个字母相交,该怎么办?

我想在一个循环中完成所有操作。速度是必须的。

注意:我提供的字典是典型的。我必须使用的数据集不包含有关单词类型的任何信息。只是它的发音,唯一有用的信息可以是这个词在说话时是短还是长。

希望在这里看到一些非常好的想法。请记住,代码必须非常高效。 TTS 实时使用它来发音不在字典中但实际上包含单词的单词,并且通常发音匹配。 无需向我提供代码,只需将想法付诸实施即可。

【问题讨论】:

    标签: python


    【解决方案1】:

    在这些情况下,您可以偏爱由连字算法或字典建议的单词中的音节中断。一个好的断字算法会告诉你light-showdata-set 正确地分解了单词。

    我认为不可能在所有情况下都做到这一点,如果没有明确将lightshow 映射到light + showdatasetdata + set 等的数据文件,无论算法如何你想出来的总会有出错的地方。

    Frank Liang 的断字算法 is available here for Python,并帮助您的两个示例之一:

    >>> hyphenate_word("dataset")
    ['dataset']
    >>> hyphenate_word("lightshow")
    ['light', 'show']
    

    您可以尝试测试hyphenate_word() 返回的音节组合(应该非常有效,因为它在 TeX 中使用),如果找不到任何内容,请尝试您的原始方法。

    在这些方面做得很好:

     [hyphenate_word(x) for x in ["backwoodsman", "whatsoever", "hereupon", "counterclockwise", "notwithstanding", "highwayman "]]
    [['back', 'woods', 'man'], ['what', 'so', 'ev', 'er'], ['here', 'upon'], ['coun', 'ter', 'clock', 'wise'], ['notwith', 'stand', 'ing'], ['high', 'way', 'man ']]
    

    A handy list of compound words,还有一些triple compound words

    【讨论】:

    • 哇,酷!我可能会使用您建议的部分算法。尽管在内存中有一个额外的字典和发音字典有一个缺点。而且不多也不少,只是在字典树的形式中。我正在查看代码并问自己这是否有效。我应该测试它的速度。我认为应该做一些优化。
    • 顺便说一句,我根据您提供的列表测试了我的拆分算法。而且,主要是因为我有一本包含大部分化合物的广泛字典,不需要拆分,但是当它是它时,它大部分都可以。在普通化合物上,蚱蜢有问题:蚱蜢,但我自己不确定草蜢这个词是否有任何意义。 :D 虽然草蜢有一些。 :D 超人组的三重复合词令人不安。所以我不能说我的算法不起作用,但是当像灯光秀这样的情况出现时,我很生气。特别是如果它在文本中重复。
    【解决方案2】:

    我会立即想到 2 个因素,但您可能想先用您的数据集进行验证。

    1. 按单词类型加权。通常组合词由名词组成,因此如果您可以在N + QN + N 之间进行选择,那么N + N 很可能是正确的解决方案。在我的脑海中,我想不出一个你更喜欢名词而不是名词的例子,但这就是你应该检查的重点
    2. 单数、复数权重。尤其是中间的“s”,它通常是复数形式,所以更喜欢S + X而不是P + X

    【讨论】:

    • 有一个大问题,我的真实数据集不包含有关单词的信息。只是它的发音。很抱歉我忘了提及这一点,我现在将编辑我的 Q。顺便说一句,数据集是错误拆分的单词之一 ["datas", "et"] :D
    • 太糟糕了。但是,您至少可以通过选择s 位于第二个单词的开头而不是第一个单词的结尾的组合来捕获s 问题。
    • 问题是,不仅有 S,还有 d(就像在 replacedict 中一样),还有其他字母,尤其是用户自定义的单词和拼写错误。
    • 我的想法是不要使用最长的单词,而是至少从复合词的左侧开始有两个最长的现有单词,然后使用较短的单词。但是如何在不排序的情况下有效地实现这一点对我来说是一个问题,因为我刚刚暂时大脑冻结。我的意思是,一些修改后的 max() 就可以了。解冻后我得试试这个。
    • 听起来您总是想选择较短的“左”字。就像你的灯塔例子一样。这是否意味着正确的结果永远不可能是更长的单词?
    猜你喜欢
    • 2014-06-09
    • 2020-03-25
    • 2018-05-16
    • 2022-08-22
    • 2016-12-07
    • 2011-06-12
    • 1970-01-01
    • 1970-01-01
    • 2010-12-04
    相关资源
    最近更新 更多