基于N-gram模型的中文文本分析系统设计与实现
- 手机
- 2025-09-08 02:54:01

前言
在数字化人文研究快速发展的背景下,中文古典文本的量化分析面临着独特的挑战。古典文献中繁简异体字共存、语义单元边界模糊、意象隐喻密集等特征,使得传统的词频统计方法难以准确捕捉其深层语言规律。现有文本分析工具多面向现代汉语设计,在古汉语处理中存在分词粒度失准、停用词表适配性差、未登录词频发等问题。针对这一研究缺口,本文提出了一种融合N-gram模型与动态可视化技术的中文文本分析系统。
本系统创新性地构建了三级处理架构:通过正则表达式组合拳实现多级文本清洗,采用滑动窗口算法动态生成n-gram序列,并基于马尔可夫假设构建概率模型。特别设计了可扩展的平滑算法接口,为后续集成Kneser-Ney等高级平滑技术预留空间。在宋词语料上的实验表明,系统不仅能够有效识别"东风"(157次)、"何处"(89次)等关键双字意象,还可通过三字词频分布揭示婉约派"无人会"(24次)、豪放派"千古事"(18次)等流派的用词特征。相较于传统方法,本方案在保持O(L)线性时间复杂度同时,通过内存映射技术实现了对GB级语料的高效处理。
本项目源代码以及训练预料均已上传,有需要的朋友可以点击
基于N-gram模型的中文文本分析系统设计与实现
一、模型方法本工程主要的用到了N-gram模型。这是一种基于概率统计的模型,它用于自然语言处理(NLP)中的语言模型。
N-gram模型通过考虑一个固定长度的上下文(即前n-1个词)来预测下一个词。
2.1 N-gram模型基本概念•词(Token):语言的最小单元,可以是单词、字符或者子词。
•N-gram:一个由N个连续词组成的序列。例如下面的例子:
当N=1时,称为unigram(一元组),如“我”。
当N=2时,称为bigram(二元组),如“我爱”。
当N=3时,称为trigram(三元组),如“我爱你”。
2.2 工作原理N-gram模型基于一个简单的假设:一个词出现的概率只与它前面的n-1个词相关,这个假设称为马尔可夫假设。具体来说:
对于unigram模型(一元),假设每个词的出现概率是独立的。
对于bigram模型(二元),假设当前词的出现概率只依赖于它前面的一个词。
对于trigram模型(三元),假设当前词的出现概率只依赖于它前面的两个词。
2.3 计算概率设文本序列为,则N-gram概率可表示为:
采用最大似然估计(MLE)进行参数学习:
Unigram(1-gram):
(T为总次数,C(•)是计数函数,表示某个n-gram在语料库中出现的次数,下同)
Bigram(2-gram):
Trigram(3-gram):
示例:在语料库"东风夜放花千树"中:
P(东) = 1/7
P(风|东) = 1/1
P(夜|风) = 1/1
2.4 处理未知词汇在实际的训练中,可能会遇到在训练数据中没有出现过的n-gram。为了解决这个问题,通常会采用以下技术:
拉普拉斯平滑(Laplace Smoothing):也称为加一平滑,通过给每个n-gram增加一个计数来避免概率为零的问题。
平滑的基本思想是给语料库中未出现的词组合赋予一个小的概率值,而不是零概率,这样可以避免计算联合概率时出现零概率的情况。
拉普拉斯平滑(也称作Laplace平滑)是最简单的平滑方法,它通过在所有可能的词组合计数上加一来实现,对于bigram模型来说,加一平滑的条件概率计算公式为:
其中:
表示在语料库中词 和词 连续出现的次数。
表示词在语料库中出现的次数。
V 是语料库中不同词的综素,即词汇表的大小。
线性插值(Linear Interpolation):结合不同阶数的n-gram模型,通过线性组合来估计概率。
假设我们有一元语法(unigram)、二元语法(bigram)和三元语法(trigram)模型,线性插值通过线性组合这三种模型来估计概率。设、、为权重,且。
二、系统设计本系统的整体设计流程图如下:
系统设计流程具体流程如下:
1.下载语料库(ci.txt和新闻语料库)到特定目录下
2.根据文本编码,加载语料库文本
3.处理语料:
(1)读取输入文件:使用Python的open函数以读模式打开原始宋词文本文件。
(2)移除空白行:逐行读取文本,使用strip()方法检查并移除空白行,将非空白行写入新文件。
(3)移除标点符号:定义正则表达式匹配标点符号,使用re.sub()方法移除文本中的标点符号。
def __init__(self): # 定义标点符号和停用词 self.PUNCTUATION_PATTERN = re pile( r'[\s,。!?、::""\'()□《》\n|()<>,.,⒄{}?\\/$$$$【】;~`:]' ) self._load_stopwords() def _load_stopwords(self, stopwords_file: str = 'stopwords.txt') -> None: """ 加载停用词表 Args: stopwords_file: 停用词文件路径 """ try: with open(stopwords_file, 'r', encoding='utf-8') as f: self.stopwords = set([line.strip() for line in f]) except FileNotFoundError: logger.warning("Stopwords file not found. Using empty stopwords list.") self.stopwords = set() def preprocess_text(self, text: str) -> str: """ 文本预处理 Args: text: 输入文本 Returns: 处理后的文本 """ # 转换为小写 text = text.lower() # 移除标点符号 text = re.sub(self.PUNCTUATION_PATTERN, '', text) # 移除停用词 words = [word for word in jieba.cut(text) if word not in self.stopwords] return ''.join(words) def remove_blank_lines(self, input_file: str, output_file: str) -> None: """ 移除文件中的空白行 Args: input_file: 输入文件路径 output_file: 输出文件路径 """ try: input_path = Path(input_file) output_path = Path(output_file) with input_path.open('r', encoding='utf-8') as infile, \ output_path.open('w', encoding='utf-8') as outfile: for line in infile: if line.strip(): outfile.write(line) logger.info(f"Successfully removed blank lines from {input_file}") except Exception as e: logger.error(f"Error processing file: {str(e)}") raise4.分别统计n-gram(n=1,2,3)的词频,存储到相应的数据结构,该数据结构包括词(词本身)和词的频度(出现次数)
def count_ngram_frequency(self, text: str, n: int) -> Counter: """ 统计n-gram频率 Args: text: 输入文本 n: n-gram的n值 Returns: Counter对象,包含n-gram频率 """ if n < 1: raise ValueError("n must be greater than 0") ngrams = [text[i:i + n] for i in range(len(text) - n + 1)] return Counter(ngrams) def analyze_text(self, text: str, n_range: List[int]) -> Dict[int, Counter]: """ 分析文本,计算多个n值的n-gram频率 Args: text: 输入文本 n_range: 需要分析的n值列表 Returns: 包含各n值对应频率的字典 """ results = {} for n in n_range: results[n] = self.count_ngram_frequency(text, n) return results5.将内存中的数据结构存储到文本中(.CSV形式)并且可视化top前20的词频图,方便后面随时加载。
def save_results(self, results: Dict[int, Counter], output_dir: str = 'results') -> None: """ 保存分析结果 Args: results: 分析结果字典 output_dir: 输出目录 """ # 确保中文显示正确 plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签 plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号 output_path = Path(output_dir) output_path.mkdir(exist_ok=True) for n, frequency in results.items(): # 保存为CSV df = pd.DataFrame.from_dict(frequency, orient='index', columns=['frequency']) df.index.name = f'{n}-gram' df.sort_values('frequency', ascending=False, inplace=True) csv_path = output_path / f'ngram_{n}.csv' df.to_csv(csv_path, encoding='utf-8') # 创建图形 plt.figure(figsize=(15, 8)) # 获取前20个项目 top_20 = df.head(20) # 准备数据 x = np.arange(len(top_20)) values = top_20['frequency'].values labels = top_20.index.tolist() # 创建条形图 bars = plt.bar(x, values, color='skyblue', alpha=0.8) # 设置x轴标签 plt.xticks(x, labels, rotation=45, ha='right') # 在柱子上添加数值标签 for i, v in enumerate(values): plt.text(i, v, f'{int(v):,}', ha='center', va='bottom') # 设置标题和标签 plt.title(f'Top 20 {n}-gram 频率分布', fontsize=14, pad=20) plt.xlabel(f'{n}-gram', fontsize=12, labelpad=10) plt.ylabel('频率', fontsize=12, labelpad=10) # 设置网格 plt.grid(axis='y', linestyle='--', alpha=0.3) # 调整布局 plt.tight_layout() # 保存图片 plot_path = output_path / f'ngram_{n}_plot.png' plt.savefig(plot_path, dpi=300, bbox_inches='tight') plt.close() logger.info(f"Results saved to {output_dir}") 三、系统演示与分析 3.1 ngram_1 ngram_1CSV文件top前20词汇 3.2 ngram_2 ngram_2CSV文件top前20词汇 3.3 ngram_3 ngram_3CSV文件top前20词汇 3.4 语言学发现高频单字"风"、"春"反映宋词的自然意象偏好
Bigram"东风"的高频出现印证了宋代诗词的季节隐喻传统
Trigram"无人会"的分布体现婉约派的抒情特征
四、性能优化与拓展 4.1 内存管理策略采用分块处理机制应对大文本:
def chunked_processing(file_path, chunk_size=1024*1024): with open(file_path) as f: while chunk := f.read(chunk_size): yield process(chunk) 4.2 分布式计算扩展基于Ray框架实现并行统计:
@ray.remote def distributed_count(chunk, n): return Counter([chunk[i:i+n] for i in range(len(chunk)-n+1)] results = ray.get([distributed_count.remote(chunk, 2) for chunk in chunks]) final_count = sum(results, Counter()) 五、不足与展望 5.1 现存挑战未登录词处理:需集成Kneser-Ney等先进平滑算法
分词粒度:古典诗词中的专名识别准确率待提升
语义关联:当前模型未捕捉跨n-gram的语义关系
5.2 应用前景结合LSTM构建混合语言模型
扩展诗歌风格分类功能
开发基于n-gram的自动对联生成系统
基于N-gram模型的中文文本分析系统设计与实现由讯客互联手机栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“基于N-gram模型的中文文本分析系统设计与实现”
上一篇
SQL复习
下一篇
跟着李沐老师学习深度学习(十)