自然语言处理(NLP)—— 语言检测器

 1. 文章概述

1.1 目的

        在本篇文章中,我们将构建一个语言检测器,这是一个能够识别文本语言的简单分类器。这是一个能够识别文本是用哪种语言写的程序。想象一下,你给这个程序一段文字,它就能告诉你这是英语、法语还是其他语言。

1.2 方法

        遵循频率主义者的方法,我们从零开始,几乎不假设任何关于语言的先验知识,甚至不假设单词或标记的存在。我们仅考虑构成文本的符号——Unicode字符,以及它们出现的排列。我们使用的方法叫做“朴素贝叶斯分类”。它的工作方式是通过观察文本中字母或符号的组合(我们称之为“n-gram”),因为不同的语言中这些组合的出现频率是不同的。比如说,某些字母组合在法语中很常见,但在英语中可能就很罕见。为此,我们将简单地计算字符n-gram的频率。我们的假设是,字符n-gram的分布远非随机,并且每种语言都不同:它提供了一种语言的签名。我们将通过使用(甚至构建)一个简单的朴素贝叶斯分类器来测试这一假设。

1.3 示例

        如果我们有一段法文“ÉLÈVE ÈVE”,我们会注意到其中一些字母组合,比如“ÉLÈ”、“LÈV”、“ÈVE”等出现的次数。我们的程序会用这些信息来判断文本的语言。例如,法文文本"ÉLÈVE ÈVE"将包含以下的三元组计数(‘_’表示空格):

        ÉLÈ: 1
        LÈV: 1
        ÈVE: 2
        VE_: 1
        E_È: 1
        _ÈV: 1

        三元组计数(trigram counting)是一种文本分析方法,用于统计和分析文本中每个连续的三个字符(或字母)出现的频率。这种方法把文本分成许多三个字符的组合(或称为“三元组”),然后计算每种组合在文本中出现的次数。三元组计数是自然语言处理(NLP)中常用的一种特征提取技术,尤其在语言识别、拼写检查和文本生成等任务中非常有用。

        举个例子,对于文本“hello”,其三元组及其计数如下:

        “hel”:1次
        “ell”:1次
        “llo”:1次

        通过对不同语言的文本进行三元组计数,我们可以得到这些语言字符组合的频率分布。由于每种语言都有其特定的字符组合习惯,这些频率分布可以作为识别语言的依据。在朴素贝叶斯分类器中,这些三元组的频率数据会被用来预测文本所属的语言,即通过分析文本中的三元组出现频率来判断这段文本最可能是哪种语言。

1.4 朴素贝叶斯分类

        朴素贝叶斯分类中的“朴素”意味着分类器将所有特征视为独立它认为遇到ÉLÈ与遇到LÈV是独立的,这在语言中显然不是这样,但它是构建简单模型的一个方便假设。“贝叶斯”则是指贝叶斯定理:


P(y|x) = \frac{P(x|y)P(y)}{P(x)}


        在我们的案例中,x = x_1, x_2, ..., x_n代表我们的n-gram观察值,y是一种语言。P(y|x)预测给定输入三元组x时,语言是y的概率。

        实际操作中,由于“朴素”属性,P(x|y)计算为P(x_1|y)...P(x_n|y)。另外,在分类时,我们省略计算分母P(x),因为它在各个类别中是常数(与y无关),因此不改变最终结果。我们的朴素贝叶斯分类器将简单地计算:
        每种语言的单独n-gram频率(例如P(x = EVE|y = French),ÈVE在法文、英文、印尼语等中出现的频率);
        训练语料库中法文、英文等n-gram的比例:P(y = French)

1.5 实现这个语言检测器的步骤

        a.收集数据:首先,我们需要不同语言的文本数据。这些文本包含了我们想要识别的语言。

        b.提取特征:然后,我们从这些文本中提取“n-gram”。比如,我们可以看每三个字母的组合出现了多少次。这些统计数据帮助我们理解每种语言的特点。

        c.训练分类器:有了这些数据后,我们就可以训练我们的程序了。训练就是让程序学习不同语言的n-gram频率模式。

        d.预测语言:一旦训练完成,我们就可以给程序任何一段文本,它会使用它学到的知识来告诉我们这段文本是什么语言。

        简而言之,我们的目标是创建一个能够通过查看文本中字母组合的频率来判断语言的程序。

2. 现在让我们开始实验吧!

2.1 准备阶段

        在这个练习中,你将使用Python进行编程。为了完成这个任务,你需要安装几个Python库,包括`numpy`、`scikit-learn`和(可选的)`nltk`。这些库可以通过以下命令安装:

pip install numpy

        安装numpy,一个用于科学计算的库,支持大量的维度数组和矩阵运算,此外还提供了大量的数学函数库。

pip install scikit-learn

        安装scikit-learn,一个用于机器学习的库。提供了许多不同的算法和工具来进行数据挖掘和数据分析。

pip install nltk

        安装nltk,自然语言处理工具包,用于处理人类语言数据的库。

这个练习将使用两个语料库:
        easy corpus包含10种语言,每种语言有10,000个训练句子和1,000个评估句子。
        challenging corpus包含75种语言,每种语言仅有900个训练句子和100个评估句子。

        第二个语料库更具挑战性,因为对于更多的目标类别(语言),训练数据要少得多。

        代码可在绑定资源里下载。

2.2 初步探索

        要进行这项初步探索,我们将编写一些简单的Python代码来分析语料库中的n-gram频率。这段代码将计算每种语言的唯一n-gram数量,并显示每种语言20个最常见的n-gram。n-gram的大小(数字n)将是代码中的一个可修改参数,这样你就可以用单个字符(unigrams)、两个字符(bigrams)、三个字符(trigrams)、四个字符(quadrigrams)等来试验。

        首先,我将展示一个简化的代码示例,用于计算和显示n-gram的频率。这个例子将使用Python标准库来处理文本,而不是`nltk`,这样我们可以更清楚地看到底层逻辑。然后,我会展示如何使用`nltk`的`FreqDist`类来完成同样的任务。

2.2.1 使用Python标准库

        我们将从基本的文本处理开始,提取n-gram并计算它们的频率。

def generate_ngrams(text, n=2):
    ngrams = [text[i:i+n] for i in range(len(text)-n+1)]
    return ngrams

def ngram_frequencies(texts, n=2):
    from collections import Counter
    ngrams_all = []
    for text in texts:
        ngrams = generate_ngrams(text, n)
        ngrams_all.extend(ngrams)
    return Counter(ngrams_all)

        假设texts是一个包含多种语言文本的字典,其中键是语言名称,值是该语言的文本列表

        示例: texts = {'English': ['This is a sentence.', ...], 'French': ['Ceci est une phrase.', ...]}

        下面是如何使用这个函数并打印每种语言20个最常见的n-gram

n = 3  # 你可以修改这个参数来探索不同的n-gram大小
for language, text_list in texts.items():
    fdist = ngram_frequencies(text_list, n)
    print(f"{language} - Top 20 n-grams: {fdist.most_common(20)}")

2.2.2 使用`nltk`的`FreqDist`

        如果你选择使用`nltk`,代码会更简洁,因为`FreqDist`类已经为我们处理了频率计算。

import nltk
from nltk.probability import FreqDist

def ngram_frequencies_nltk(texts, n=2):
    ngrams_all = []
    for text in texts:
        ngrams = nltk.ngrams(text, n)
        ngrams_all.extend(ngrams)
    return FreqDist(ngrams_all)

# 使用nltk的FreqDist
for language, text_list in texts.items():
    texts_combined = " ".join(text_list)  # 将所有文本合并为一个长字符串
    fdist = ngram_frequencies_nltk(texts_combined, n)
    print(f"{language} - Top 20 n-grams: {fdist.most_common(20)}")

        这两种方法都可以用来探索n-gram的频率分布。

        n-gram数量随n的增加而指数增长,因为组合的可能性会大大增加。

        比较不同语言最常见的n-gram可以揭示语言之间的相似性和差异性。

        对于一些特定的n-gram,它们可能在多种语言中都很常见,而其他一些则可能是某特定语言特有的,这些差异对于构建语言检测模型特别有用。

2.2.3 最终代码

        计算每种语言的唯一n-gram数量,并显示每种语言20个最常见的n-gram。

2.3 基于 Scikit 的分类

        Scikit 为我们做了一切。它的 CountVectorizer 类提取 n-grams 并计算其出现次数。

        出现的次数。MultinomialNB 类则根据 n-gram 计数计算似然值,用于训练、和语言类别概率进行预测。

  1. 查看 langdetect_scikit.py 的源代码。
  2. 在 "easy "语料库上运行 langdetect_scikit.py,n-gram 的大小从 1 开始依次增加。记下结果。理想的 n-gram 大小是多少?
  3. 注意 CountVectorizer 的参数。如果去掉重音(设置为 "unicode"),结果会怎样?(设置为 "unicode")?如果我们将文本转换为小写?
  4. 您还可以尝试去掉标点符号和数字:这有帮助吗?
  5. 在 "具有挑战性 "的语料库上也做几次测试,然后比较结果。

3. 布朗语料库的某些方面

3.1 先决条件

        要在没有 root 用户的情况下安装 NLTK,您可以编写以下命令

pip install nltk --user

        然后,为了加载我们需要的语料库,我们将以交互模式启动 Python,并写下

python
>>> import nltk
>>> nltk.download()

        在打开的窗口中,如果没有配额问题,在 "Collections "中选择 "All",或者选择 "Book",然后点击 "Donwload"。完成操作后,按 Ctrl-D 键退出交互模式。
将使用以下模块:

import nltk
from nltk.corpus import brown
from nltk.probability import FreqDist
import re

        您可以使用

brown.tagged_words()

        方法获取布朗语料库中的所有单词及其 POS 标记元组。

NLTK :: Installing NLTK Data

        您可以从 nltk 网页上https://www.nltk.org/book/ch02.html获取更多有关通过常规方法访问语料库的信息。

3.2 问题和答案

        a) 在布朗的语料库中,哪些名词的复数比单数更常见?复数

        认为复数只需加上一个 "s "即可构成)。按复数形式的出现频率和复数/单数形式的出现频率对前 20 个结果进行分类。
        按复数形式的频率和复数/单数的比例对前 20 个结果进行分类。

        b) 哪个单词有最多的不同标记?它们代表什么?

        c) 按频率降序列出标签(前 20 个)。它们代表什么?

        d) 名词前面最常见的标记是什么?它们代表什么?

4 标记器评估

4.1 基于 POS 的 POS 标记

        在本节中,我们将创建标记符(默认标记符为 nltk.DefaultTagger,the n-grams tagger, nltk.NgramTagger),并使用布朗语料库中的新闻类别对它们进行训练。

        我们将使用布朗语料库中的新闻类别对它们进行训练。

        进行十倍交叉验证。

        使用简化标签集评估相同的标记符。

4.2 基于内在属性的给定名称性别标签

        在本节中,我们将使用模块

import nltk
from nltk.corpus import names
import random
import collections

        姓名语料库由两个文件组成:female.txt 和 male.txt。创建一个元组列表(给定名称、性别)的随机顺序。统计上位混合名。
        在上一节中,我们使用了单词和标签。在这里,我们将采用一种更通用的方法:我们将定义属性,并评估这些属性对分类任务的贡献(在我们的案例中:给定姓名的性别)。在我们的例子中:给定名字的性别)的贡献。第一个候选属性:最后一个字母。

def gender_features(word):
    return {'last_letter': word[-1]}
featuresets = [(gender_features(n), g) for (n,g) in names]
train_set, test_set = featuresets[500:], featuresets[:500]
classifier = nltk.NaiveBayesClassifier.train(train_set)
print(nltk.classify.accuracy(classifier, test_set))

        我们得到的就是准确率。同时计算每个性别的精确度、召回率和 F-measure(使用
使用 nltk.metrics 的同名方法,注意:要使用这些方法,您必须将给定名字的数量收集到列表中。
注意:要使用这些方法,您必须根据排名和真实性别收集列表中给定名字的数量)。我们发现了什么?
        使用 classify 的 show_most_informative_features(10) 方法,我们可以找出
属性的值。
        要想尝试新的属性,可以编写代码来显示所有分类错误的代码,并为每个错误显示正确的类别、错误的类别和名称。

        测试其他属性及其组合。

5. 使用NLTK进行名字性别分类

        在本章中,我们将使用Python的Natural Language Toolkit(NLTK)库来分析和分类名字的性别,基于名字的内在属性。我们将通过几个步骤来完成这个任务:

5.1 导入模块和数据

        首先,我们需要导入所需的模块,并从NLTK的名字语料库中加载男性和女性的名字。这些名字将被存储在两个分别包含男性和女性名字的文件中。

import nltk
from nltk.corpus import names
import random
import collections

# 确保已下载名字数据集
nltk.download('names')

# 加载男性和女性的名字
male_names = names.words('male.txt')
female_names = names.words('female.txt')

5.2 创建名字和性别的元组列表

        接着,我们将这些名字和对应的性别标签('male' 或 'female')组合成元组,然后将这些元组随机排序,以便后续的数据分割和分析。

# 创建名字和性别的元组列表,并随机排序
names = [(name, 'male') for name in male_names] + [(name, 'female') for name in female_names]
random.shuffle(names)

5.3 定义特征提取函数

        为了分类任务,我们定义一个函数 `gender_features`,该函数基于名字的内在属性来提取特征。在这个例子中,我们使用的第一个属性是名字的最后一个字母。

# 定义特征提取函数
def gender_features(word):
    return {'last_letter': word[-1]}

5.4 创建特征集

        使用 `gender_features` 函数,我们为每个名字提取特征,并将这些特征与相应的性别标签组合成特征集。

# 创建特征集
featuresets = [(gender_features(n), g) for (n, g) in names]

5.5 分割数据集

        我们将特征集分为训练集和测试集,用于训练和评估模型。

# 分割数据集
train_set, test_set = featuresets[500:], featuresets[:500]

5.6 训练分类器

        使用训练集,我们训练一个Naive Bayes分类器。

# 训练分类器
classifier = nltk.NaiveBayesClassifier.train(train_set)

5.7 评估分类器

        评估分类器在测试集上的准确性,并计算精确度(precision)、召回率(recall)和F-度量(F-measure)等性能指标。

# 计算并打印分类器的准确性
accuracy = nltk.classify.accuracy(classifier, test_set)
print(f'Accuracy: {accuracy:.2f}')

# 收集预测和真实的性别标签
test_truth = [label for (features, label) in test_set]
test_pred = [classifier.classify(features) for (features, label) in test_set]

# 计算精确度、召回率和F-度量
def get_metrics(truth, pred, label):
    tp = sum(1 for t, p in zip(truth, pred) if t == label and p == label)
    fp = sum(1 for t, p in zip(truth, pred) if t != label and p == label)
    fn = sum(1 for t, p in zip(truth, pred) if t == label and p != label)
    precision_val = tp / (tp + fp) if tp + fp > 0 else 0
    recall_val = tp / (tp + fn) if tp + fn > 0 else 0
    f_measure_val = 2 * precision_val * recall_val / (precision_val + recall_val) if precision_val + recall_val > 0 else 0
    return precision_val, recall_val, f_measure_val

precision_male, recall_male, f_measure_male = get_metrics(test_truth, test_pred, 'male')
precision_female, recall_female, f_measure_female = get_metrics(test_truth, test_pred, 'female')

print(f"Precision (male): {precision_male:.2f}")
print(f"Recall (male): {recall_male:.2f}")
print(f"F-measure (male): {f_measure_male:.2f}")

print(f"Precision (female): {precision_female:.2f}")
print(f"Recall (female): {recall_female:.2f}")
print(f"F-measure (female): {f_measure_female:.2f}")

5.8 显示最有信息量的特征

        通过 `show_most_informative_features` 方法,我们可以了解哪些属性对于性别分类最有判别力。

# 显示最有信息量的特征
classifier.show_most_informative_features(10)

5.9. 分析分类错误

        编写代码来展示分类错误,为每个错误提供正确的类别、错误选择的类别和名字。

# 分析分类错误
errors = []
for (name, tag) in names[:500]:
    guess = classifier.classify(gender_features(name))
    if guess != tag:
        errors.append((tag, guess, name))

print("Errors:")
for (tag, guess, name) in sorted(errors):
    print(f"correct={tag} guess={guess} name={name}")

5.10 测试其他属性和它们的组合

        探索除了名字的最后一个字母之外的其他属性,以及它们对分类任务的影响。

# 测试其他特征
def gender_features_extended(word):
    return {
        'last_letter': word[-1],
        'first_letter': word[0],
        'length': len(word),
        'last_two': word[-2:]
    }

# 创建扩展特征集
extended_featuresets = [(gender_features_extended(n), g) for (n, g) in names]
train_set_extended, test_set_extended = extended_featuresets[500:], extended_featuresets[:500]

# 训练扩展特征集上的分类器
classifier_extended = nltk.NaiveBayesClassifier.train(train_set_extended)

# 计算并打印扩展特征集分类器的准确性
accuracy_extended = nltk.classify.accuracy(classifier_extended, test_set_extended)
print(f'Extended Features Accuracy: {accuracy_extended:.2f}')

# 显示扩展特征集上最有信息量的特征
classifier_extended.show_most_informative_features(10)

5.11 总结

        通过这些步骤,我们能够使用NLTK库构建一个简单但有效的名字性别分类器。我们从名字的最后一个字母开始提取特征,逐步扩展到包括更多的属性,并对分类器进行了训练和评估。通过这种方式,我们不仅实现了名字性别的分类,还探索了不同特征组合对分类性能的影响。这为进一步优化分类模型提供了基础,也展示了NLTK在自然语言处理任务中的强大功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/688774.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux 35.5 + JetPack v5.1.3@FC-Planner编译安装

Linux 35.5 JetPack v5.1.3FC-Planner编译安装 1. 源由2. 编译&安装Step 1:依赖库安装Step 2:克隆工程Step 3:编译工程Step 4:LKH编译Step 5:安装工程 3. 问题汇总3.1 swarm_exploration/plan_env - OpenCV3.2 程…

天才简史——Tamim Asfour与他的H²T实验室

一、Tamim Asfour介绍 Tamim Asfour为KIT人类学和机器人学研究所(Institute for Anthropomatics and Robotics)的全职教授,并担任高性能人形技术实验室 (High Performance Humanoid Technologies Lab,HT) 负责人。他目前的研究兴…

【算法专题--栈】最小栈--高频面试题(图文详解,小白一看就会!!)

目录 一、前言 二、题目描述 三、解题方法 ⭐解题方法--1 ⭐解题方法--2 四、总结 五、共勉 一、前言 最小栈这道题,可以说是--栈专题--,比较经典的一道题,也是在面试中频率较高的一道题目,通常在面试中,面试官可…

码蹄集部分题目(2024OJ赛18期;并查集+ST表+贪心)

1🐋🐋史莱姆融合(钻石;并查集) 时间限制:1秒 占用内存:128M 🐟题目描述 🐟题目思路 这道题目使用并查集,同一集合的所有元素的最顶上的祖父节点是统一的。…

SAP ABAP 创建表结构 SE11

目录 一,创建表 :T-code:SE11 二,编辑内容: 1,内容说明:必填项,属性:锁定不可更改 2,出荷と更新 3,項目 A:表的第一个项目必须是…

编写程序提示用户输入一个数目(例如:100)、年利率(例如:5)以及月份数(例如:6),然后显示给定月份后账户上的钱数。

(财务应用程序:复利值)假设你每月向银行账户存 100美元,年利率为5%,那么每 月利率是 0.05/12-0.00417。 第一个月之后,账户上的值就变成:100*(10.00417)100.417 第二个月之后,账户上的值就变成(100100.417)*(10.00417)-201.252 第…

【Python报错】已解决ImportError: cannot import name ‘xxx‘

成功解决“ImportError: cannot import name ‘xxx’”错误的全面指南 一、引言 在Python编程中,ImportError是一种常见的异常类型,它通常表明Python解释器在尝试导入某个模块或模块中的某个成员时遇到了问题。当看到错误消息“ImportError: cannot imp…

解密智慧校园解决方案:赋能数字化教育的未来

在当今数字化时代,智慧校园解决方案正以惊人的速度改变着教育界的面貌。随着科技的快速发展,数字化教育已经逐渐成为现代教育的核心。智慧校园解决方案作为一个集技术、教育和创新于一体的综合性项目,为学校提供了许多机遇和挑战。本文将揭示…

嵌入式Linux系统中RTC应用的操作详解

第一:RTC的作用以及时间简介 “RTC”的英文全称是Reul-Time Clock,翻译过来是实时时钟芯片.实时时钟芯片是日常生活中应用最为广泛的电子器件之一,它为人们或者电子系统提供精确的实时时间,实时时钟芯片通过引脚对外提供时间读写接口,通常内部带有电池,保证在外部系统关…

width: 100%和 width: 100vw这两种写法有什么区别

width: 100%; 和 width: 100vw; 是两种不同的 CSS 写法,它们在实际应用中会有不同的效果。以下是这两种写法的主要区别: width: 100%; 定义:将元素的宽度设置为其包含块(通常是父元素)宽度的 100%。效果:元…

Maven核心功能依赖和构建管理

1.依赖管理和配置 Maven 依赖管理是 Maven 软件中最重要的功能之一。Maven 的依赖管理能够帮助开发人员自动解决软件包依赖问题,使得开发人员能够轻松地将其他开发人员开发的模块或第三方框架集成到自己的应用程序或模块中,避免出现版本冲突和依赖缺失等…

springboot停车微信小程序小程序-计算机毕业设计源码92714

摘 要 在信息飞速发展的今天,网络已成为人们重要的信息交流平台。每天都有大量的农产品需要通过网络发布,为此,本人开发了一个基于springboot停车微信小程序小程序。 对于本停车微信小程序的设计来说,它主要是采用后台采用java语…

Android Webview 详解

一 简介 一个基于webkit引擎、展现web页面的控件 Android 4.4前:Android Webview在低版本 & 高版本采用了不同的webkit版本的内核Android 4.4后:直接使用了Chrome内核 1.1 作用 在 Android 客户端上加载h5页面在本地 与 h5页面实现交互 & …

关于RDMA传输的基本流量控制

Basic flow control for RDMA transfers | The Geek in the Corner (wordpress.com) 文心一言 已经介绍了使用发送/接收操作和RDMA读写操作,那么现在是一个很好的机会来结合这两种方法的元素,并讨论一般的流量控制。还会稍微谈谈RDMA带有立即数据的写操…

《机器学习特征提取》

书籍:Building Feature Extraction with Machine Learning: Geospatial Applications 作者:Bharath.H. Aithal,Prakash P.S. 出版:CRC Press 书籍下载-《机器学习特征提取》这是一本面向专业人士和研究生的实用指南&#xff0c…

uniapp uni-popup内容被隐藏问题

今天开发新需求的时候发现uni-popup 过一会就被隐藏掉只留下遮罩(css被更改了),作者进行了如下调试。 1.讲uni-popup放入其他节点内 失败! 2.在生成dom后在打开 失败! 3.uni-popup将该节点在包裹一层 然后将统计设置样式,v-if v-s…

selenium中, quit 和close的区别

close时 """ close和quit的区别 close关闭当前页 (只是关闭了当前) quit离开整个浏览器 (走远了) """ from selenium import webdriver import time# 创建浏览器驱动对象 from selenium.webdriver.co…

抢人!抢人!抢人! IT行业某岗位已经开始抢人了!

所谓抢滩鸿蒙,人才先行。鸿蒙系统火力全开后,抢人已成鸿蒙市场的主题词! 智联招聘数据显示,春节后首周,鸿蒙相关职位数同比增长163%,是去年同期的2.6倍,2023年9-12月鸿蒙相关职位数同比增速为3…

深入理解C++多线程系列——线程基础

概念 在现代计算机中,多线程编程是一种强大的并发执行计数,允许多个线程在单个程序内部并行执行,提高程序的执行效率和响应速度。线程,作为CPU调度的最小单元,它被用来执行程序中的指令。一个线程是进程中的一个单一顺…

跨境电商测评自养号需要解决哪些问题?

现在做测评工作室这块的,真正有技术的每天单都做不过来,同样也滋生出很多找别人买个设备和账号就以为自己懂了,直接开始教学来割韭菜,很多人没接触过这行业,不知道里面的水很深,花了钱,却没有掌…