机器学习实战-KNN

KNN
k-近邻算法(knn)是机器学习分类算法中最简单而且相当高效的算法,它的主要思想就是,选择与测试样本最相似的前K个训练样本,其中同一标签个数最多的标签就是测试样本的结果。一般来说,我们只选择样本数据集中前K个最相似的数据,这就是knn算法中k的出处,通常k是不大于20的整数。
下面我们使用Python语言实现简单的knn分类算法(按照《机器学习实战》),代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
from numpy import *
import operator

def createDataSet():
group = array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]])
labels = ['A', 'A', 'B', 'B']
return group, labels

def classify0(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0]
diffMat = tile(inX, (dataSetSize, 1)) - dataSet
sqDiffMat = diffMat ** 2
sqDistances = sqDiffMat.sum(axis = 1)
distances = sqDistances ** 0.5
sortedDistIndicies = distances.argsort()
classCount = {}
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
sortedClassCount = sorted(classCount.iteritems()\
, key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]

def file2matrix(filename):
fr = open(filename)
arrayOLines = fr.readlines()
numberOfLines = len(arrayOLines)
returnMat = zeros((numberOfLines, 3))
classLabelVector = []
index = 0
for line in arrayOLines:
line = line.strip()
listFromLine = line.split('\t')
returnMat[index,:] = listFromLine[0:3]
classLabelVector.append(int(listFromLine[-1]))
index += 1
return returnMat, classLabelVector

def autoNorm(dataSet):
minVals = dataSet.min(0)
maxVals = dataSet.max(0)
ranges = maxVals - minVals
normDataSet = zeros(shape(dataSet))
m = dataSet.shape[0]
normDataSet = dataSet - tile(minVals, (m, 1))
normDataSet = normDataSet / tile(ranges, (m, 1))
return normDataSet, ranges, minVals

def datingClassTest(k):
hoRatio = 0.10
datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
normMat, ranges, minVals = autoNorm(datingDataMat)
m = normMat.shape[0]
numTestVecs = int(m * hoRatio)
errorCount = 0.0
for i in range(numTestVecs):
classifierResult = classify0(normMat[i,:], normMat[numTestVecs:m,:],
datingLabels[numTestVecs:m], k)
print "The classifier came back with: %d, the real answer is: %d"\
% (classifierResult, datingLabels[i])
if classifierResult != datingLabels[i] : errorCount += 1.0
print "The total error rate is: %f" % (errorCount / float(numTestVecs))

knn算法比较简单,并且使用python语言,所以可以很快地实现该算法。动手跟着《机器学习实战》这本书敲了一遍代码之后,对knn的理解更加深入了一点。千里之行,始于足下。

LSTM Neural Networks for Chinese Word Segmentation

0.摘要

现在绝大多数的先进的中文分词方法都是基于有监督学习,其特征多数从本地文本中提取。这些方法不能利用一些至关重要的长距离的信息。在本篇文章中,我们发表了一篇对于中文分词的神经网络模型,它采用了长短记忆(LSTM)网络将先前的重要信息保存在记忆细胞中,并且避免了本地文本窗口的限制。实验在PKU,MSRA和CTB6人工标注的训练集,并展现出了比以往先进模型更出色的表现。

1.介绍

分词是中文自然语言处理中的一项基本任务。近些年,中文分词(CWS)的到了巨大的发展。流行的方法是将分词任务视为序列标记的问题。序列标注的目标是给序列中每一个元素分配标签,使用最大熵(ME)和条件随机场(CRF)等有监督学习算法可以实现。然而,这些模型受制于特征的设计,并且特征种类繁多以至于结果模型太大不利于实际应用,还被证明对于训练语料会产生过拟合。

RNN for NLP

背景

近些年,深度学习备受关注,这一前沿技术将在众多NLP问题上大放异彩,如预言模型,机器翻译,语音识别,语义理解等。然而解决这些应用上的问题,还需要人们不断探索与研究。本文将借鉴一些论文以及网上一些博客上的思想,如有侵权请给我留言,以便及时更正。
本篇文章将讨论RNN解决NLP中序列标注问题的优化。序列标注是NLP领域中有代表性的任务,可以解决中文分词,命名实体识别,词性标注等经典问题。解决序列标注问题的传统方法有CRF、最大熵等。随着深度学习技术的不断发展,深度学习将逐渐地取代传统方法。

序列标注

如上文所描述,一些NLP的问题可以转化为序列标注任务,所谓“序列标注”,就是说对于一个一维线性输入序列:

1
X = x1, x2, x3,..., xi,..., xn

得到标签集合中每个元素对应的标签:

1
Y = y1, y2, y3,..., yi,..., yn

所以,其本质上是对线性序列中每个元素根据上下文内容进行分类问题。一般情况下,对于NLP任务来说,线性序列就是输入的文本,往往可以把一个汉字看做线性序列中的一个元素,而不同标签集合对应的任务可能不想同。但是归根结底,都是抽象成了一个问题:如何根据汉字的上下文给汉字打上一个合适的标签。
下面再用命名实体识别(NER)问题举个序列标注解决问题的例子,命名实体识别任务是识别句子中出现的实体,通常识别人名、地名、机构名这三类实体。假设输入中文句子如下:

1
{花园北路的北医三院里,昏迷三年的我听杨幂的爱的供养时起身关了收音机。}

首先,我们将其看做汉字线性序列,然后我们定义标签集合:

1
LabelSet={BA, MA, EA, BO, MO, EO, BP, MP, EP, O}

其中,BA代表这个汉字是地址首字,MA代表这个汉字是地址中间字,EA代表这个汉字是地址的尾字;BO代表这个汉字是机构名的首字,MO代表这个汉字是机构名称的中间字,EO代表这个汉字是机构名的尾字;BP代表这个汉字是人名首字,MP代表这个汉字是人名中间字,EP代表这个汉字是人名尾字,而O代表这个汉字不属于命名实体。
有了输入序列和标签集合,我们只需要通过已有语料训练出ML模型,对于新的文本序列可以得到对应的标签,再通过后处理,把人名,地名,机构名都明确标记出来。如下图所示:
NER

RNN解决序列标注问题

首先用RNN解决序列标注问题,然后可以通过LSTM或者GRU来代替RNN中的隐藏单元,因为LSTM或GRU对于解决长距离依赖问题明显优于RNN本身。如果训练数据规模不大的情况下,很可能出现过拟合现象,所以使用LSTM的时候记得用上DropOut以及L1/L2正则来避免过拟合。至于GRU和LSTM两者相比,到底哪个更好目前并无定论,倾向于认为两者性能差不多,但是GRU是LSTM的简化模型,所以同样结构的神经网络其参数要少,在训练数据不太大情况下,优先考虑使用GRU。

参考文献

使用RNN解决NLP中序列标注问题的通用优化思路

了解word2vec

image

一、什么是word2vec

word2vec是Google在2013年中开元的一款将词表征为实数值向量的高效工具,采用的模型有CBOW(Continuous Bag-Of-Words,即连续的词袋模型)和Skip-Gram两种。word2vec项目主页地址点击,它遵循Apache License 2.0 开源协议,是一种对商业友好的许可,需要充分尊重原作者的著作权。
word2vec一般被外界认为是一个Deep Learning(深度学习)的模型,究其原因,可能和作者Tomas Mikolov的Deep Learning背景以及word2vec是一种神经网络模型相关,但我们认为该模型层次较浅,严格来讲还不能算是深层模型。当然如果word2vec上层再套一层与具体应用相关的输出层,比如Softmax,此时更像是一个深层模型。
word2vec通过训练,可以把对文本内容处理简化为K维向量空间中的向量运算,而向量空间上的相似度可以用来表示文本语义上的相似度。因此,word2vec输出的词向量可以被用来做很多NLP相关的工作,比如聚类、找同义词、词性分析等。而word2vec被人广为传颂的地方是其他向量的假发组合运算(Additive Compositionality),官网上的例子是:vector(‘Paris’) - vector(‘France’) + vector(‘Italy’) ≈ vector(‘Rome’)。但我们认为这个多少有点被过度炒作了,很多其他降维或主题模型在一定程度也能达到类似效果,而word2vec也只是少量的例子完美符合这种加减法操作,并不是所有的case都满足。
word2vec大受欢迎的另一个原因是其高效性,Mikolov在论文中支出优化的单机版本一天可训练上千亿词。

二、快速入门

  1. 代码下载
  2. 针对个人需求修改makefile文件,也可以不做修改
  3. 运行“make”编译word2vec工具
  4. 运行demo脚本,查看效果

三、背景知识

1.One-hot Representation
NLP相关任务中最常见的第一步是创建一个词表库并把每个词顺序编号。