查找给定长度的模态子串
我们的输入如下:
mylist = ["hey how's it going?", "I'm fine thanks.", "Did you get that thing?", "Of course I got that thing, that's why I asked you: how's it going?"]
首先,我们将定义一个预处理函数,以清理多余的空格和标点符号。这使得从句子中提取单词变得更容易:
def preprocess(strings):
# used this answer to get rid of extra whitespaces: https://stackoverflow.com/a/1546251/6735980
return [" ".join(string.split()).replace(",", "").replace(".", "").replace("?", "") for string in strings]
我们还将定义一个辅助函数来查找n -grams(一个句子中n 个单词的子字符串):
def find_n_grams(string, n):
words = string.split(" ")
n_grams = []
for i in range(len(words) - n + 1):
n_grams.append(" ".join([words[i + idx] for idx in range(n)]))
return n_grams
然后,我们可以使用以下函数为给定数量的单词找到问题中定义的“模态子字符串”。我不确定这是否是计算它的最佳/有效方法,但它可以完成工作:
def find_modal_substring(strings, num_words):
n_grams_per_string = [find_n_grams(string, num_words) for string in strings]
max_num_occurences = 0
modal_substring = None
for i in range(len(strings)):
n_grams = n_grams_per_string[i]
for n_gram in n_grams:
num_occurences = 1
for j in range(i + 1, len(strings)):
if n_gram in n_grams_per_string[j]:
num_occurences += 1
if num_occurences > max_num_occurences:
max_num_occurences = num_occurences
modal_substring = n_gram
elif num_occurences == max_num_occurences and len(modal_substring) < len(n_gram):
max_num_occurences = num_occurences
modal_substring = n_gram
return modal_substring
一些输入/输出对:
> print(find_modal_substring(preprocess(mylist), 3))
怎么样了
> print(find_modal_substring(preprocess(mylist), 2))
那个东西
使用 alpha 参数查找模态子字符串
这部分问题中最困难的事情是如何在给定 alpha 参数的情况下定义得分函数。我们知道:
接近 1 的 Alpha 将选择一个非常长(以单词表示)但不一定在列表中出现多次的模态子字符串。接近 0 的 Alpha 将选择在列表中出现尽可能多且不关心子字符串长度的模态子字符串。
以下是满足这一点的一个得分函数,但我们可能还可以想到许多其他得分函数。通过将它隔离在一个函数中,任何人都可以根据自己的需要轻松修改它:
def compute_score(n_gram, occurences, alpha):
return alpha * len(n_gram.split(" ")) + (1.0 - alpha) * occurences
鉴于此,查找基于 alpha 的模态子字符串的函数相当长,因为它首先需要为所有n找到所有可能的n -gram ,但我们开始:
def find_modal_substring_alpha(strings, alpha):
n_grams_per_n_per_string = []
n = 1
while True:
n_grams_per_string = [find_n_grams(string, n) for string in strings]
if all(n_grams == [] for n_grams in n_grams_per_string):
break
else:
n_grams_per_n_per_string.append(n_grams_per_string)
n += 1
best_modal_substring = None
best_score = 0.0
for n_grams_per_string in n_grams_per_n_per_string:
for i in range(len(strings)):
n_grams = n_grams_per_string[i]
for n_gram in n_grams:
num_occurences = 1
for j in range(i + 1, len(strings)):
if n_gram in n_grams_per_string[j]:
num_occurences += 1
score = compute_score(n_gram, num_occurences, alpha)
if score > best_score:
best_score = score
best_modal_substring = n_gram
elif score == best_score and len(best_modal_substring) < len(n_gram):
best_score = score
best_modal_substring = n_gram
return best_modal_substring
事实证明,在这里调整 alpha 有点困难。即使对于相对较低的 alpha ( 0.3
),我们得到的结果与我们得到的完全相同1.0
:
> print(find_modal_substring_alpha(preprocess(mylist), 0.3))
我当然知道了,所以我问你:最近怎么样
如果我们将 alpha 一直向下移动到0.01
例如,我们得到:
> print(find_modal_substring_alpha(preprocess(mylist), 0.01))
怎么样了