首页 > 编程语言 >基于n-gram语言模型实现输入单词推荐功能(附源码及语料库)

基于n-gram语言模型实现输入单词推荐功能(附源码及语料库)

时间:2024-06-01 14:57:46浏览次数:12  
标签:pairs word 语料库 单词 源码 gram pair counts

一、开发环境

1.语言:python

2.开源工具:nltk

3.语料库:维基百科英文语料库

二、环境配置

关于pyhton项目对nltk的部署,我看了以下文章。

NLTK库安装教程

在安装nltk库的过程中,我又遇到了pip更新的问题,看了以下文章。

PIP更新

​​​​三、实验要求

利用n-gram语言模型完成,输入文字时的推荐功能,一个单词时推荐1-gram统计词频最大的前五个,两个单词时看前一个单词和当前单词的2-gram得分最高的前五个,已输入第三个单词时看前两个单词与当前单词的3-gram得分最高的前五个,最多看3-gram。

四、分析与实现

根据以上计算公式,得出,当已输入词大于等于1时,以使用tri-gram模型进行推荐为例,假设已输入的词分别为A,B,语料库中其他的单词为X,所以只计算P(X|A,B)=P(A,B,X)/P(A,B),找出其中最大的前五个单词X。由于分子相同,所以只比较分母。以下是实现的代码。

import re
from collections import Counter
from nltk.tokenize import word_tokenize
from collections import defaultdict

text_file = 'wiki01.txt'

# 读取文件内容
with open(text_file, 'r', encoding='utf-8') as file:
    text = file.read()

# 使用正则表达式去除标点符号
text = re.sub(r'[^\w\s]', '', text)

# 分词
tokens = word_tokenize(text)

# 第一次推荐
def uni_gram():
    word_counts = Counter(tokens)
    # 输出词频最高的前五个单词
    for word, count in word_counts.most_common(5):
        print(f"推荐:{word}")

# 第二次推荐
def bi_gram(A):
    word_pairs_counts = defaultdict(int)
    # 遍历分词后的列表,找到包含目标单词A的词对
    for i in range(len(tokens) - 1):
        if tokens[i].lower() == A.lower():  # 忽略大小写比较
            # 词对是(A,后一个词)
            if i > 0 and i < len(tokens)-1:
                word_pairs_counts[(A, tokens[i + 1])] += 1
    if not word_pairs_counts:
        print("未找到合适的推荐")
    else:
        # 输出频率最高的前五个词对
        top_pairs = sorted(word_pairs_counts.items(), key=lambda x: x[1], reverse=True)[:5]
        # 如果频率最高的词对个数不足五个,输出提示信息
        if len(top_pairs) < 5:
            print("合适的推荐不足五个,只找到以下推荐:")
            for pair, count in sorted(word_pairs_counts.items(), key=lambda x: x[1], reverse=True)[:5]:
                print(f"推荐:({pair[0]}  {pair[1]})")
        else:
            for pair, count in sorted(word_pairs_counts.items(), key=lambda x: x[1], reverse=True)[:5]:
                print(f"推荐:({pair[0]}  {pair[1]})")



def tri_gram(A,B):
    tri_word_pairs_counts = defaultdict(int)
    # 遍历分词后的列表,找到同时包含A和B,且顺序为A, B, C的词对
    for i in range(len(tokens) - 2):
        if tokens[i].lower() == A.lower() and tokens[i + 1].lower() == B.lower():
            # 三词词对是(A, B, C)
            tri_word_pairs_counts[(tokens[i], tokens[i + 1], tokens[i + 2])] += 1
            # 输出频率最高的前五个三词词对
    if not tri_word_pairs_counts:
        print("未找到合适的推荐")
    else:
        # 输出频率最高的前五个三词词对
        top_pairs = sorted(tri_word_pairs_counts.items(), key=lambda x: x[1], reverse=True)[:5]
        # 如果频率最高的词对个数不足五个,输出提示信息
        if len(top_pairs) < 5:
            print("合适的推荐不足五个,只找到以下推荐:")
            for pair, count in sorted(tri_word_pairs_counts.items(), key=lambda x: x[1], reverse=True)[:5]:
                print(f"推荐 ({pair[0]}, {pair[1]}, {pair[2]})")
        else:
            for pair, count in sorted(tri_word_pairs_counts.items(), key=lambda x: x[1], reverse=True)[:5]:
                print(f"推荐 ({pair[0]}, {pair[1]}, {pair[2]})")


def main():0
    # 主程序代码
    uni_gram()
    word_list = []
    while True:
        word = input("请输入一个单词(输入'0'结束): ")
        if word == '0':
            break
        word_list.append(word)  # 将单词添加到列表中
        length = len(word_list)
        if length == 1:
            bi_gram(word_list[0])
        else:
            tri_gram(word_list[length-2],word_list[length-1])

# 检查脚本是否作为主程序运行(而不是被导入为模块)
if __name__ == "__main__":
    main()

五、实验结果

为了方便测试,我只截取了维基英文语料库中的一部分作为本次实验的语料库。实验结果如下:当已输入单词超过两个时,一直使用tri-gram模型进行推荐,由于在前两个单词的影响下,有时会无法在语料库中找到足够的合适的推荐(与语料库的大小有关)。

六、语料库资源下载

链接:https://pan.baidu.com/s/1HKvYn974fiuX0QgZ2hOmDA 
提取码:qtra 


感谢观看,希望对你有帮助!

标签:pairs,word,语料库,单词,源码,gram,pair,counts
From: https://blog.csdn.net/weixin_62284803/article/details/139373412

相关文章