3 回答

TA貢獻(xiàn)1818條經(jīng)驗(yàn) 獲得超3個(gè)贊
有多種方法可以加快該過(guò)程,但我懷疑是否存在多項(xiàng)式解決方案。
因此,讓我們使用多重處理,并盡我們所能來(lái)生成有意義的結(jié)果。下面的示例與您所要求的并不相同,但它確實(shí)從一本大詞典中組成了一個(gè)明顯復(fù)合詞的列表。
對(duì)于下面的代碼,我正在獲取https://gist.github.com/h3xx/1976236,其中按英語(yǔ)頻率順序列出了大約 80,000 個(gè)唯一單詞。
如果預(yù)先按字母順序?qū)斎雴卧~列表進(jìn)行排序,則可以輕松加快下面的代碼,因?yàn)閺?fù)合詞的每個(gè)頭將立即跟隨其潛在的復(fù)合成員:
black
blackberries
blackberry
blackbird
blackbirds
blackboard
blackguard
blackguards
blackmail
blackness
blacksmith
blacksmiths
正如評(píng)論中提到的,您可能還需要使用語(yǔ)義過(guò)濾器來(lái)識(shí)別真正的復(fù)合詞 - 例如,“一般”一詞不是“基因集會(huì)”的復(fù)合詞!因此,雖然您可能會(huì)獲得競(jìng)爭(zhēng)者列表,但您需要以某種方式消除誤報(bào)。
# python 3.9
import multiprocessing as mp
# returns an ordered list of lowercase words to be used.
def load(name) -> list:
return [line[:-1].lower() for line in open(name) if not line.startswith('#') and len(line) > 3]
# function that identifies the compounds of a word from a list.
# ... can be optimised if using a sorted list.
def compounds_of(word: str, values: list):
return [w for w in values if w.startswith(word) and w.removeprefix(word) in values]
# apply compound finding across an mp environment
# but this is the slowest part
def compose(values: list) -> dict:
with mp.Pool() as pool:
result = {(word, i): pool.apply(compounds_of, (word, values)) for i, word in enumerate(values)}
return result
if __name__ == '__main__':
# https://gist.github.com/h3xx/1976236
words = load('wiki-100k.txt') # words are ordered by popularity, and are 3 or more letters, in lowercase.
words = list(dict.fromkeys(words))
# remove those word heads which have less than 3 tails
compounds = {k: v for k, v in compose(words).items() if len(v) > 3}
# get the top 500 keys
rank = list(sorted(compounds.keys(), key=lambda x: x[1]))[:500]
# compose them into a dict and print
tops = {k[0]: compounds[k] for k in rank}
print(tops)

TA貢獻(xiàn)1825條經(jīng)驗(yàn) 獲得超4個(gè)贊
我想我會(huì)這樣做:創(chuàng)建一個(gè)僅包含單詞的新列表。在 for 循環(huán)中遍歷此列表,并在其中查找屬于外循環(huán)單詞的一部分的單詞。如果找到:用空字符串替換找到的部分。如果隨后整個(gè)單詞被空字符串替換:顯示原始列表中相應(yīng)索引的單詞。
編輯:正如評(píng)論中所指出的,在某些情況下代碼可能存在問(wèn)題,例如:lst = ["BREAKFASTBUFFET;35", "BREAK;60", "BREAKFAST;18", "BUFFET;75"]
在 BREAKFASTBUFFET 中,我首先發(fā)現(xiàn) BREAK 是其中的一部分,所以我用空字符串替換了該代碼,這阻止找到早餐。我希望可以通過(guò)按單詞長(zhǎng)度降序?qū)α斜磉M(jìn)行排序來(lái)解決這個(gè)問(wèn)題。
編輯2
我之前的編輯并不是完美無(wú)缺的,比如有一個(gè)詞BREAKFASTEN,它不應(yīng)該被BREAKFAST“吃掉”。該版本執(zhí)行以下操作:
列出候選者列表:調(diào)查中單詞的所有單詞
制作另一個(gè)以該單詞開頭的單詞列表
跟蹤候選列表中您已經(jīng)嘗試過(guò)的單詞
一會(huì)兒正確:繼續(xù)嘗試,直到開始列表為空,或者您已成功地將所有單詞替換為候選單詞
lst = ['FAST;5','BREAK;60','FASTBREAK;40',
'OUTBREAK;110','BREAKFASTBUFFET;35',
'POINTS;25',
'BUFFET;75','FASTBREAKPOINTS;60', 'BREAKPOINTS;15'
]
lst2 = [ s.split(';')[0] for s in lst ]
for i, word in enumerate(lst2):
# candidates: words that are part of current word
candidates = [ x for i2, x in enumerate(lst2) if x in word and i != i2 ]
if len(candidates) > 0:
tried = []
word2 = word
found = False
while not found:
# start: subset of candidates that the current word starts with
start = [ x for x in candidates if word2.startswith(x) and x not in tried ]
for trial in start:
word2 = word2.replace(trial,'')
tried.append(trial)
if len(word2)==0:
print(lst[i])
found = True
break
if len(candidates)>1:
candidates = candidates[1:]
word2=candidates[0]
else:
break

TA貢獻(xiàn)1891條經(jīng)驗(yàn) 獲得超3個(gè)贊
這是一些完成這項(xiàng)工作的代碼。我確信它并不適合您的情況(有一百萬(wàn)個(gè)條目),但也許在某些方面有用:
#!/usr/bin/env python
from collections import namedtuple
Word = namedtuple("Word", ("characters", "number"))
separator = ";"
lst = [
"FAST;5",
"BREAK;60",
"FASTBREAK;40",
"OUTBREAK;110",
"BREAKFASTBUFFET;35",
"BUFFET;75",
"FASTBREAKPOINTS;60",
]
words = [Word(*w.rsplit(separator, 1)) for w in lst]
def findparts(oword, parts):
if len(oword.characters) == 0:
return parts
for iword in words:
if not parts and iword.characters == oword.characters:
continue
if iword.characters in oword.characters:
parts.append(iword)
characters = oword.characters.replace(iword.characters, "")
return findparts(Word(characters, oword.number), parts)
return []
ans = []
for word in words:
parts = findparts(word, [])
if parts:
ans.append(separator.join(word))
print(ans)
它使用遞歸函數(shù),獲取列表中的單詞并嘗試將其與同一列表中的其他單詞組合起來(lái)。此功能還將向您展示形成復(fù)合詞的實(shí)際原子詞。
然而,它并不是很聰明。以下是它不會(huì)檢測(cè)的組合示例:[BREAKFASTBUFFET, BREAK, BREAKFAST, BUFFET]。
它使用了一個(gè)命名元組來(lái)暫時(shí)將實(shí)際單詞與附加到它的數(shù)字分開,假設(shè)分隔符始終是;。
我不認(rèn)為正則表達(dá)式比簡(jiǎn)單的字符串搜索有優(yōu)勢(shì)。
如果您知道有關(guān)復(fù)合詞組成的更多條件,例如組件的最大數(shù)量,itertools組合生成器可能會(huì)幫助您顯著加快速度并避免錯(cuò)過(guò)上面給出的示例。
添加回答
舉報(bào)