第1章 自然语言处理和深度学习概述
正如章节题目,本章更多是一些基础性的概述,介绍的部分库的一些功能比较有趣。
去除停用词,并分词
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
# 需要先nltk.download('punkt')和nltk.download('stopwords')
sent = 'deep learning for natural language processing is very interesting'
stop_words = set(stopwords.words('english'))
word_tokens = word_tokenize(sent)
filtered_sent = [w for w in word_tokens if w not in stop_words]
print(filtered_sent)
# ['deep', 'learning', 'natural', 'language', 'processing', 'interesting']
计数向量化,生成词向量的one-hot编码
from sklearn.feature_extraction.text import CountVectorizer
texts = ['Ramiess sing classic songs', 'he listens to old pop', 'and rock music']
cv = CountVectorizer()
cv_fit = cv.fit_transform(texts)
print(cv.get_feature_names())
# ['and', 'classic', 'he', 'listens', 'music', 'old', 'pop', 'ramiess', 'rock', 'sing', 'songs', 'to']
print(cv_fit.toarray())
# [[0 1 0 0 0 0 0 1 0 1 1 0]
# [0 0 1 1 0 1 1 0 0 0 0 1]
# [1 0 0 0 1 0 0 0 1 0 0 0]]
TF-IDF分数
TF-IDF(词频和反向文档频率,term frequency–inverse document frequency)是信息检索领域的常用指标,字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降,即如果某个词或短语在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。
t
f
−
i
d
f
i
=
t
f
i
,
j
⋅
i
d
f
i
tf-idf_i=tf_{i,j} \cdot idf_i
tf−idfi=tfi,j⋅idfi
t
f
i
,
j
=
n
i
,
j
∑
k
n
k
,
j
tf_{i,j}=\frac{n_{i,j}}{\sum_k n_{k,j}}
tfi,j=∑knk,jni,j
n
i
,
j
n_{i,j}
ni,j表示单词
i
i
i在文档
j
j
j中出现的次数
n
k
,
j
n_{k,j}
nk,j表示单词
k
k
k在文档
j
j
j中出现的次数
故,
t
f
i
,
j
tf_{i,j}
tfi,j计算的是单词
i
i
i在文档
j
j
j中的比例,即词频
i
d
f
i
=
l
g
∣
D
∣
∣
{
j
:
t
i
∈
d
j
}
∣
idf_i=lg\frac{\vert D \vert}{\vert \{j:t_i\in d_j\} \vert}
idfi=lg∣{j:ti∈dj}∣∣D∣
∣
D
∣
\vert D \vert
∣D∣表示语料库的文档总数
∣
{
j
:
t
i
∈
d
j
}
∣
\vert \{j:t_i\in d_j\} \vert
∣{j:ti∈dj}∣表示包含单词i的文档j的数量
故,两者相除再取以10为底的对数,即逆文档频率
举个例子:
假设一个文档包含100个单词,单词happy出现了5次,那么词频即为5/100=0.05,假设语料库共有1000万个文档,而单词happy出现在其中1000个文档中,那么逆文档频率为lg(10000000/1000)=4,故tf-idf=0.05×4=0.2
from sklearn.feature_extraction.text import TfidfVectorizer
texts = ['aaa bbb aaa', 'aaa ccc']
vert = TfidfVectorizer()
X = vert.fit_transform(texts)
print(X.todense())
#[[0.81818021 0.57496187 0. ]
# [0.57973867 0. 0.81480247]]
如果大家测试上面的代码,会发现和上面的公式的计算结果不同,这是因为在sklearn中采用的公式和上面不同,其使用的公式如下:
v
i
,
j
=
t
f
i
,
j
⋅
i
d
f
i
v_{i,j}=tf_{i,j} \cdot idf_i
vi,j=tfi,j⋅idfi
t
f
−
i
d
f
i
=
v
i
,
j
∑
k
v
k
,
j
2
tf-idf_i=\frac{v_{i,j}}{\sqrt {\sum_k v_{k,j}^2}}
tf−idfi=∑kvk,j2vi,j
分母上求了文档中所有单词的欧氏距离
t
f
i
,
j
=
n
i
,
j
tf_{i,j}=n_{i,j}
tfi,j=ni,j
即
t
f
tf
tf的值就是出现的次数
i
d
f
i
=
l
n
∣
D
∣
+
1
∣
{
j
:
t
i
∈
d
j
}
∣
+
1
+
1
idf_i=ln\frac{\vert D \vert +1} {\vert \{ j:t_i \in d_j\} \vert + 1}+1
idfi=ln∣{j:ti∈dj}∣+1∣D∣+1+1
使用是以e为底,公式上也有变化
但如果在代码中使用
v
e
r
t
=
T
f
i
d
V
e
c
t
o
r
i
z
e
r
(
s
m
o
o
t
h
i
d
f
=
F
a
l
s
e
)
vert=TfidVectorizer(smooth_idf=False)
vert=TfidVectorizer(smoothidf=False)
那么
i
d
f
i
=
l
n
∣
D
∣
+
1
∣
{
j
:
t
i
∈
d
j
}
∣
+
1
idf_i=ln\frac{\vert D \vert+1}{\vert \{ j:t_i \in d_j\}\vert + 1}
idfi=ln∣{j:ti∈dj}∣+1∣D∣+1
就不会在后面加1了,默认的是True,就是上面的加了1的公式
示例代码中的语料库为[‘aaa bbb aaa’, ‘aaa ccc’]
以第一个文档中的bbb为例,程序输出结果为0.57496187
因为在第一个文档中只出现了一次,所以
t
f
i
,
j
=
1
tf_{i,j}=1
tfi,j=1
语料库中的文档总数为2,出现了bbb的文档数为1,所以
i
d
f
i
=
l
n
3
2
+
1
=
1.4054651081081644
idf_i=ln\frac{3}{2}+1=1.4054651081081644
idfi=ln23+1=1.4054651081081644
所以bbb的
v
i
,
j
=
1
×
1.4054651081081644
=
1.4054651081081644
v_{i,j}=1 \times 1.4054651081081644=1.4054651081081644
vi,j=1×1.4054651081081644=1.4054651081081644
同理,计算得第一个文档中的aaa的
v
i
,
j
=
2
×
(
l
n
3
3
+
1
)
=
2
v_{i,j}=2\times (ln\frac{3}{3} + 1)=2
vi,j=2×(ln33+1)=2
所以bbb的
t
f
−
i
d
f
i
=
1.4054651081081644
1.405465108108164
4
2
+
2
2
=
0.5749618667993135
tf-idf_i=\frac{1.4054651081081644}{\sqrt{1.4054651081081644^2+2^2}}=0.5749618667993135
tf−idfi=1.40546510810816442+221.4054651081081644=0.5749618667993135
Keras构建MIP模型的小例子
本例子所用的输血数据集见本文的下载链接
数据集一共有748条数据和4个属性
- Recency, months since last donation
- Frequency, total number of donation
- Monetary, total blood donated in c.c.
- Time, months since first donation
和一个二元属性用1或0表示该用户是否在2007年3月献血
首先对文件进行读取,并提取自变量和因变量
import keras
from keras.layers import Dense
from keras.models import Sequential
import numpy as np
# 根据具体的文件路径进行修改
trans = np.genfromtxt('D:\\py3\\book_dl_for_nlp\\transfusion.csv', delimiter=',', skip_header=1)
X = trans[:, 0:4]
Y = trans[:, 4]
下面,创建网络结构,第一层隐藏层由8个神经元组成,第二层隐藏层由6个神经元组成,均使用ReLU激活函数,输出层使用Sigmoid激活函数进行二元分类。
mlp_keras = Sequential()
mlp_keras.add(Dense(8, input_dim=4, kernel_initializer='uniform', activation='relu'))
mlp_keras.add(Dense(6, kernel_initializer='uniform', activation='relu'))
mlp_keras.add(Dense(1, kernel_initializer='uniform', activation='sigmoid'))
设置学习参数,并输出结果
mlp_keras.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
mlp_keras.fit(X, Y, epochs=200, batch_size=8, verbose=0)
accuracy = mlp_keras.evaluate(X, Y)
print('Accuracy:%0.2f%%' % (accuracy[1]*100))
整体代码如下
import keras
from keras.layers import Dense
from keras.models import Sequential
import numpy as np
#%%
trans = np.genfromtxt('D:\\py3\\book_dl_for_nlp\\transfusion.csv', delimiter=',', skip_header=1)
X = trans[:, 0:4]
Y = trans[:, 4]
#%%
mlp_keras = Sequential()
mlp_keras.add(Dense(8, input_dim=4, kernel_initializer='uniform', activation='relu'))
mlp_keras.add(Dense(6, kernel_initializer='uniform', activation='relu'))
mlp_keras.add(Dense(1, kernel_initializer='uniform', activation='sigmoid'))
#%%
mlp_keras.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
mlp_keras.fit(X, Y, epochs=200, batch_size=8, verbose=0)
accuracy = mlp_keras.evaluate(X, Y)
print('Accuracy:%0.2f%%' % (accuracy[1]*100))