估计两个单词之间的音素相似度

11

我正在使用卡内基梅隆大学的发音字典,致力于在Python中检测押韵,并想知道:如何估计两个单词之间的语音相似性?换句话说,是否有一种算法可以确定“hands”和“plans”比“hands”和“fries”更接近韵律?

一些背景信息:起初,我希望说如果两个单词的重读音节及其后续的所有音节都相同,则它们是押韵的(如果您想在Python中复制,请参考c06d):

def create_cmu_sound_dict():

    final_sound_dict = {}

    with open('resources/c06d/c06d') as cmu_dict:
        cmu_dict = cmu_dict.read().split("\n")
        for i in cmu_dict:
            i_s = i.split()
            if len(i_s) > 1:
                word = i_s[0]
                syllables = i_s[1:]

                final_sound = ""
                final_sound_switch = 0

                for j in syllables:
                    if "1" in j:
                        final_sound_switch = 1
                        final_sound += j
                    elif final_sound_switch == 1:
                        final_sound += j

            final_sound_dict[word.lower()] = final_sound

    return final_sound_dict

如果我接着运行

print cmu_final_sound_dict["hands"]
print cmu_final_sound_dict["plans"]

我发现hands和plans听起来非常相似。虽然我可以自己努力估算它们之间的相似度,但我想询问一下:是否有复杂的算法可以将这种声音(或听觉)相似度与数学值联系起来?也就是说,有哪些算法或软件包可以用来数值化两个单词之间的音位相似度?我知道这是一个大问题,但如果其他人能够提供任何建议,我将不胜感激。


2
您是否在寻找类似 Soundex 算法的东西?(http://en.wikipedia.org/wiki/Soundex) - acfrancis
我不能代表那个给你点踩的人说话,但关闭投票的原因是你的问题看起来像是在寻求建议。你可能想重新提问,更明确地询问“我应该怎样做X?”,而不是“我应该使用哪种工具来做X?”。 - Ilmari Karonen
@acfrancis,Soundex 看起来很有趣,但它似乎更像一种哈希算法,而不是一种可以估计两个单词之间音位相似度的方法。 - duhaime
这个问题要么是在寻找算法,要么是在寻找库。无论哪种方式,都没有人能够写出正确的答案,因为有(希望)许多可能的正确答案,并且选择最好的答案完全是主观的。这并不意味着这是一个不好的问题 - 在不同的StackExchange站点、邮件列表和论坛等地方可能会成为一个很好的问题。这只是意味着它不适合StackOverflow。 - abarnert
没有一种算法可以检测所有的押韵,但是语音算法可以检测一些类型。Metaphone和Soundex(用于英语)都可以用于此目的。 - Tom Erik Støwer
显示剩余3条评论
2个回答

4

1) 通过Web API或本地SAPI获取所有单词的TTS音频

2) 如果可以,提取语音特征(1,2),或者至少获取语音数据的功率

3) 根据您拥有的功能,这里有一些方法。

如果您可以获取每个语音数据样本(维度为1)的功率,则一种简单的方法无疑是计算两组特征的相关性

如果您有其他类型的功能,很可能会具有更多的维度,您可以将其视为图像,并查看2d卷积动态时间扭曲

4)如果您对任务1、2、3的语音处理没有任何了解,请查看pyphonetics

#pip install pyphonetics
>>> from pyphonetics import RefinedSoundex
>>> rs = RefinedSoundex()
>>> rs.distance('Rupert', 'Robert')
0
>>> rs.distance('assign', 'assist', metric='hamming')
2

3
作弊。
#!/usr/bin/env python

from Levenshtein import *

if __name__ == '__main__':
    s1 = ['HH AE1 N D Z', 'P L AE1 N Z']
    s2 = ['HH AE1 N D Z', 'F R AY1 Z']
    s1nospaces = map(lambda x: x.replace(' ', ''), s1)
    s2nospaces = map(lambda x: x.replace(' ', ''), s2)
    for seq in [s1, s2, s1nospaces, s2nospaces]:
        print seq, distance(*seq)

输出:

['HH AE1 N D Z', 'P L AE1 N Z'] 5
['HH AE1 N D Z', 'F R AY1 Z'] 8
['HHAE1NDZ', 'PLAE1NZ'] 3
['HHAE1NDZ', 'FRAY1Z'] 5

库:https://pypi.python.org/pypi/python-Levenshtein/0.11.2

然而,由于您只有文本作为输入,基本上只有基于文本的CMU字典,所以您只能对文本输入进行某种操作;但是我认为,可用的音素数量有限,因此您可以选择最重要的音素并为它们分配“音位权重”。在您指出的CMU字典中,只有74个音素:

 % cat cmudict.06.txt | grep -v '#' | cut -f 2- -d ' ' | tr ' ' '\n' | sort | uniq | wc -l
 75

(75减去一行空行)

如果在第二步中做了更高级的事情,例如给特定的音素组合分配权重,则可能会获得更好的结果。然后,您可以修改某些Levenshtein-type距离度量(例如上面的库),以提供在文本输入上工作的“音素距离”度量。

第三步不需要太多工作:利润。


这个完全忽略了音位特征,使得“nd”倾向于向“n”的方向同化,而例如“nk”并不会这样做(或者倾向于“ngk”,或者确实被常规地实现为“ngk”)。 - tripleee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接