個々の公共の番号でこの記事の発信元:TechFlow
我々は導入前の記事ナイーブベイズモデルの基本原則を。
ナイーブベイズコアエッセンスサンプル変数間ことを仮定することである分布に従うので、条件付き確率計算された確率のサンプルを使用することは、カテゴリに属します。通常、サンプルは、多くの場合、それはおそらく、これらの特性との間に相関関係があるされ、多くの機能が含まれています。モデルを単純化するために、ナイーブベイズモデルでは、これらの変数が独立であると仮定しました。だから我々は単にサンプルの確率を計算することができること。
学生はあなたが前に戻って記事のリンクをクリックすることができ、詳細を確認したいです:
機械学習の基礎 - あなた文学ナイーブベイズモデルになります
あなたが原則と理論モデルを見れば私たちの学習アルゴリズムの過程で、いくつかの紙がZhongjue感が来る常にあります。多くの場合、明確かつ論理的に言って、本当に力がまだ無知になりますとき始めたい理由。それとも実際に従事してやっとですが、プロセスは常にそれらに片道または予期しない問題の他、さまざまなを実行します。我々は十分なハンズオンではない一方で、他の一方で理解するための深い十分ではありません。
この記事では、今日、私たちは実践的な実装モデルとされている実際のデータセット、それらを実行し、我々のモデルの業績を見て。
ナイーブベイズテキスト分類
一般的に、我々は、と信じているイベント狭い結果は、制限すべきイベントの結果があるべきであることを意味する離散値を連続値ではなく。ベイズモデルはとても早く、イデオロギーガウス混合モデルが、またのための離散サンプル値の導入前(疑わしい、私は推測)。それでは、脇連続機能のシーンを入れてナイーブベイズモデルどのような実用的なアプリケーション間の離散サンプルを見てみましょう。
機械学習のシナリオの広い範囲では、その中で、非常に古典的なシナリオは、それは離散サンプルである必要があり、それは、自然言語処理(自然言語処理)。言語では、それはステートメントまたはテキストの一部であるかどうかをどの言語に関係なくは、その最小単位は、単語や単語のどちらかです。これらのユニットである離散ので、自然とナイーブベイズモデルが非常にフィットしています。
私たちはシーンモデルを行う。この時間があるスパムを識別し、これが私たちの日常生活は、多くの場合、接触機能に来るべきです。今すぐメールボックスの基本的認識スパムは、スパムであることが判明した場合、多くの場合、直接ではないユーザーに、シールド。初期のスパムやスパムメッセージが実現される機能ナイーブベイズによって識別されます。
この実験では、使用UCIのデータセットを。UCI機械学習データセットの大学は非常によく、多くの教材や教科書を例として、自社のデータセットで使用されている、知られています。私たちは、ウェブを介して直接自分のデータをダウンロードすることができ、データ内のUCIデータセットは無料です。
ダウンロードが完了したら、のは、それらのいくつかの選択を見てみましょう:
唯一のブギスnは偉大な世界ラ・電子ビュッフェで利用可能ジュロン・ポイントまでのハムゴー、クレイジー... ...シネアモーレ・ワットがそこに着きました...
ハム[OK]をLAR ...冗談WIF uの鬼...
2のスパム無料エントリーエントリー質問(率TXT STD)T&Cの適用08452810075over18さんを受けるために87121にFAカップ決勝TKTSの5月21日、2005年のテキストFAを獲得するwklyコンプ
ハムU焦げ茶色はそんなに早くHORを言う... U C、既にその後、言います...
データは、ファイル・タイプTXT保存され、通常のハムを示すテキストの種類を示すテキストの各行の最初の単語は、スパム表現はスパムです。
私たちは、まず、第1の間でファイルリストの内容は、私たちのフォローアップ治療を容易にするため、それらを読み取るために、ファイルを読み込みます。
def read_file(filename):
file = open(filename, 'r')
content = []
for line in file.readlines():
content.append(line)
return content
私たちは、最初の3つのデータを見てみましょう。
\ T(タブ)でカテゴリとテキストの間の分離見つけることができ、我々は、Pythonのクラスやメソッドを分割することができます直接テキストから分離します。私たちはラベルに教師付き学習と呼ばれるモデルの結果を学びたいものをどのカテゴリです。テキストと呼ばれる機能に基づいて予測を行うためにもモデルの一部です。間でテキスト分類シーンで機能テキスト情報です。
私たちは、ラベルとテキストを区切ります:
labels = []
data = []
for i in smsTxt:
row = i.split('\t')
if len(row) == 2:
labels.append(row[0])
data.append(row[1])
フィルタの句読点
テキストとラベルを分離した後、我々はテキストに対処する必要があります。プロセスを行う前に、ちょうど、我々が最初にここで選択したデータを見てみましょう:
「ゴージュロンポイント、までクレイジー...のみ・ラ・電子ビュッフェブギスnは偉大な世界で利用可能な...シネそこに着いたアモーレ・ワット... \ n」は
これは非常に典型的な未処理の前に、だけでなく、混合大文字と小文字、およびいくつかの特殊記号の中のテキストです。だから、最初のステップは、すべて小文字、句読点、および削除を処理するすべてのテキストを置くことです。
より複雑言えば、しかし長い正規表現の使用などとして、我々は簡単に達成することができます:
import re
# 只保留英文字母和数字
rule = re.compile("[^a-zA-Z\d ]")
for i in range(len(data)):
data[i] = re.sub("[^a-zA-Z\d ]", '', data[i].lower())
次のように最後に、得られた結果は以下のとおりです。
唯一のブギスnは偉大な世界で利用可能なジュロン・ポイントクレイジー・ラ・アモーレワットそこに着いたシネビュッフェEまで行きます
ここでは、正規表現は非常に単純で、文字と数字のみ、スペース、すべてのフィルタの内容のすべての残りの部分を維持することです。私たちは、それが小文字にすべて大文字に変わります、ケースの変換を行うための時間を可決しました。この時点まで、すべての特殊文字は、あなたが単語ことができ、処分されているでしょう。
英語の単語は非常に簡単で、私たちは宇宙から直接分割することができます。中国語の単語ならば、あなたはいくつかのサードパーティのライブラリを使用することができ、完成前の記事で紹介され、我々はここに入りません。
インストールNLTK
次のテキスト処理の中で、私たちは、自然言語処理NLTKのライブラリーと呼ばれるツールを使用する必要があります。これは、私たちが直接インストールするPIPを使用する前に、非常に便利なNLPツール、ライブラリ、およびツールの数を統合します。
pip3 install nltk
Python2はもはや維持のでここで強く、のpython3お勧めします。このステップの終了後、ちょうどNLTKライブラリ、我々はファイルをダウンロードする必要があり、他の多くのリソースがあるNLTKを設置。私たちは、Pythonから直接ダウンロードすることができます。
import nltk
nltk.download()
ダウンロードウィンドウのためにこのコードを呼び出した後にポップアップ表示されます:
我々は、すべてを選択してダウンロードする]をクリックしますが、国内の直接ダウンロードの外国人の国でこのデータソースは、遅くなることがあります。インターネット曲線に加えて、他の方法は、githubの中の対応するデータリソースから直接ダウンロードすることができる。https://github.com/nltk/nltk_data
あなたが指定した場所にデータを置く必要があることに注意、特定の設置場所は、それが赤いボックスのパスを表示した後メソッドをダウンロード呼び出すことができます。または清華ミラーのソースを使用することができる、次のコマンドを使用します。
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple/nltk
ダウンロードはそれでは、私たちはPythonでそれらを実行します。
fron nltk.book import *
次のような結果が表示された場合、それはインストールが完了したことを示しています。
ストップワードを削除します
インストールNLTKたら、まず私たちが行う必要がある前のストップワードを削除することです。
英語のストップワードは、テキストがセマンティック語彙問題ではないことを意味し、ストップワード、です。言葉、補助剤、前置詞などの一般的な機能が含まれています。これらの言葉のほとんどは、単純に決定的な役割を達成することはありません、テキストの意味内容に影響を変更しています。したがってNLPの技術の中でも、精度を高めるために計算モデルを減らすためにフィルタリングすることができます。
(中国は含まない)ストップリストを提供NLTKは、私たちが指定した言語に合格し、ストップワードのリストを返します。一般的な主流の言語です。私たちは、言葉の後によると、ストップリストをフィルタリングすることができます。
私たちは、分類、テキストほとんど助けに私たちのために、それらのすべての状況で発生する可能性があり、それらのほとんどが空の単語やパーティクルあり、見に英語ですべてのストップワードをプリントアウトすることができます。
POSの正規化
众所周知,英文当中的单词有很多形态。比如名词有单复数形式,有些特殊的名词复数形式还很不一样。动词有过去、现在以及未来三种时态,再加上完成时和第三人称一般时等,又有很多变化。
举例来说,do这个动词在文本当中会衍生出许多小词来。比如does, did, done, doing等,这些单词虽然各不相同,但是表示的意思完全一样。因此,在做英文NLP模型的时候,需要将这些时态的单词都还原成最基本的时态,这被称为是词性归一化。
原本这是一项非常复杂的工作,但我们有了nltk之后,这个工作变得简单了很多。要做单词归一化,我们需要用到nltk当中的两个工具。
第一个方法叫做pos_tag, 它接收一个单词的list作为入参。返回也是一个tuple的list,每个tuple当中包含两个值,一个是单词本身,第二个参数就是我们想要的词性。
举个例子:
我们传入只有一个单词apple的list,在返回的结果当中除了apple之外,还多了一个NN,它表示apple是一个名词nouns。
关于返回的词性解释,感兴趣的可以自行查看官方文档的说明。
我们这里并不需要区分那么细,只需要区分最常用的动词、名词、形容词、副词就基本上够了。
我们可以直接根据返回结果的首字母做个简单的映射:
from nltk import word_tokenize, pos_tag
from nltk.corpus import wordnet
from nltk.stem import WordNetLemmatizer
# 获取单词的词性
def get_wordnet_pos(tag):
if tag.startswith('J'):
return wordnet.ADJ
elif tag.startswith('V'):
return wordnet.VERB
elif tag.startswith('N'):
return wordnet.NOUN
elif tag.startswith('R'):
return wordnet.ADV
else:
return None
通过pos_tag方法我们很容易就可以拿到单词的词性,但是这还不够,我们还需要将它还原成最基础的形态。这个时候需要用到另一个工具:WordNetLemmatizer
它的用途是根据单词以及单词的词性返回单词最一般的形态,也就是归一化的操作。
举个例子:
我们传入了box的复数形式:boxes,以及box对应的名词,它返回的结果正是我们想要的box。
我们结合刚刚实现的查询单词词性的方法,就可以完成单词的归一化了。
到这里为止,关于文本的初始化就算是差不多结束了。除了刚刚提到的内容之外,nltk还包含许多其他非常方便好用的工具库。由于篇幅的限制,我们不能一一穷尽,感兴趣的同学可以自行钻研。
下面,我们把刚才介绍的几种文本预处理的方法一起用上,对所有的短信进行预处理:
for i in range(len(data)):
data[i] = re.sub("[^a-zA-Z ]", '', data[i].lower())
tokens = data[i].split(' ') # 分词
tagged_sent = pos_tag([i for i in tokens if i and not i in stopwords.words('english')]) # 获取单词词性
wnl = WordNetLemmatizer()
lemmas_sent = []
for tag in tagged_sent:
wordnet_pos = get_wordnet_pos(tag[1]) or wordnet.NOUN
lemmas_sent.append(wnl.lemmatize(tag[0], pos=wordnet_pos))
data[i] = lemmas_sent
通过nltk的工具库,我们只需要几行代码,就可以完成文本的分词、停用词的过滤以及词性的归一化等工作。
接下来,我们就可以进行朴素贝叶斯的模型的训练与预测了。
首先,我们需要求出背景概率。所谓的背景概率,也就是指在不考虑任何特征的情况下,这份样本中信息当中天然的垃圾邮件的概率。
这个其实很简单,我们只需要分别其实正常的邮件与垃圾邮件的数量然后分别除以总数即可:
def base_prob(labels):
pos, neg = 0.0, 0.0
for i in labels:
if i == 'ham':
neg += 1
else:
pos += 1
return pos / (pos + neg), neg / (pos + neg)
我们run一下测试一下结果:
可以看到垃圾邮件的概率只占13%,大部分邮件都是正常的。这也符合我们的生活经验,毕竟垃圾邮件是少数。
接下来我们需要求出每个单词属于各个类别的概率,也就是要求一个单词的概率表。这段代码稍微复杂一些,但是也不麻烦:
def word_prob(data, labels):
n = len(data)
# 创建词表
word_dict = {}
for i in range(n):
lab = labels[i]
# 先转set再转list,去除重复的常规操作
dat = list(set(data[i]))
for word in dat:
# 单词不在dict中的时候创建dict,默认从1开始计数,为了防止除0
if word not in word_dict:
word_dict[word] = {'ham' : 1, 'spam': 1} # 拉普帕斯平滑避免除0
word_dict[word][lab] += 1
# 将数量转化成概率
for i in word_dict:
dt = word_dict[i]
ham = dt['ham']
spam = dt['spam']
word_dict[i]['ham'] = ham / float(ham + spam)
word_dict[i]['spam'] = spam / float(ham + spam)
return word_dict
同样,我们运行一下测试一下结果:
这些都有了之后,就是预测的重头戏了。这里有一点需要注意,根据我们上文当中的公式,我们在预测文本的概率的时候,会用到多个概率的连乘。由于浮点数有精度限制,所以我们不能直接计算乘积,而是要将它转化成对数相加,这样我们就可以通过加法来代替乘法,就可以避免连乘带来的精度问题了。
import math
def predict(samples, word_prob, base_p, base_n):
ret = []
for sam in samples:
neg = math.log(base_n)
pos = math.log(base_p)
for word in sam:
if word not in word_prob:
continue
neg += math.log(word_prob[word]['spam'])
pos += math.log(word_prob[word]['ham'])
ret.append('ham' if pos > neg else 'spam')
return ret
预测的方法也非常简单,我们分别计算出一个文本属于spam以及ham的概率,然后选择概率较大的那个作为最终的结果即可。
我们将原始数据分隔成训练集以及预测集,调用我们刚刚编写的算法获取预测的结果:
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(data, labels, test_size=0.25)
base_p, base_n = base_prob(y_train)
word_dt = word_prob(x_train, y_train)
ret = predict(x_test, word_dt, base_p, base_n)
最后,我们调用一下sklearn当中的classification_report方法来获取贝叶斯模型的预测效果:
从上图当中看,贝叶斯模型的预测效果还是不错的。对于垃圾文本识别的准确率有90%,可惜的是召回率低了一点,说明有一些比较模糊的垃圾文本没有识别出来。这也是目前这个场景下问题的难点之一,但总的来说,贝叶斯模型的原理虽然简单,但是效果不错,也正因此,时至今日,它依旧还在发挥着用处。
NLP是当今机器学习领域非常复杂和困难的应用场景之一,关于文本的预处理以及模型的选择和优化都存在着大量的操作。本文当中列举的只是其中最简单也是最常用的部分。
到这里,关于朴素贝叶斯的实践就结束了。我想亲手从零开始写出一个可以用的模型,一定是一件非常让人兴奋的事情。但关于朴素贝叶斯模型其实还没有结束,它仍然有许多细节等待着大家去思考,也有很多引申的知识。模型虽然简单,但仍然值得我们用心地体会。
今天的文章就到这里,扫码关注我的公众号,查看更多文章,你们的支持是我最大的动力。