首页 文章 精选 留言 我的

精选列表

搜索[快速入门],共10000篇文章
优秀的个人博客,低调大师

Python入门(六)序列之中,序列之间

1.列表 向列表中添加元素 一次只能添加一个元素到列表末尾:append() >>> player=['酷狗音乐','网易云音乐','QQ音乐','虾米音乐'] >>> player.append('落网') >>> player ['酷狗音乐', '网易云音乐', 'QQ音乐', '虾米音乐', '落网'] 一次添加多个元素到列表末尾:extend([]) >>> player=['酷狗音乐','网易云音乐','QQ音乐','虾米音乐'] >>> player.extend(['落网','酷我音乐']) >>> player ['酷狗音乐', '网易云音乐', 'QQ音乐', '虾米音乐', '落网', '落网', '酷我音乐'] 插入元素,可指定元素位置:insert() >>> player=['酷狗音乐','网易云音乐','QQ音乐','虾米音乐'] >>> player.insert(0,'落网') >>> player ['落网', '酷狗音乐', '网易云音乐', 'QQ音乐', '虾米音乐'] 从列表中获取元素 >>> player=['酷狗音乐','网易云音乐','QQ音乐','虾米音乐'] >>> temp=player[0] >>> temp '酷狗音乐' >>> player[0]=player[1] >>> player ['网易云音乐', '网易云音乐', 'QQ音乐', '虾米音乐'] >>> player[1]=temp >>> player ['网易云音乐', '酷狗音乐', 'QQ音乐', '虾米音乐'] 从列表删除元素 remove() >>> player=['酷狗音乐','网易云音乐','QQ音乐','虾米音乐'] >>> player.remove('QQ音乐') >>> player ['酷狗音乐', '网易云音乐', '虾米音乐'] del() >>> player=['酷狗音乐','网易云音乐','QQ音乐','虾米音乐'] >>> del player[2] >>> player ['酷狗音乐', '网易云音乐', '虾米音乐'] >>> del player >>> player NameError: name 'player' is not defined pop() >>> player=['酷狗音乐','网易云音乐','QQ音乐','虾米音乐'] >>> er=player.pop() >>> er '虾米音乐' >>> player ['酷狗音乐', '网易云音乐', 'QQ音乐'] 列表分片[:] 列表分片 >>> player=['酷狗音乐','网易云音乐','QQ音乐','虾米音乐'] >>> player[1:3] ['网易云音乐', 'QQ音乐'] >>> player ['酷狗音乐', '网易云音乐', 'QQ音乐', '虾米音乐'] 列表拷贝 >>> player=['酷狗音乐','网易云音乐','QQ音乐','虾米音乐'] >>> player1=player[:] >>> player1 ['酷狗音乐', '网易云音乐', 'QQ音乐', '虾米音乐'] 列表中常用的操作符 比较运算符 >>> number1=[3,4,2,6] >>> number2=[3,4,6,6] >>> number1>number2 False 列表中,从第0个元素开始依次向后比较,只要不相等,不再继续向后比较。 逻辑操作符 >>> number1=[3,4,2,6] >>> number2=[3,4,6,6] >>> number3=[3,2,6,4] >>> (number1<number2)or(number1==number3) True 连接操作符 >>> number1=[3,4,2,6] >>> number2=[3,4,6,6] >>> number1+number2 [3, 4, 2, 6, 3, 4, 6, 6] 重复操作符 >>> number1=[3,4,2,6] >>> number1*3 [3, 4, 2, 6, 3, 4, 2, 6, 3, 4, 2, 6] >>> number1 #number1没有改变 [3, 4, 2, 6] >>> number1*=3 >>> number1 #number1改变 [3, 4, 2, 6, 3, 4, 2, 6, 3, 4, 2, 6] 成员关系操作符(in、not in) >>> number1=[3,4,2,6,[7,8,9]] >>> 3 in number1 True >>> 7 not in number1 #由结果可知成员关系操作符不能识别列表中的列表元素 True >>> number1[4][0] #想访问列表中的列表元素,类似二维数组 7 列表的BIF 可以在编译器内查看列表有哪些BIF 检测参数在列表中出现的次数:count([parameter]) >>> number1=[3, 4, 2, 6, 3, 4, 2, 6, 3, 4, 2, 6] >>> number1.count(3) 3 返回参数在列表中的位置:index([parameter],[start],[end]) >>> number1=[3, 4, 2, 6, 3, 4, 2, 6, 3, 4, 2, 6] >>> number1.index(3,2,6) #从第2个参数到第六个参数之间的范围内查找参数3的位置 4 将整个列表原地翻转:reverse() >>> number1=[3, 4, 2, 6, 3, 4, 2, 6, 3, 4, 2, 6] >>> number1.reverse() >>> number1 [6, 2, 4, 3, 6, 2, 4, 3, 6, 2, 4, 3] 将列表内元素排序,用func设置排序算法,key表示与算法搭配的关键字:sort(func,key,reverse = Flase) >>> number1=[3, 4, 2, 6, 3, 4, 2, 6, 3, 4, 2, 6] >>> number1.sort() #默认是从小到大排序 >>> number1 [2, 2, 2, 3, 3, 3, 4, 4, 4, 6, 6, 6] >>>number1=[3, 4, 2, 6, 3, 4, 2, 6, 3, 4, 2, 6] >>> number1.sort(reverse = True) #从大到小排序 >>> number1 [6, 6, 6, 4, 4, 4, 3, 3, 3, 2, 2, 2] >>> number1=[3,2,6,4] >>> number2=number1[:] #通过分片的方法获得一个和number1相同的列表 >>> number3=number1 #通过直接赋值的方法获得一个和number1相同的列表 >>> number2 [3, 2, 6, 4] >>> number3 [3, 2, 6, 4] >>> number1.sort() #将number1排序 >>> number1 #number1改变 [2, 3, 4, 6] >>> number2 #number2改变 [3, 2, 6, 4] >>> number3 #number3不变 [2, 3, 4, 6] 这说明通过分片拷贝获得的新列表是不受原列表影响的独立列表,而通过赋值获得的只是改变了列表名称,本质上还是同一个列表。 2.元祖 向元祖中插入元素 >>> tuple1=('酷狗音乐', '网易云音乐', 'QQ音乐', '虾米音乐') >>> tuple1=tuple1[:2]+('落网',)+tuple1[2:] >>> tuple1 ('酷狗音乐', '网易云音乐', '落网', 'QQ音乐', '虾米音乐') 从元祖中获取元素 >>> tuple1=(1,2,3,4) >>> tuple2=tuple1[:2] >>> tuple2 (1, 2) 删除元祖 >>> tuple1=('酷狗音乐', '网易云音乐', 'QQ音乐', '虾米音乐') >>> del tuple1 >>> tuple1 NameError: name 'tuple1' is not defined 元祖可变?不可变? >>> tuple1= ('酷狗音乐', '网易云音乐', ['华晨宇', '丁可']) >>> list1= tuple1[2] >>> list1[0] = '杨千嬅' >>> list1[1] = '莫文蔚' >>> tuple1 ('酷狗音乐', '网易云音乐', ['杨千嬅', '莫文蔚']) 这说明tuple所谓的“不变”是说,tuple的每个元素的指向不变。 元祖拷贝和操作符的用法与列表类似 3.字符串、列表和元祖的关系 序列的特点 都可以通过索引得到每一个元素; 默认索引值总是从0开始; 可以通过切片的方法得到一个范围内的元素的集合; 有很多共同的操作符(重复操作符、拼接操作符、成员关系操作符)。 序列的BIF 返回sub的长度:len(sub) >>> tuple1= ('酷狗音乐', '网易云音乐', ['华晨宇', '丁可']) >>> len(tuple1) 3 返回序列中的最大值、最小值,对于字母是比较它们的ASCII码:max(seq)、min(seq)在数学类函数中介绍的max()和min(),只说明了它们对数字的处理能力,其实它们也可以对序列操作。 >>> player=['酷狗音乐','网易云音乐','QQ音乐','虾米音乐'] >>> max(player) '虾米音乐' >>> min(player) 'QQ音乐' 对序列元素进行翻转:reversed() >>> player=['酷狗音乐','网易云音乐','QQ音乐','虾米音乐'] >>> reversed(player) #这样返回的是一个可迭代对象 <list_reverseiterator object at 0x0000000002E09780> >>> list(reversed(player)) #这才是翻转的正确操作 ['虾米音乐', 'QQ音乐', '网易云音乐', '酷狗音乐'] 生成每个元素的索引值和iterable值和组成的元祖的列表:enumerate() >>> player=['酷狗音乐','网易云音乐','QQ音乐','虾米音乐'] >>> enumerate(player) <enumerate object at 0x00000000030D71F8> >>> list(enumerate(player)) [(0, '酷狗音乐'), (1, '网易云音乐'), (2, 'QQ音乐'), (3, '虾米音乐')] 返回由各个参数的序列组成的元祖:zip() >>> player=['酷狗音乐','网易云音乐','QQ音乐','虾米音乐'] >>> singer=['华晨宇','丁可','杨乃文','王若琳'] >>> zip(player,singer) <zip object at 0x00000000030DF348> >>> list(zip(player,singer)) [('酷狗音乐', '华晨宇'), ('网易云音乐', '丁可'), ('QQ音乐', '杨乃文'), ('虾米音乐', '王若琳')] 对序列元素进行排序:sorted() >>> player=['酷狗音乐','网易云音乐','QQ音乐','虾米音乐'] >>> sorted(player) ['QQ音乐', '网易云音乐', '虾米音乐', '酷狗音乐'] 返回序列中数值设定参数start的总和: sum(iterable[,start=0]) >>> tuple1=(1,2,3,4,) >>> sum(tuple1) 10 >>> sum(tuple1,5) 15 任何参数都能用sum()吗? >>> tuple1=('a','b','c','d') >>> sum(tuple1) TypeError: unsupported operand type(s) for +: 'int' and 'str' 当序列的元素有非数字类型时报错了,说明sum()只能对数字型数据进行操作。 END!

优秀的个人博客,低调大师

Python入门(四)数学类函数总结

数学常量 圆周率:pi; 自然常数:e。 数学函数 返回数字的绝对值,且值的类型取决于原参数的类型(复数返回浮点型):abs( x )x---数值 >>> abs(-1.23) 1.23 >>> abs(3+4j) 5.0 返回浮点数或整数的绝对值,且值的类型只能是浮点型:fabs( x )x---数值 >>> import math >>> math.fabs(-1.23) 1.23 返回数字上取后的整数:ceil( x )x---数值 >>> import math # ceil(x)不能直接访问,需先导入 math 模块 >>> math.ceil(-0.74) 0 返回数字下舍后的整数:floor(x)x---数值 >>> import math # floor(x)不能直接访问,需先导入 math 模块 >>> math.floor(-0.74) -1 返回x的小数部分与整数部分,注意整数部分以浮点型表示:modf(x)x---数值 >>> import math # modf(x)不能直接访问,需先导入 math 模块 >>> math.modf(-111.222) (-0.2219999999999942, -111.0) 返回浮点数x的四舍五入值:round(x [, n]) x---浮点数; n---精度 >>> round(111.222333444, 6) 111.222333 返回x的y次方:pow() 1)内置方法 >>> pow(2, 3) #把参数作为整型 8 2)导入math模块 >>> import math #把参数作为浮点型 >>> math.pow(2, 3) 8.0 返回数字x的平方根:sqrt(x)x---数值 >>> import math # sqrt(x)不能直接访问,需先导入 math 模块 >>> math.sqrt(100) 10.0 返回x的自然对数:log(x)x---数值表达式 >>> import math # log(x)不能直接访问,需先导入 math 模块 >>> math.log(0.1353352832366127) -2.0 返回x的指数:exp( x )x---数值表达式 >>> import math # exp(x)不能直接访问,需先导入 math 模块 >>> math.exp(-2) 0.1353352832366127 返回给定参数的最大值,参数可以为序列:max( x, y, z, .... )x,y,z---数值 >>> max(1, 3, 2) 3 返回给定参数的最小值,参数可以为序列:min( x, y, z, .... )x,y,z---数值 >>> min(1, 3, 2) 1 随机数函数 从序列的元素中随机挑选一个元素:choice(seq)seq---列表,元组或字符串 >>> import random >>> print('DJY,are you handsome?',random.choice(['--SURE!','--NOT AT ALL!','--GUESS?'])) DJY,are you handsome? --SURE! 从给定的范围返回随机项:randrange ([start,] stop [,step])start---指定范围内的开始值,包含在范围内; stop---指定范围内的结束值,不包含在范围内;step---步长,默认为1。 >>> import random >>> random.randrange(11, 999, 12) 587 返回随机生成的一个实数,它在[0,1)范围内: random() >>> import random >>> random.random() 0.5895961190959703 改变随机数生成器的种子,可以在调用其他随机模块函数之前调用此函数:seed(x)x---改变随机数生成器的种子,可不设置 >>> import random >>> random.seed(10) >>> random.random() 0.5714025946899135 >>> random.seed(10) >>> random.random() 0.5714025946899135 随机生成一个在[x,y]范围内的实数:uniform(x, y)x---最小随机数; y---最大随机数; >>> import random >>> random.uniform(0.15,578) 168.77383737106067 返回随机排序后的序列:shuffle (lst)lst---列表 >>> import random >>> list1 = ['酷狗音乐','网易云音乐','QQ音乐', '虾米音乐'] >>> random.shuffle(list1) >>> list1 ['QQ音乐', '虾米音乐', '酷狗音乐', '网易云音乐'] 三角函数 返回x的反正弦、反余弦弧度值:asin(x) 、acos(x)x--- -1到1之间的数值 >>> import math >>> math.acos(0.55) 0.9884320889261531 >>> import math >>> math.asin(0.55) 0.5823642378687435 返回x的反正切弧度值:atan(x)x---数值 >>> import math >>> math.atan(0.55) 0.5028432109278609 返回给定的 X 及 Y 坐标值的反正切值:atan2(y, x)x,y---数值 >>> import math >>> math.atan2(0.55,0.55) 0.7853981633974483 返回x的弧度的正弦值、余弦值、正切值:sin(x)、cos(x)、tan(x)x---数值 >>> import math >>> math.sin(0.55) 0.5226872289306592 >>> import math >>> math.cos(0.55) 0.8525245220595057 >>> import math >>> math.tan(0.55) 0.6131052132881357 返回欧几里德范数 sqrt(x*x + y*y):hypot(x,y) x,y---数值 >>> import math >>> math.hypot(1,2) 2.23606797749979 将弧度转换为角度:degrees(x) x---数值 >>> import math >>> math.degrees(-2) -114.59155902616465 角度转换为弧度:radians() x---数值 >>>import math >>> math.radians(-2) -0.03490658503988659 最后有点感想,对于函数,往往看中的是它的功能以及返回值,有些函数功能很类似,但是不要忽略了,他们运行速度的微略差距,也许很不起眼,但是并不渺小。 END!

优秀的个人博客,低调大师

Python 数据科学入门教程:NLTK

自然语言处理教程 原文:Natural Language Process 译者:飞龙 协议:CC BY-NC-SA 4.0 一、使用 NLTK 分析单词和句子 欢迎阅读自然语言处理系列教程,使用 Python 的自然语言工具包 NLTK 模块。 NLTK 模块是一个巨大的工具包,目的是在整个自然语言处理(NLP)方法上帮助您。 NLTK 将为您提供一切,从将段落拆分为句子,拆分词语,识别这些词语的词性,高亮主题,甚至帮助您的机器了解文本关于什么。在这个系列中,我们将要解决意见挖掘或情感分析的领域。 在我们学习如何使用 NLTK 进行情感分析的过程中,我们将学习以下内容: 分词 - 将文本正文分割为句子和单词。 词性标注 机器学习与朴素贝叶斯分类器 如何一起使用 Scikit Learn(sklearn)与 NLTK 用数据集训练分类器 用 Twitter 进行实时的流式情感分析。 …以及更多。 为了开始,你需要 NLTK 模块,以及 Python。 如果您还没有 Python,请转到python.org并下载最新版本的 Python(如果您在 Windows上)。如果你在 Mac 或 Linux 上,你应该可以运行apt-get install python3。 接下来,您需要 NLTK 3。安装 NLTK 模块的最简单方法是使用pip。 对于所有的用户来说,这通过打开cmd.exe,bash,或者你使用的任何 shell,并键入以下命令来完成: pip install nltk 接下来,我们需要为 NLTK 安装一些组件。通过你的任何常用方式打开 python,然后键入: import nltk nltk.download() 除非你正在操作无头版本,否则一个 GUI 会弹出来,可能只有红色而不是绿色: 为所有软件包选择下载“全部”,然后单击“下载”。 这会给你所有分词器,分块器,其他算法和所有的语料库。 如果空间是个问题,您可以选择手动选择性下载所有内容。 NLTK 模块将占用大约 7MB,整个nltk_data目录将占用大约 1.8GB,其中包括您的分块器,解析器和语料库。 如果您正在使用 VPS 运行无头版本,您可以通过运行 Python ,并执行以下操作来安装所有内容: import nltk nltk.download() d (for download) all (for download everything) 这将为你下载一切东西。 现在你已经拥有了所有你需要的东西,让我们敲一些简单的词汇: 语料库(Corpus) - 文本的正文,单数。Corpora 是它的复数。示例:A collection of medical journals。 词库(Lexicon) - 词汇及其含义。例如:英文字典。但是,考虑到各个领域会有不同的词库。例如:对于金融投资者来说,Bull(牛市)这个词的第一个含义是对市场充满信心的人,与“普通英语词汇”相比,这个词的第一个含义是动物。因此,金融投资者,医生,儿童,机械师等都有一个特殊的词库。 标记(Token) - 每个“实体”都是根据规则分割的一部分。例如,当一个句子被“拆分”成单词时,每个单词都是一个标记。如果您将段落拆分为句子,则每个句子也可以是一个标记。 这些是在进入自然语言处理(NLP)领域时,最常听到的词语,但是我们将及时涵盖更多的词汇。以此,我们来展示一个例子,说明如何用 NLTK 模块将某些东西拆分为标记。 from nltk.tokenize import sent_tokenize, word_tokenize EXAMPLE_TEXT = "Hello Mr. Smith, how are you doing today? The weather is great, and Python is awesome. The sky is pinkish-blue. You shouldn't eat cardboard." print(sent_tokenize(EXAMPLE_TEXT)) 起初,你可能会认为按照词或句子来分词,是一件相当微不足道的事情。 对于很多句子来说,它可能是。 第一步可能是执行一个简单的.split('. '),或按照句号,然后是空格分割。 之后也许你会引入一些正则表达式,来按照句号,空格,然后是大写字母分割。 问题是像Mr. Smith这样的事情,还有很多其他的事情会给你带来麻烦。 按照词分割也是一个挑战,特别是在考虑缩写的时候,例如we和we're。 NLTK 用这个看起来简单但非常复杂的操作为您节省大量的时间。 上面的代码会输出句子,分成一个句子列表,你可以用for循环来遍历。 ['Hello Mr. Smith, how are you doing today?', 'The weather is great, and Python is awesome.', 'The sky is pinkish-blue.', "You shouldn't eat cardboard."] 所以这里,我们创建了标记,它们都是句子。让我们这次按照词来分词。 print(word_tokenize(EXAMPLE_TEXT)) ['Hello', 'Mr.', 'Smith', ',', 'how', 'are', 'you', 'doing', 'today', '?', 'The', 'weather', 'is', 'great', ',', 'and', 'Python', 'is', 'awesome', '.', 'The', 'sky', 'is', 'pinkish-blue', '.', 'You', 'should', "n't", 'eat', 'cardboard', '.'] 这里有几件事要注意。 首先,注意标点符号被视为一个单独的标记。 另外,注意单词shouldn't分隔为should和n't。 最后要注意的是,pinkish-blue确实被当作“一个词”来对待,本来就是这样。很酷! 现在,看着这些分词后的单词,我们必须开始思考我们的下一步可能是什么。 我们开始思考如何通过观察这些词汇来获得含义。 我们可以想清楚,如何把价值放在许多单词上,但我们也看到一些基本上毫无价值的单词。 这是一种“停止词”的形式,我们也可以处理。 这就是我们将在下一个教程中讨论的内容。 二、NLTK 与停止词 自然语言处理的思想,是进行某种形式的分析或处理,机器至少可以在某种程度上理解文本的含义,表述或暗示。 这显然是一个巨大的挑战,但是有一些任何人都能遵循的步骤。然而,主要思想是电脑根本不会直接理解单词。令人震惊的是,人类也不会。在人类中,记忆被分解成大脑中的电信号,以发射模式的神经组的形式。对于大脑还有很多未知的事情,但是我们越是把人脑分解成基本的元素,我们就会发现基本的元素。那么,事实证明,计算机以非常相似的方式存储信息!如果我们要模仿人类如何阅读和理解文本,我们需要一种尽可能接近的方法。一般来说,计算机使用数字来表示一切事物,但是我们经常直接在编程中看到使用二进制信号(True或False,可以直接转换为 1 或 0,直接来源于电信号存在(True, 1)或不存在(False, 0))。为此,我们需要一种方法,将单词转换为数值或信号模式。将数据转换成计算机可以理解的东西,这个过程称为“预处理”。预处理的主要形式之一就是过滤掉无用的数据。在自然语言处理中,无用词(数据)被称为停止词。 我们可以立即认识到,有些词语比其他词语更有意义。我们也可以看到,有些单词是无用的,是填充词。例如,我们在英语中使用它们来填充句子,这样就没有那么奇怪的声音了。一个最常见的,非官方的,无用词的例子是单词umm。人们经常用umm来填充,比别的词多一些。这个词毫无意义,除非我们正在寻找一个可能缺乏自信,困惑,或者说没有太多话的人。我们都这样做,有…呃…很多时候,你可以在视频中听到我说umm或uhh。对于大多数分析而言,这些词是无用的。 我们不希望这些词占用我们数据库的空间,或占用宝贵的处理时间。因此,我们称这些词为“无用词”,因为它们是无用的,我们希望对它们不做处理。 “停止词”这个词的另一个版本可以更书面一些:我们停在上面的单词。 例如,如果您发现通常用于讽刺的词语,可能希望立即停止。讽刺的单词或短语将因词库和语料库而异。就目前而言,我们将把停止词当作不含任何含义的词,我们要把它们删除。 您可以轻松地实现它,通过存储您认为是停止词的单词列表。 NLTK 用一堆他们认为是停止词的单词,来让你起步,你可以通过 NLTK 语料库来访问它: from nltk.corpus import stopwords 这里是这个列表: >>> set(stopwords.words('english')) {'ourselves', 'hers', 'between', 'yourself', 'but', 'again', 'there', 'about', 'once', 'during', 'out', 'very', 'having', 'with', 'they', 'own', 'an', 'be', 'some', 'for', 'do', 'its', 'yours', 'such', 'into', 'of', 'most', 'itself', 'other', 'off', 'is', 's', 'am', 'or', 'who', 'as', 'from', 'him', 'each', 'the', 'themselves', 'until', 'below', 'are', 'we', 'these', 'your', 'his', 'through', 'don', 'nor', 'me', 'were', 'her', 'more', 'himself', 'this', 'down', 'should', 'our', 'their', 'while', 'above', 'both', 'up', 'to', 'ours', 'had', 'she', 'all', 'no', 'when', 'at', 'any', 'before', 'them', 'same', 'and', 'been', 'have', 'in', 'will', 'on', 'does', 'yourselves', 'then', 'that', 'because', 'what', 'over', 'why', 'so', 'can', 'did', 'not', 'now', 'under', 'he', 'you', 'herself', 'has', 'just', 'where', 'too', 'only', 'myself', 'which', 'those', 'i', 'after', 'few', 'whom', 't', 'being', 'if', 'theirs', 'my', 'against', 'a', 'by', 'doing', 'it', 'how', 'further', 'was', 'here', 'than'} 以下是结合使用stop_words集合,从文本中删除停止词的方法: from nltk.corpus import stopwords from nltk.tokenize import word_tokenize example_sent = "This is a sample sentence, showing off the stop words filtration." stop_words = set(stopwords.words('english')) word_tokens = word_tokenize(example_sent) filtered_sentence = [w for w in word_tokens if not w in stop_words] filtered_sentence = [] for w in word_tokens: if w not in stop_words: filtered_sentence.append(w) print(word_tokens) print(filtered_sentence) 我们的输出是: ['This', 'is', 'a', 'sample', 'sentence', ',', 'showing', 'off', 'the', 'stop', 'words', 'filtration', '.'] ['This', 'sample', 'sentence', ',', 'showing', 'stop', 'words', 'filtration', '.'] 我们的数据库感谢了我们。数据预处理的另一种形式是“词干提取(Stemming)”,这就是我们接下来要讨论的内容。 三、NLTK 词干提取 词干的概念是一种规范化方法。 除涉及时态之外,许多词语的变体都具有相同的含义。 我们提取词干的原因是为了缩短查找的时间,使句子正常化。 考虑: I was taking a ride in the car. I was riding in the car. 这两句话意味着同样的事情。 in the car(在车上)是一样的。 I(我)是一样的。 在这两种情况下,ing都明确表示过去式,所以在试图弄清这个过去式活动的含义的情况下,是否真的有必要区分riding和taking a ride? 不,并没有。 这只是一个小例子,但想象英语中的每个单词,可以放在单词上的每个可能的时态和词缀。 每个版本有单独的字典条目,将非常冗余和低效,特别是因为一旦我们转换为数字,“价值”将是相同的。 最流行的瓷感提取算法之一是 Porter,1979 年就存在了。 首先,我们要抓取并定义我们的词干: from nltk.stem import PorterStemmer from nltk.tokenize import sent_tokenize, word_tokenize ps = PorterStemmer() 现在让我们选择一些带有相似词干的单词,例如: example_words = ["python","pythoner","pythoning","pythoned","pythonly"] 下面,我们可以这样做来轻易提取词干: for w in example_words: print(ps.stem(w)) 我们的输出: python python python python pythonli 现在让我们尝试对一个典型的句子,而不是一些单词提取词干: new_text = "It is important to by very pythonly while you are pythoning with python. All pythoners have pythoned poorly at least once." words = word_tokenize(new_text) for w in words: print(ps.stem(w)) 现在我们的结果为: It is import to by veri pythonli while you are python with python . All python have python poorli at least onc . 接下来,我们将讨论 NLTK 模块中一些更高级的内容,词性标注,其中我们可以使用 NLTK 模块来识别句子中每个单词的词性。 四、NLTK 词性标注 NLTK模块的一个更强大的方面是,它可以为你做词性标注。 意思是把一个句子中的单词标注为名词,形容词,动词等。 更令人印象深刻的是,它也可以按照时态来标记,以及其他。 这是一列标签,它们的含义和一些例子: POS tag list: CC coordinating conjunction CD cardinal digit DT determiner EX existential there (like: "there is" ... think of it like "there exists") FW foreign word IN preposition/subordinating conjunction JJ adjective 'big' JJR adjective, comparative 'bigger' JJS adjective, superlative 'biggest' LS list marker 1) MD modal could, will NN noun, singular 'desk' NNS noun plural 'desks' NNP proper noun, singular 'Harrison' NNPS proper noun, plural 'Americans' PDT predeterminer 'all the kids' POS possessive ending parent's PRP personal pronoun I, he, she PRP$ possessive pronoun my, his, hers RB adverb very, silently, RBR adverb, comparative better RBS adverb, superlative best RP particle give up TO to go 'to' the store. UH interjection errrrrrrrm VB verb, base form take VBD verb, past tense took VBG verb, gerund/present participle taking VBN verb, past participle taken VBP verb, sing. present, non-3d take VBZ verb, 3rd person sing. present takes WDT wh-determiner which WP wh-pronoun who, what WP$ possessive wh-pronoun whose WRB wh-abverb where, when 我们如何使用这个? 当我们处理它的时候,我们要讲解一个新的句子标记器,叫做PunktSentenceTokenizer。 这个标记器能够无监督地进行机器学习,所以你可以在你使用的任何文本上进行实际的训练。 首先,让我们获取一些我们打算使用的导入: import nltk from nltk.corpus import state_union from nltk.tokenize import PunktSentenceTokenizer 现在让我们创建训练和测试数据: train_text = state_union.raw("2005-GWBush.txt") sample_text = state_union.raw("2006-GWBush.txt") 一个是 2005 年以来的国情咨文演说,另一个是 2006 年以来的乔治·W·布什总统的演讲。 接下来,我们可以训练 Punkt 标记器,如下所示: custom_sent_tokenizer = PunktSentenceTokenizer(train_text) 之后我们可以实际分词,使用: tokenized = custom_sent_tokenizer.tokenize(sample_text) 现在我们可以通过创建一个函数,来完成这个词性标注脚本,该函数将遍历并标记每个句子的词性,如下所示: def process_content(): try: for i in tokenized[:5]: words = nltk.word_tokenize(i) tagged = nltk.pos_tag(words) print(tagged) except Exception as e: print(str(e)) process_content() 输出应该是元组列表,元组中的第一个元素是单词,第二个元素是词性标签。 它应该看起来像: [('PRESIDENT', 'NNP'), ('GEORGE', 'NNP'), ('W.', 'NNP'), ('BUSH', 'NNP'), ("'S", 'POS'), ('ADDRESS', 'NNP'), ('BEFORE', 'NNP'), ('A', 'NNP'), ('JOINT', 'NNP'), ('SESSION', 'NNP'), ('OF', 'NNP'), ('THE', 'NNP'), ('CONGRESS', 'NNP'), ('ON', 'NNP'), ('THE', 'NNP'), ('STATE', 'NNP'), ('OF', 'NNP'), ('THE', 'NNP'), ('UNION', 'NNP'), ('January', 'NNP'), ('31', 'CD'), (',', ','), ('2006', 'CD'), ('THE', 'DT'), ('PRESIDENT', 'NNP'), (':', ':'), ('Thank', 'NNP'), ('you', 'PRP'), ('all', 'DT'), ('.', '.')] [('Mr.', 'NNP'), ('Speaker', 'NNP'), (',', ','), ('Vice', 'NNP'), ('President', 'NNP'), ('Cheney', 'NNP'), (',', ','), ('members', 'NNS'), ('of', 'IN'), ('Congress', 'NNP'), (',', ','), ('members', 'NNS'), ('of', 'IN'), ('the', 'DT'), ('Supreme', 'NNP'), ('Court', 'NNP'), ('and', 'CC'), ('diplomatic', 'JJ'), ('corps', 'NNS'), (',', ','), ('distinguished', 'VBD'), ('guests', 'NNS'), (',', ','), ('and', 'CC'), ('fellow', 'JJ'), ('citizens', 'NNS'), (':', ':'), ('Today', 'NN'), ('our', 'PRP$'), ('nation', 'NN'), ('lost', 'VBD'), ('a', 'DT'), ('beloved', 'VBN'), (',', ','), ('graceful', 'JJ'), (',', ','), ('courageous', 'JJ'), ('woman', 'NN'), ('who', 'WP'), ('called', 'VBN'), ('America', 'NNP'), ('to', 'TO'), ('its', 'PRP$'), ('founding', 'NN'), ('ideals', 'NNS'), ('and', 'CC'), ('carried', 'VBD'), ('on', 'IN'), ('a', 'DT'), ('noble', 'JJ'), ('dream', 'NN'), ('.', '.')] [('Tonight', 'NNP'), ('we', 'PRP'), ('are', 'VBP'), ('comforted', 'VBN'), ('by', 'IN'), ('the', 'DT'), ('hope', 'NN'), ('of', 'IN'), ('a', 'DT'), ('glad', 'NN'), ('reunion', 'NN'), ('with', 'IN'), ('the', 'DT'), ('husband', 'NN'), ('who', 'WP'), ('was', 'VBD'), ('taken', 'VBN'), ('so', 'RB'), ('long', 'RB'), ('ago', 'RB'), (',', ','), ('and', 'CC'), ('we', 'PRP'), ('are', 'VBP'), ('grateful', 'JJ'), ('for', 'IN'), ('the', 'DT'), ('good', 'NN'), ('life', 'NN'), ('of', 'IN'), ('Coretta', 'NNP'), ('Scott', 'NNP'), ('King', 'NNP'), ('.', '.')] [('(', 'NN'), ('Applause', 'NNP'), ('.', '.'), (')', ':')] [('President', 'NNP'), ('George', 'NNP'), ('W.', 'NNP'), ('Bush', 'NNP'), ('reacts', 'VBZ'), ('to', 'TO'), ('applause', 'VB'), ('during', 'IN'), ('his', 'PRP$'), ('State', 'NNP'), ('of', 'IN'), ('the', 'DT'), ('Union', 'NNP'), ('Address', 'NNP'), ('at', 'IN'), ('the', 'DT'), ('Capitol', 'NNP'), (',', ','), ('Tuesday', 'NNP'), (',', ','), ('Jan', 'NNP'), ('.', '.')] 到了这里,我们可以开始获得含义,但是还有一些工作要做。 我们将要讨论的下一个话题是分块(chunking),其中我们跟句单词的词性,将单词分到,有意义的分组中。 五、NLTK 分块 现在我们知道了词性,我们可以注意所谓的分块,把词汇分成有意义的块。 分块的主要目标之一是将所谓的“名词短语”分组。 这些是包含一个名词的一个或多个单词的短语,可能是一些描述性词语,也可能是一个动词,也可能是一个副词。 这个想法是把名词和与它们有关的词组合在一起。 为了分块,我们将词性标签与正则表达式结合起来。 主要从正则表达式中,我们要利用这些东西: + = match 1 or more ? = match 0 or 1 repetitions. * = match 0 or MORE repetitions . = Any character except a new line 如果您需要正则表达式的帮助,请参阅上面链接的教程。 最后需要注意的是,词性标签中用<和>表示,我们也可以在标签本身中放置正则表达式,来表达“全部名词”(<N.*>)。 import nltk from nltk.corpus import state_union from nltk.tokenize import PunktSentenceTokenizer train_text = state_union.raw("2005-GWBush.txt") sample_text = state_union.raw("2006-GWBush.txt") custom_sent_tokenizer = PunktSentenceTokenizer(train_text) tokenized = custom_sent_tokenizer.tokenize(sample_text) def process_content(): try: for i in tokenized: words = nltk.word_tokenize(i) tagged = nltk.pos_tag(words) chunkGram = r"""Chunk: {<RB.?>*<VB.?>*<NNP>+<NN>?}""" chunkParser = nltk.RegexpParser(chunkGram) chunked = chunkParser.parse(tagged) chunked.draw() except Exception as e: print(str(e)) process_content() 结果是这样的: 这里的主要一行是: chunkGram = r"""Chunk: {<RB.?>*<VB.?>*<NNP>+<NN>?}""" 把这一行拆分开: <RB.?>*:零个或多个任何时态的副词,后面是: <VB.?>*:零个或多个任何时态的动词,后面是: <NNP>+:一个或多个合理的名词,后面是: <NN>?:零个或一个名词单数。 尝试玩转组合来对各种实例进行分组,直到您觉得熟悉了。 视频中没有涉及,但是也有个合理的任务是实际访问具体的块。 这是很少被提及的,但根据你在做的事情,这可能是一个重要的步骤。 假设你把块打印出来,你会看到如下输出: (S (Chunk PRESIDENT/NNP GEORGE/NNP W./NNP BUSH/NNP) 'S/POS (Chunk ADDRESS/NNP BEFORE/NNP A/NNP JOINT/NNP SESSION/NNP OF/NNP THE/NNP CONGRESS/NNP ON/NNP THE/NNP STATE/NNP OF/NNP THE/NNP UNION/NNP January/NNP) 31/CD ,/, 2006/CD THE/DT (Chunk PRESIDENT/NNP) :/: (Chunk Thank/NNP) you/PRP all/DT ./.) 很酷,这可以帮助我们可视化,但如果我们想通过我们的程序访问这些数据呢? 那么,这里发生的是我们的“分块”变量是一个 NLTK 树。 每个“块”和“非块”是树的“子树”。 我们可以通过像chunked.subtrees的东西来引用它们。 然后我们可以像这样遍历这些子树: for subtree in chunked.subtrees(): print(subtree) 接下来,我们可能只关心获得这些块,忽略其余部分。 我们可以在chunked.subtrees()调用中使用filter参数。 for subtree in chunked.subtrees(filter=lambda t: t.label() == 'Chunk'): print(subtree) 现在,我们执行过滤,来显示标签为“块”的子树。 请记住,这不是 NLTK 块属性中的“块”…这是字面上的“块”,因为这是我们给它的标签:chunkGram = r"""Chunk: {<RB.?>*<VB.?>*<NNP>+<NN>?}"""。 如果我们写了一些东西,类似chunkGram = r"""Pythons: {<RB.?>*<VB.?>*<NNP>+<NN>?}""",那么我们可以通过"Pythons."标签来过滤。 结果应该是这样的: - (Chunk PRESIDENT/NNP GEORGE/NNP W./NNP BUSH/NNP) (Chunk ADDRESS/NNP BEFORE/NNP A/NNP JOINT/NNP SESSION/NNP OF/NNP THE/NNP CONGRESS/NNP ON/NNP THE/NNP STATE/NNP OF/NNP THE/NNP UNION/NNP January/NNP) (Chunk PRESIDENT/NNP) (Chunk Thank/NNP) 完整的代码是: import nltk from nltk.corpus import state_union from nltk.tokenize import PunktSentenceTokenizer train_text = state_union.raw("2005-GWBush.txt") sample_text = state_union.raw("2006-GWBush.txt") custom_sent_tokenizer = PunktSentenceTokenizer(train_text) tokenized = custom_sent_tokenizer.tokenize(sample_text) def process_content(): try: for i in tokenized: words = nltk.word_tokenize(i) tagged = nltk.pos_tag(words) chunkGram = r"""Chunk: {<RB.?>*<VB.?>*<NNP>+<NN>?}""" chunkParser = nltk.RegexpParser(chunkGram) chunked = chunkParser.parse(tagged) print(chunked) for subtree in chunked.subtrees(filter=lambda t: t.label() == 'Chunk'): print(subtree) chunked.draw() except Exception as e: print(str(e)) process_content() 六、 NLTK 添加缝隙(Chinking) 你可能会发现,经过大量的分块之后,你的块中还有一些你不想要的单词,但是你不知道如何通过分块来摆脱它们。 你可能会发现添加缝隙是你的解决方案。 添加缝隙与分块很像,它基本上是一种从块中删除块的方法。 你从块中删除的块就是你的缝隙。 代码非常相似,你只需要用}{来代码缝隙,在块后面,而不是块的{}。 import nltk from nltk.corpus import state_union from nltk.tokenize import PunktSentenceTokenizer train_text = state_union.raw("2005-GWBush.txt") sample_text = state_union.raw("2006-GWBush.txt") custom_sent_tokenizer = PunktSentenceTokenizer(train_text) tokenized = custom_sent_tokenizer.tokenize(sample_text) def process_content(): try: for i in tokenized[5:]: words = nltk.word_tokenize(i) tagged = nltk.pos_tag(words) chunkGram = r"""Chunk: {<.*>+} }<VB.?|IN|DT|TO>+{""" chunkParser = nltk.RegexpParser(chunkGram) chunked = chunkParser.parse(tagged) chunked.draw() except Exception as e: print(str(e)) process_content() 使用它,你得到了一些东西: 现在,主要的区别是: }<VB.?|IN|DT|TO>+{ 这意味着我们要从缝隙中删除一个或多个动词,介词,限定词或to这个词。 现在我们已经学会了,如何执行一些自定义的分块和添加缝隙,我们来讨论一下 NLTK 自带的分块形式,这就是命名实体识别。 七、NLTK 命名实体识别 自然语言处理中最主要的分块形式之一被称为“命名实体识别”。 这个想法是让机器立即能够拉出“实体”,例如人物,地点,事物,位置,货币等等。 这可能是一个挑战,但 NLTK 是为我们内置了它。 NLTK 的命名实体识别有两个主要选项:识别所有命名实体,或将命名实体识别为它们各自的类型,如人物,地点,位置等。 这是一个例子: import nltk from nltk.corpus import state_union from nltk.tokenize import PunktSentenceTokenizer train_text = state_union.raw("2005-GWBush.txt") sample_text = state_union.raw("2006-GWBush.txt") custom_sent_tokenizer = PunktSentenceTokenizer(train_text) tokenized = custom_sent_tokenizer.tokenize(sample_text) def process_content(): try: for i in tokenized[5:]: words = nltk.word_tokenize(i) tagged = nltk.pos_tag(words) namedEnt = nltk.ne_chunk(tagged, binary=True) namedEnt.draw() except Exception as e: print(str(e)) process_content() 在这里,选择binary = True,这意味着一个东西要么是命名实体,要么不是。 将不会有进一步的细节。 结果是: 如果你设置了binary = False,结果为: 你可以马上看到一些事情。 当binary是假的时候,它也选取了同样的东西,但是把White House这样的术语分解成White和House,就好像它们是不同的,而我们可以在binary = True的选项中看到,命名实体的识别 说White House是相同命名实体的一部分,这是正确的。 根据你的目标,你可以使用binary选项。 如果您的binary为false,这里是你可以得到的,命名实体的类型: NE Type and Examples ORGANIZATION - Georgia-Pacific Corp., WHO PERSON - Eddy Bonte, President Obama LOCATION - Murray River, Mount Everest DATE - June, 2008-06-29 TIME - two fifty a m, 1:30 p.m. MONEY - 175 million Canadian Dollars, GBP 10.40 PERCENT - twenty pct, 18.75 % FACILITY - Washington Monument, Stonehenge GPE - South East Asia, Midlothian 无论哪种方式,你可能会发现,你需要做更多的工作才能做到恰到好处,但是这个功能非常强大。 在接下来的教程中,我们将讨论类似于词干提取的东西,叫做“词形还原”(lemmatizing)。 八、NLTK 词形还原 与词干提权非常类似的操作称为词形还原。 这两者之间的主要区别是,你之前看到了,词干提权经常可能创造出不存在的词汇,而词形是实际的词汇。 所以,你的词干,也就是你最终得到的词,不是你可以在字典中查找的东西,但你可以查找一个词形。 有时你最后会得到非常相似的词语,但有时候,你会得到完全不同的词语。 我们来看一些例子。 from nltk.stem import WordNetLemmatizer lemmatizer = WordNetLemmatizer() print(lemmatizer.lemmatize("cats")) print(lemmatizer.lemmatize("cacti")) print(lemmatizer.lemmatize("geese")) print(lemmatizer.lemmatize("rocks")) print(lemmatizer.lemmatize("python")) print(lemmatizer.lemmatize("better", pos="a")) print(lemmatizer.lemmatize("best", pos="a")) print(lemmatizer.lemmatize("run")) print(lemmatizer.lemmatize("run",'v')) 在这里,我们有一些我们使用的词的词形的例子。 唯一要注意的是,lemmatize接受词性参数pos。 如果没有提供,默认是“名词”。 这意味着,它将尝试找到最接近的名词,这可能会给你造成麻烦。 如果你使用词形还原,请记住! 在接下来的教程中,我们将深入模块附带的 NTLK 语料库,查看所有优秀文档,他们在那里等待着我们。 九、 NLTK 语料库 在本教程的这一部分,我想花一点时间来深入我们全部下载的语料库! NLTK 语料库是各种自然语言数据集,绝对值得一看。 NLTK 语料库中的几乎所有文件都遵循相同的规则,通过使用 NLTK 模块来访问它们,但是它们没什么神奇的。 这些文件大部分都是纯文本文件,其中一些是 XML 文件,另一些是其他格式文件,但都可以通过手动或模块和 Python 访问。 让我们来谈谈手动查看它们。 根据您的安装,您的nltk_data目录可能隐藏在多个位置。 为了找出它的位置,请转到您的 Python 目录,也就是 NLTK 模块所在的位置。 如果您不知道在哪里,请使用以下代码: import nltk print(nltk.__file__) 运行它,输出将是 NLTK 模块__init__.py的位置。 进入 NLTK 目录,然后查找data.py文件。 代码的重要部分是: if sys.platform.startswith('win'): # Common locations on Windows: path += [ str(r'C:\nltk_data'), str(r'D:\nltk_data'), str(r'E:\nltk_data'), os.path.join(sys.prefix, str('nltk_data')), os.path.join(sys.prefix, str('lib'), str('nltk_data')), os.path.join(os.environ.get(str('APPDATA'), str('C:\\')), str('nltk_data')) ] else: # Common locations on UNIX & OS X: path += [ str('/usr/share/nltk_data'), str('/usr/local/share/nltk_data'), str('/usr/lib/nltk_data'), str('/usr/local/lib/nltk_data') ] 在那里,你可以看到nltk_data的各种可能的目录。 如果你在 Windows 上,它很可能是在你的appdata中,在本地目录中。 为此,你需要打开你的文件浏览器,到顶部,然后输入%appdata%。 接下来点击roaming,然后找到nltk_data目录。 在那里,你将找到你的语料库文件。 完整的路径是这样的: C:\Users\yourname\AppData\Roaming\nltk_data\corpora 在这里,你有所有可用的语料库,包括书籍,聊天记录,电影评论等等。 现在,我们将讨论通过 NLTK 访问这些文档。 正如你所看到的,这些主要是文本文档,所以你可以使用普通的 Python 代码来打开和阅读文档。 也就是说,NLTK 模块有一些很好的处理语料库的方法,所以你可能会发现使用他们的方法是实用的。 下面是我们打开“古腾堡圣经”,并阅读前几行的例子: from nltk.tokenize import sent_tokenize, PunktSentenceTokenizer from nltk.corpus import gutenberg # sample text sample = gutenberg.raw("bible-kjv.txt") tok = sent_tokenize(sample) for x in range(5): print(tok[x]) 其中一个更高级的数据集是wordnet。 Wordnet 是一个单词,定义,他们使用的例子,同义词,反义词,等等的集合。 接下来我们将深入使用 wordnet。 十、 NLTK 和 Wordnet WordNet 是英语的词汇数据库,由普林斯顿创建,是 NLTK 语料库的一部分。 您可以一起使用 WordNet 和 NLTK 模块来查找单词含义,同义词,反义词等。 我们来介绍一些例子。 首先,你将需要导入wordnet: from nltk.corpus import wordnet 之后我们打算使用单词program来寻找同义词: syns = wordnet.synsets("program") 一个同义词的例子: print(syns[0].name()) # plan.n.01 只是单词: print(syns[0].lemmas()[0].name()) # plan 第一个同义词的定义: print(syns[0].definition()) # a series of steps to be carried out or goals to be accomplished 单词的使用示例: print(syns[0].examples()) # ['they drew up a six-step plan', 'they discussed plans for a new bond issue'] 接下来,我们如何辨别一个词的同义词和反义词? 这些词形是同义词,然后你可以使用.antonyms找到词形的反义词。 因此,我们可以填充一些列表,如: synonyms = [] antonyms = [] for syn in wordnet.synsets("good"): for l in syn.lemmas(): synonyms.append(l.name()) if l.antonyms(): antonyms.append(l.antonyms()[0].name()) print(set(synonyms)) print(set(antonyms)) ''' {'beneficial', 'just', 'upright', 'thoroughly', 'in_force', 'well', 'skilful', 'skillful', 'sound', 'unspoiled', 'expert', 'proficient', 'in_effect', 'honorable', 'adept', 'secure', 'commodity', 'estimable', 'soundly', 'right', 'respectable', 'good', 'serious', 'ripe', 'salutary', 'dear', 'practiced', 'goodness', 'safe', 'effective', 'unspoilt', 'dependable', 'undecomposed', 'honest', 'full', 'near', 'trade_good'} {'evil', 'evilness', 'bad', 'badness', 'ill'} ''' 你可以看到,我们的同义词比反义词更多,因为我们只是查找了第一个词形的反义词,但是你可以很容易地平衡这个,通过也为bad这个词执行完全相同的过程。 接下来,我们还可以很容易地使用 WordNet 来比较两个词的相似性和他们的时态,把 Wu 和 Palmer 方法结合起来用于语义相关性。 我们来比较名词ship和boat: w1 = wordnet.synset('ship.n.01') w2 = wordnet.synset('boat.n.01') print(w1.wup_similarity(w2)) # 0.9090909090909091 w1 = wordnet.synset('ship.n.01') w2 = wordnet.synset('car.n.01') print(w1.wup_similarity(w2)) # 0.6956521739130435 w1 = wordnet.synset('ship.n.01') w2 = wordnet.synset('cat.n.01') print(w1.wup_similarity(w2)) # 0.38095238095238093 接下来,我们将讨论一些问题并开始讨论文本分类的主题。 十一、NLTK 文本分类 现在我们熟悉 NLTK 了,我们来尝试处理文本分类。 文本分类的目标可能相当宽泛。 也许我们试图将文本分类为政治或军事。 也许我们试图按照作者的性别来分类。 一个相当受欢迎的文本分类任务是,将文本的正文识别为垃圾邮件或非垃圾邮件,例如电子邮件过滤器。 在我们的例子中,我们将尝试创建一个情感分析算法。 为此,我们首先尝试使用属于 NLTK 语料库的电影评论数据库。 从那里,我们将尝试使用词汇作为“特征”,这是“正面”或“负面”电影评论的一部分。 NLTK 语料库movie_reviews数据集拥有评论,他们被标记为正面或负面。 这意味着我们可以训练和测试这些数据。 首先,让我们来预处理我们的数据。 import nltk import random from nltk.corpus import movie_reviews documents = [(list(movie_reviews.words(fileid)), category) for category in movie_reviews.categories() for fileid in movie_reviews.fileids(category)] random.shuffle(documents) print(documents[1]) all_words = [] for w in movie_reviews.words(): all_words.append(w.lower()) all_words = nltk.FreqDist(all_words) print(all_words.most_common(15)) print(all_words["stupid"]) 运行此脚本可能需要一些时间,因为电影评论数据集有点大。 我们来介绍一下这里发生的事情。 导入我们想要的数据集后,您会看到: documents = [(list(movie_reviews.words(fileid)), category) for category in movie_reviews.categories() for fileid in movie_reviews.fileids(category)] 基本上,用简单的英文,上面的代码被翻译成:在每个类别(我们有正向和独享),选取所有的文件 ID(每个评论有自己的 ID),然后对文件 ID存储word_tokenized版本(单词列表),后面是一个大列表中的正面或负面标签。 接下来,我们用random来打乱我们的文件。这是因为我们将要进行训练和测试。如果我们把他们按序排列,我们可能会训练所有的负面评论,和一些正面评论,然后在所有正面评论上测试。我们不想这样,所以我们打乱了数据。 然后,为了你能看到你正在使用的数据,我们打印出documents[1],这是一个大列表,其中第一个元素是一列单词,第二个元素是pos或neg标签。 接下来,我们要收集我们找到的所有单词,所以我们可以有一个巨大的典型单词列表。从这里,我们可以执行一个频率分布,然后找出最常见的单词。正如你所看到的,最受欢迎的“词语”其实就是标点符号,the,a等等,但是很快我们就会得到有效词汇。我们打算存储几千个最流行的单词,所以这不应该是一个问题。 print(all_words.most_common(15)) 以上给出了15个最常用的单词。 你也可以通过下面的步骤找出一个单词的出现次数: print(all_words["stupid"]) 接下来,我们开始将我们的单词,储存为正面或负面的电影评论的特征。 十二、使用 NLTK 将单词转换为特征 在本教程中,我们在以前的视频基础上构建,并编撰正面评论和负面评论中的单词的特征列表,来看到正面或负面评论中特定类型单词的趋势。 最初,我们的代码: import nltk import random from nltk.corpus import movie_reviews documents = [(list(movie_reviews.words(fileid)), category) for category in movie_reviews.categories() for fileid in movie_reviews.fileids(category)] random.shuffle(documents) all_words = [] for w in movie_reviews.words(): all_words.append(w.lower()) all_words = nltk.FreqDist(all_words) word_features = list(all_words.keys())[:3000] 几乎和以前一样,只是现在有一个新的变量,word_features,它包含了前 3000 个最常用的单词。 接下来,我们将建立一个简单的函数,在我们的正面和负面的文档中找到这些前 3000 个单词,将他们的存在标记为是或否: def find_features(document): words = set(document) features = {} for w in word_features: features[w] = (w in words) return features 下面,我们可以打印出特征集: print((find_features(movie_reviews.words('neg/cv000_29416.txt')))) 之后我们可以为我们所有的文档做这件事情,通过做下列事情,保存特征存在性布尔值,以及它们各自的正面或负面的类别: featuresets = [(find_features(rev), category) for (rev, category) in documents] 真棒,现在我们有了特征和标签,接下来是什么? 通常,下一步是继续并训练算法,然后对其进行测试。 所以,让我们继续这样做,从下一个教程中的朴素贝叶斯分类器开始! 十三、NLTK 朴素贝叶斯分类器 现在是时候选择一个算法,将我们的数据分成训练和测试集,然后启动!我们首先要使用的算法是朴素贝叶斯分类器。这是一个非常受欢迎的文本分类算法,所以我们只能先试一试。然而,在我们可以训练和测试我们的算法之前,我们需要先把数据分解成训练集和测试集。 你可以训练和测试同一个数据集,但是这会给你带来一些严重的偏差问题,所以你不应该训练和测试完全相同的数据。为此,由于我们已经打乱了数据集,因此我们将首先将包含正面和负面评论的 1900 个乱序评论作为训练集。然后,我们可以在最后的 100 个上测试,看看我们有多准确。 这被称为监督机器学习,因为我们正在向机器展示数据,并告诉它“这个数据是正面的”,或者“这个数据是负面的”。然后,在完成训练之后,我们向机器展示一些新的数据,并根据我们之前教过计算机的内容询问计算机,计算机认为新数据的类别是什么。 我们可以用以下方式分割数据: # set that we'll train our classifier with training_set = featuresets[:1900] # set that we'll test against. testing_set = featuresets[1900:] 下面,我们可以定义并训练我们的分类器: classifier = nltk.NaiveBayesClassifier.train(training_set) 首先,我们只是简单调用朴素贝叶斯分类器,然后在一行中使用.train()进行训练。 足够简单,现在它得到了训练。 接下来,我们可以测试它: print("Classifier accuracy percent:",(nltk.classify.accuracy(classifier, testing_set))*100) 砰,你得到了你的答案。 如果你错过了,我们可以“测试”数据的原因是,我们仍然有正确的答案。 因此,在测试中,我们向计算机展示数据,而不提供正确的答案。 如果它正确猜测我们所知的答案,那么计算机是正确的。 考虑到我们所做的打乱,你和我可能准确度不同,但你应该看到准确度平均为 60-75%。 接下来,我们可以进一步了解正面或负面评论中最有价值的词汇: classifier.show_most_informative_features(15) 这对于每个人都不一样,但是你应该看到这样的东西: Most Informative Features insulting = True neg : pos = 10.6 : 1.0 ludicrous = True neg : pos = 10.1 : 1.0 winslet = True pos : neg = 9.0 : 1.0 detract = True pos : neg = 8.4 : 1.0 breathtaking = True pos : neg = 8.1 : 1.0 silverstone = True neg : pos = 7.6 : 1.0 excruciatingly = True neg : pos = 7.6 : 1.0 warns = True pos : neg = 7.0 : 1.0 tracy = True pos : neg = 7.0 : 1.0 insipid = True neg : pos = 7.0 : 1.0 freddie = True neg : pos = 7.0 : 1.0 damon = True pos : neg = 5.9 : 1.0 debate = True pos : neg = 5.9 : 1.0 ordered = True pos : neg = 5.8 : 1.0 lang = True pos : neg = 5.7 : 1.0 这个告诉你的是,每一个词的负面到正面的出现几率,或相反。 因此,在这里,我们可以看到,负面评论中的insulting一词比正面评论多出现 10.6 倍。Ludicrous是 10.1。 现在,让我们假设,你完全满意你的结果,你想要继续,也许使用这个分类器来预测现在的事情。 训练分类器,并且每当你需要使用分类器时,都要重新训练,是非常不切实际的。 因此,您可以使用pickle模块保存分类器。 我们接下来做。 十四、使用 NLTK 保存分类器 训练分类器和机器学习算法可能需要很长时间,特别是如果您在更大的数据集上训练。 我们的其实很小。 你可以想象,每次你想开始使用分类器的时候,都要训练分类器吗? 这么恐怖! 相反,我们可以使用pickle模块,并序列化我们的分类器对象,这样我们所需要做的就是简单加载该文件。 那么,我们该怎么做呢? 第一步是保存对象。 为此,首先需要在脚本的顶部导入pickle,然后在使用.train()分类器进行训练后,可以调用以下几行: save_classifier = open("naivebayes.pickle","wb") pickle.dump(classifier, save_classifier) save_classifier.close() 这打开了一个pickle文件,准备按字节写入一些数据。 然后,我们使用pickle.dump()来转储数据。 pickle.dump()的第一个参数是你写入的东西,第二个参数是你写入它的地方。 之后,我们按照我们的要求关闭文件,这就是说,我们现在在脚本的目录中保存了一个pickle或序列化的对象! 接下来,我们如何开始使用这个分类器? .pickle文件是序列化的对象,我们现在需要做的就是将其读入内存,这与读取任何其他普通文件一样简单。 这样做: classifier_f = open("naivebayes.pickle", "rb") classifier = pickle.load(classifier_f) classifier_f.close() 在这里,我们执行了非常相似的过程。 我们打开文件来读取字节。 然后,我们使用pickle.load()来加载文件,并将数据保存到分类器变量中。 然后我们关闭文件,就是这样。 我们现在有了和以前一样的分类器对象! 现在,我们可以使用这个对象,每当我们想用它来分类时,我们不再需要训练我们的分类器。 虽然这一切都很好,但是我们可能不太满意我们所获得的 60-75% 的准确度。 其他分类器呢? 其实,有很多分类器,但我们需要 scikit-learn(sklearn)模块。 幸运的是,NLTK 的员工认识到将 sklearn 模块纳入 NLTK 的价值,他们为我们构建了一个小 API。 这就是我们将在下一个教程中做的事情。 十五、NLTK 和 Sklearn 现在我们已经看到,使用分类器是多么容易,现在我们想尝试更多东西! Python 的最好的模块是 Scikit-learn(sklearn)模块。 如果您想了解 Scikit-learn 模块的更多信息,我有一些关于 Scikit-Learn 机器学习的教程。 幸运的是,对于我们来说,NLTK 背后的人们更看重将 sklearn 模块纳入NLTK分类器方法的价值。 就这样,他们创建了各种SklearnClassifier API。 要使用它,你只需要像下面这样导入它: from nltk.classify.scikitlearn import SklearnClassifier 从这里开始,你可以使用任何sklearn分类器。 例如,让我们引入更多的朴素贝叶斯算法的变体: from sklearn.naive_bayes import MultinomialNB,BernoulliNB 之后,如何使用它们?结果是,这非常简单。 MNB_classifier = SklearnClassifier(MultinomialNB()) MNB_classifier.train(training_set) print("MultinomialNB accuracy percent:",nltk.classify.accuracy(MNB_classifier, testing_set)) BNB_classifier = SklearnClassifier(BernoulliNB()) BNB_classifier.train(training_set) print("BernoulliNB accuracy percent:",nltk.classify.accuracy(BNB_classifier, testing_set)) 就是这么简单。让我们引入更多东西: from sklearn.linear_model import LogisticRegression,SGDClassifier from sklearn.svm import SVC, LinearSVC, NuSVC 现在,我们所有分类器应该是这样: print("Original Naive Bayes Algo accuracy percent:", (nltk.classify.accuracy(classifier, testing_set))*100) classifier.show_most_informative_features(15) MNB_classifier = SklearnClassifier(MultinomialNB()) MNB_classifier.train(training_set) print("MNB_classifier accuracy percent:", (nltk.classify.accuracy(MNB_classifier, testing_set))*100) BernoulliNB_classifier = SklearnClassifier(BernoulliNB()) BernoulliNB_classifier.train(training_set) print("BernoulliNB_classifier accuracy percent:", (nltk.classify.accuracy(BernoulliNB_classifier, testing_set))*100) LogisticRegression_classifier = SklearnClassifier(LogisticRegression()) LogisticRegression_classifier.train(training_set) print("LogisticRegression_classifier accuracy percent:", (nltk.classify.accuracy(LogisticRegression_classifier, testing_set))*100) SGDClassifier_classifier = SklearnClassifier(SGDClassifier()) SGDClassifier_classifier.train(training_set) print("SGDClassifier_classifier accuracy percent:", (nltk.classify.accuracy(SGDClassifier_classifier, testing_set))*100) SVC_classifier = SklearnClassifier(SVC()) SVC_classifier.train(training_set) print("SVC_classifier accuracy percent:", (nltk.classify.accuracy(SVC_classifier, testing_set))*100) LinearSVC_classifier = SklearnClassifier(LinearSVC()) LinearSVC_classifier.train(training_set) print("LinearSVC_classifier accuracy percent:", (nltk.classify.accuracy(LinearSVC_classifier, testing_set))*100) NuSVC_classifier = SklearnClassifier(NuSVC()) NuSVC_classifier.train(training_set) print("NuSVC_classifier accuracy percent:", (nltk.classify.accuracy(NuSVC_classifier, testing_set))*100) 运行它的结果应该是这样: Original Naive Bayes Algo accuracy percent: 63.0 Most Informative Features thematic = True pos : neg = 9.1 : 1.0 secondly = True pos : neg = 8.5 : 1.0 narrates = True pos : neg = 7.8 : 1.0 rounded = True pos : neg = 7.1 : 1.0 supreme = True pos : neg = 7.1 : 1.0 layered = True pos : neg = 7.1 : 1.0 crappy = True neg : pos = 6.9 : 1.0 uplifting = True pos : neg = 6.2 : 1.0 ugh = True neg : pos = 5.3 : 1.0 mamet = True pos : neg = 5.1 : 1.0 gaining = True pos : neg = 5.1 : 1.0 wanda = True neg : pos = 4.9 : 1.0 onset = True neg : pos = 4.9 : 1.0 fantastic = True pos : neg = 4.5 : 1.0 kentucky = True pos : neg = 4.4 : 1.0 MNB_classifier accuracy percent: 66.0 BernoulliNB_classifier accuracy percent: 72.0 LogisticRegression_classifier accuracy percent: 64.0 SGDClassifier_classifier accuracy percent: 61.0 SVC_classifier accuracy percent: 45.0 LinearSVC_classifier accuracy percent: 68.0 NuSVC_classifier accuracy percent: 59.0 所以,我们可以看到,SVC 的错误比正确更常见,所以我们可能应该丢弃它。 但是呢? 接下来我们可以尝试一次使用所有这些算法。 一个算法的算法! 为此,我们可以创建另一个分类器,并根据其他算法的结果来生成分类器的结果。 有点像投票系统,所以我们只需要奇数数量的算法。 这就是我们将在下一个教程中讨论的内容。 十六、使用 NLTK 组合算法 现在我们知道如何使用一堆算法分类器,就像糖果岛上的一个孩子,告诉他们只能选择一个,我们可能会发现很难只选择一个分类器。 好消息是,你不必这样! 组合分类器算法是一种常用的技术,通过创建一种投票系统来实现,每个算法拥有一票,选择得票最多分类。 为此,我们希望我们的新分类器的工作方式像典型的 NLTK 分类器,并拥有所有方法。 很简单,使用面向对象编程,我们可以确保从 NLTK 分类器类继承。 为此,我们将导入它: from nltk.classify import ClassifierI from statistics import mode 我们也导入mode(众数),因为这将是我们选择最大计数的方法。 现在,我们来建立我们的分类器类: class VoteClassifier(ClassifierI): def __init__(self, *classifiers): self._classifiers = classifiers 我们把我们的类叫做VoteClassifier,我们继承了 NLTK 的ClassifierI。 接下来,我们将传递给我们的类的分类器列表赋给self._classifiers。 接下来,我们要继续创建我们自己的分类方法。 我们打算把它称为.classify,以便我们可以稍后调用.classify,就像传统的 NLTK 分类器那样。 def classify(self, features): votes = [] for c in self._classifiers: v = c.classify(features) votes.append(v) return mode(votes) 很简单,我们在这里所做的就是,遍历我们的分类器对象列表。 然后,对于每一个,我们要求它基于特征分类。 分类被视为投票。 遍历完成后,我们返回mode(votes),这只是返回投票的众数。 这是我们真正需要的,但是我认为另一个参数,置信度是有用的。 由于我们有了投票算法,所以我们也可以统计支持和反对票数,并称之为“置信度”。 例如,3/5 票的置信度弱于 5/5 票。 因此,我们可以从字面上返回投票比例,作为一种置信度指标。 这是我们的置信度方法: def confidence(self, features): votes = [] for c in self._classifiers: v = c.classify(features) votes.append(v) choice_votes = votes.count(mode(votes)) conf = choice_votes / len(votes) return conf 现在,让我们把东西放到一起: import nltk import random from nltk.corpus import movie_reviews from nltk.classify.scikitlearn import SklearnClassifier import pickle from sklearn.naive_bayes import MultinomialNB, BernoulliNB from sklearn.linear_model import LogisticRegression, SGDClassifier from sklearn.svm import SVC, LinearSVC, NuSVC from nltk.classify import ClassifierI from statistics import mode class VoteClassifier(ClassifierI): def __init__(self, *classifiers): self._classifiers = classifiers def classify(self, features): votes = [] for c in self._classifiers: v = c.classify(features) votes.append(v) return mode(votes) def confidence(self, features): votes = [] for c in self._classifiers: v = c.classify(features) votes.append(v) choice_votes = votes.count(mode(votes)) conf = choice_votes / len(votes) return conf documents = [(list(movie_reviews.words(fileid)), category) for category in movie_reviews.categories() for fileid in movie_reviews.fileids(category)] random.shuffle(documents) all_words = [] for w in movie_reviews.words(): all_words.append(w.lower()) all_words = nltk.FreqDist(all_words) word_features = list(all_words.keys())[:3000] def find_features(document): words = set(document) features = {} for w in word_features: features[w] = (w in words) return features #print((find_features(movie_reviews.words('neg/cv000_29416.txt')))) featuresets = [(find_features(rev), category) for (rev, category) in documents] training_set = featuresets[:1900] testing_set = featuresets[1900:] #classifier = nltk.NaiveBayesClassifier.train(training_set) classifier_f = open("naivebayes.pickle","rb") classifier = pickle.load(classifier_f) classifier_f.close() print("Original Naive Bayes Algo accuracy percent:", (nltk.classify.accuracy(classifier, testing_set))*100) classifier.show_most_informative_features(15) MNB_classifier = SklearnClassifier(MultinomialNB()) MNB_classifier.train(training_set) print("MNB_classifier accuracy percent:", (nltk.classify.accuracy(MNB_classifier, testing_set))*100) BernoulliNB_classifier = SklearnClassifier(BernoulliNB()) BernoulliNB_classifier.train(training_set) print("BernoulliNB_classifier accuracy percent:", (nltk.classify.accuracy(BernoulliNB_classifier, testing_set))*100) LogisticRegression_classifier = SklearnClassifier(LogisticRegression()) LogisticRegression_classifier.train(training_set) print("LogisticRegression_classifier accuracy percent:", (nltk.classify.accuracy(LogisticRegression_classifier, testing_set))*100) SGDClassifier_classifier = SklearnClassifier(SGDClassifier()) SGDClassifier_classifier.train(training_set) print("SGDClassifier_classifier accuracy percent:", (nltk.classify.accuracy(SGDClassifier_classifier, testing_set))*100) ##SVC_classifier = SklearnClassifier(SVC()) ##SVC_classifier.train(training_set) ##print("SVC_classifier accuracy percent:", (nltk.classify.accuracy(SVC_classifier, testing_set))*100) LinearSVC_classifier = SklearnClassifier(LinearSVC()) LinearSVC_classifier.train(training_set) print("LinearSVC_classifier accuracy percent:", (nltk.classify.accuracy(LinearSVC_classifier, testing_set))*100) NuSVC_classifier = SklearnClassifier(NuSVC()) NuSVC_classifier.train(training_set) print("NuSVC_classifier accuracy percent:", (nltk.classify.accuracy(NuSVC_classifier, testing_set))*100) voted_classifier = VoteClassifier(classifier, NuSVC_classifier, LinearSVC_classifier, SGDClassifier_classifier, MNB_classifier, BernoulliNB_classifier, LogisticRegression_classifier) print("voted_classifier accuracy percent:", (nltk.classify.accuracy(voted_classifier, testing_set))*100) print("Classification:", voted_classifier.classify(testing_set[0][0]), "Confidence %:",voted_classifier.confidence(testing_set[0][0])*100) print("Classification:", voted_classifier.classify(testing_set[1][0]), "Confidence %:",voted_classifier.confidence(testing_set[1][0])*100) print("Classification:", voted_classifier.classify(testing_set[2][0]), "Confidence %:",voted_classifier.confidence(testing_set[2][0])*100) print("Classification:", voted_classifier.classify(testing_set[3][0]), "Confidence %:",voted_classifier.confidence(testing_set[3][0])*100) print("Classification:", voted_classifier.classify(testing_set[4][0]), "Confidence %:",voted_classifier.confidence(testing_set[4][0])*100) print("Classification:", voted_classifier.classify(testing_set[5][0]), "Confidence %:",voted_classifier.confidence(testing_set[5][0])*100) 所以到了最后,我们对文本运行一些分类器示例。我们所有输出: Original Naive Bayes Algo accuracy percent: 66.0 Most Informative Features thematic = True pos : neg = 9.1 : 1.0 secondly = True pos : neg = 8.5 : 1.0 narrates = True pos : neg = 7.8 : 1.0 layered = True pos : neg = 7.1 : 1.0 rounded = True pos : neg = 7.1 : 1.0 supreme = True pos : neg = 7.1 : 1.0 crappy = True neg : pos = 6.9 : 1.0 uplifting = True pos : neg = 6.2 : 1.0 ugh = True neg : pos = 5.3 : 1.0 gaining = True pos : neg = 5.1 : 1.0 mamet = True pos : neg = 5.1 : 1.0 wanda = True neg : pos = 4.9 : 1.0 onset = True neg : pos = 4.9 : 1.0 fantastic = True pos : neg = 4.5 : 1.0 milos = True pos : neg = 4.4 : 1.0 MNB_classifier accuracy percent: 67.0 BernoulliNB_classifier accuracy percent: 67.0 LogisticRegression_classifier accuracy percent: 68.0 SGDClassifier_classifier accuracy percent: 57.99999999999999 LinearSVC_classifier accuracy percent: 67.0 NuSVC_classifier accuracy percent: 65.0 voted_classifier accuracy percent: 65.0 Classification: neg Confidence %: 100.0 Classification: pos Confidence %: 57.14285714285714 Classification: neg Confidence %: 57.14285714285714 Classification: neg Confidence %: 57.14285714285714 Classification: pos Confidence %: 57.14285714285714 Classification: pos Confidence %: 85.71428571428571 十七、使用 NLTK 调查偏差 在本教程中,我们将讨论一些问题。最主要的问题是我们有一个相当有偏差的算法。你可以通过注释掉文档的打乱,然后使用前 1900 个进行训练,并留下最后的 100 个(所有正面)评论来测试它。测试它,你会发现你的准确性很差。 相反,你可以使用前 100 个数据进行测试,所有的数据都是负面的,并且使用后 1900 个训练。在这里你会发现准确度非常高。这是一个不好的迹象。这可能意味着很多东西,我们有很多选择来解决它。 也就是说,我们所考虑的项目建议我们继续,并使用不同的数据集,所以我们会这样做。最后,我们会发现这个新的数据集仍然存在一些偏差,那就是它更经常选择负面的东西。原因是负面评论的负面往往比正面评论的正面程度更大。这个可以用一些简单的加权来完成,但是它也可以变得很复杂。也许是另一天的教程。现在,我们要抓取一个新的数据集,我们将在下一个教程中讨论这个数据集。 十八、使用 NLTK 改善情感分析的训练数据 所以现在是时候在新的数据集上训练了。 我们的目标是分析 Twitter 的情绪,所以我们希望数据集的每个正面和负面语句都有点短。 恰好我有 5300+ 个正面和 5300 + 个负面电影评论,这是短得多的数据集。 我们应该能从更大的训练集中获得更多的准确性,并且把 Twitter 的推文拟合得更好。 我在这里托管了这两个文件,您可以通过下载简短的评论来找到它们。 将这些文件保存为positive.txt和negative.txt。 现在,我们可以像以前一样建立新的数据集。 需要改变什么呢? 我们需要一种新的方法来创建我们的“文档”变量,然后我们还需要一种新的方法来创建all_words变量。 真的没问题,我是这么做的: short_pos = open("short_reviews/positive.txt","r").read() short_neg = open("short_reviews/negative.txt","r").read() documents = [] for r in short_pos.split('\n'): documents.append( (r, "pos") ) for r in short_neg.split('\n'): documents.append( (r, "neg") ) all_words = [] short_pos_words = word_tokenize(short_pos) short_neg_words = word_tokenize(short_neg) for w in short_pos_words: all_words.append(w.lower()) for w in short_neg_words: all_words.append(w.lower()) all_words = nltk.FreqDist(all_words) 接下来,我们还需要调整我们的特征查找功能,主要是按照文档中的单词进行标记,因为我们的新样本没有漂亮的.words()特征。 我继续并增加了最常见的词语: word_features = list(all_words.keys())[:5000] def find_features(document): words = word_tokenize(document) features = {} for w in word_features: features[w] = (w in words) return features featuresets = [(find_features(rev), category) for (rev, category) in documents] random.shuffle(featuresets) 除此之外,其余的都是一样的。 这是完整的脚本,以防万一你或我错过了一些东西: 这个过程需要一段时间..你可能想要干些别的。 我花了大约 30-40 分钟来全部运行完成,而我在 i7 3930k 上运行它。 在我写这篇文章的时候(2015),一般处理器可能需要几个小时。 不过这是一次性的过程。 import nltk import random from nltk.corpus import movie_reviews from nltk.classify.scikitlearn import SklearnClassifier import pickle from sklearn.naive_bayes import MultinomialNB, BernoulliNB from sklearn.linear_model import LogisticRegression, SGDClassifier from sklearn.svm import SVC, LinearSVC, NuSVC from nltk.classify import ClassifierI from statistics import mode from nltk.tokenize import word_tokenize class VoteClassifier(ClassifierI): def __init__(self, *classifiers): self._classifiers = classifiers def classify(self, features): votes = [] for c in self._classifiers: v = c.classify(features) votes.append(v) return mode(votes) def confidence(self, features): votes = [] for c in self._classifiers: v = c.classify(features) votes.append(v) choice_votes = votes.count(mode(votes)) conf = choice_votes / len(votes) return conf short_pos = open("short_reviews/positive.txt","r").read() short_neg = open("short_reviews/negative.txt","r").read() documents = [] for r in short_pos.split('\n'): documents.append( (r, "pos") ) for r in short_neg.split('\n'): documents.append( (r, "neg") ) all_words = [] short_pos_words = word_tokenize(short_pos) short_neg_words = word_tokenize(short_neg) for w in short_pos_words: all_words.append(w.lower()) for w in short_neg_words: all_words.append(w.lower()) all_words = nltk.FreqDist(all_words) word_features = list(all_words.keys())[:5000] def find_features(document): words = word_tokenize(document) features = {} for w in word_features: features[w] = (w in words) return features #print((find_features(movie_reviews.words('neg/cv000_29416.txt')))) featuresets = [(find_features(rev), category) for (rev, category) in documents] random.shuffle(featuresets) # positive data example: training_set = featuresets[:10000] testing_set = featuresets[10000:] ## ### negative data example: ##training_set = featuresets[100:] ##testing_set = featuresets[:100] classifier = nltk.NaiveBayesClassifier.train(training_set) print("Original Naive Bayes Algo accuracy percent:", (nltk.classify.accuracy(classifier, testing_set))*100) classifier.show_most_informative_features(15) MNB_classifier = SklearnClassifier(MultinomialNB()) MNB_classifier.train(training_set) print("MNB_classifier accuracy percent:", (nltk.classify.accuracy(MNB_classifier, testing_set))*100) BernoulliNB_classifier = SklearnClassifier(BernoulliNB()) BernoulliNB_classifier.train(training_set) print("BernoulliNB_classifier accuracy percent:", (nltk.classify.accuracy(BernoulliNB_classifier, testing_set))*100) LogisticRegression_classifier = SklearnClassifier(LogisticRegression()) LogisticRegression_classifier.train(training_set) print("LogisticRegression_classifier accuracy percent:", (nltk.classify.accuracy(LogisticRegression_classifier, testing_set))*100) SGDClassifier_classifier = SklearnClassifier(SGDClassifier()) SGDClassifier_classifier.train(training_set) print("SGDClassifier_classifier accuracy percent:", (nltk.classify.accuracy(SGDClassifier_classifier, testing_set))*100) ##SVC_classifier = SklearnClassifier(SVC()) ##SVC_classifier.train(training_set) ##print("SVC_classifier accuracy percent:", (nltk.classify.accuracy(SVC_classifier, testing_set))*100) LinearSVC_classifier = SklearnClassifier(LinearSVC()) LinearSVC_classifier.train(training_set) print("LinearSVC_classifier accuracy percent:", (nltk.classify.accuracy(LinearSVC_classifier, testing_set))*100) NuSVC_classifier = SklearnClassifier(NuSVC()) NuSVC_classifier.train(training_set) print("NuSVC_classifier accuracy percent:", (nltk.classify.accuracy(NuSVC_classifier, testing_set))*100) voted_classifier = VoteClassifier( NuSVC_classifier, LinearSVC_classifier, MNB_classifier, BernoulliNB_classifier, LogisticRegression_classifier) print("voted_classifier accuracy percent:", (nltk.classify.accuracy(voted_classifier, testing_set))*100) 输出: Original Naive Bayes Algo accuracy percent: 66.26506024096386 Most Informative Features refreshing = True pos : neg = 13.6 : 1.0 captures = True pos : neg = 11.3 : 1.0 stupid = True neg : pos = 10.7 : 1.0 tender = True pos : neg = 9.6 : 1.0 meandering = True neg : pos = 9.1 : 1.0 tv = True neg : pos = 8.6 : 1.0 low-key = True pos : neg = 8.3 : 1.0 thoughtful = True pos : neg = 8.1 : 1.0 banal = True neg : pos = 7.7 : 1.0 amateurish = True neg : pos = 7.7 : 1.0 terrific = True pos : neg = 7.6 : 1.0 record = True pos : neg = 7.6 : 1.0 captivating = True pos : neg = 7.6 : 1.0 portrait = True pos : neg = 7.4 : 1.0 culture = True pos : neg = 7.3 : 1.0 MNB_classifier accuracy percent: 65.8132530120482 BernoulliNB_classifier accuracy percent: 66.71686746987952 LogisticRegression_classifier accuracy percent: 67.16867469879519 SGDClassifier_classifier accuracy percent: 65.8132530120482 LinearSVC_classifier accuracy percent: 66.71686746987952 NuSVC_classifier accuracy percent: 60.09036144578314 voted_classifier accuracy percent: 65.66265060240963 是的,我敢打赌你花了一段时间,所以,在下一个教程中,我们将谈论pickle所有东西! 十九、使用 NLTK 为情感分析创建模块 有了这个新的数据集和新的分类器,我们可以继续前进。 你可能已经注意到的,这个新的数据集需要更长的时间来训练,因为它是一个更大的集合。 我已经向你显示,通过pickel或序列化训练出来的分类器,我们实际上可以节省大量的时间,这些分类器只是对象。 我已经向你证明了如何使用pickel来实现它,所以我鼓励你尝试自己做。 如果你需要帮助,我会粘贴完整的代码…但要注意,自己动手! 这个过程需要一段时间..你可能想要干些别的。 我花了大约 30-40 分钟来全部运行完成,而我在 i7 3930k 上运行它。 在我写这篇文章的时候(2015),一般处理器可能需要几个小时。 不过这是一次性的过程。 import nltk import random #from nltk.corpus import movie_reviews from nltk.classify.scikitlearn import SklearnClassifier import pickle from sklearn.naive_bayes import MultinomialNB, BernoulliNB from sklearn.linear_model import LogisticRegression, SGDClassifier from sklearn.svm import SVC, LinearSVC, NuSVC from nltk.classify import ClassifierI from statistics import mode from nltk.tokenize import word_tokenize class VoteClassifier(ClassifierI): def __init__(self, *classifiers): self._classifiers = classifiers def classify(self, features): votes = [] for c in self._classifiers: v = c.classify(features) votes.append(v) return mode(votes) def confidence(self, features): votes = [] for c in self._classifiers: v = c.classify(features) votes.append(v) choice_votes = votes.count(mode(votes)) conf = choice_votes / len(votes) return conf short_pos = open("short_reviews/positive.txt","r").read() short_neg = open("short_reviews/negative.txt","r").read() # move this up here all_words = [] documents = [] # j is adject, r is adverb, and v is verb #allowed_word_types = ["J","R","V"] allowed_word_types = ["J"] for p in short_pos.split('\n'): documents.append( (p, "pos") ) words = word_tokenize(p) pos = nltk.pos_tag(words) for w in pos: if w[1][0] in allowed_word_types: all_words.append(w[0].lower()) for p in short_neg.split('\n'): documents.append( (p, "neg") ) words = word_tokenize(p) pos = nltk.pos_tag(words) for w in pos: if w[1][0] in allowed_word_types: all_words.append(w[0].lower()) save_documents = open("pickled_algos/documents.pickle","wb") pickle.dump(documents, save_documents) save_documents.close() all_words = nltk.FreqDist(all_words) word_features = list(all_words.keys())[:5000] save_word_features = open("pickled_algos/word_features5k.pickle","wb") pickle.dump(word_features, save_word_features) save_word_features.close() def find_features(document): words = word_tokenize(document) features = {} for w in word_features: features[w] = (w in words) return features featuresets = [(find_features(rev), category) for (rev, category) in documents] random.shuffle(featuresets) print(len(featuresets)) testing_set = featuresets[10000:] training_set = featuresets[:10000] classifier = nltk.NaiveBayesClassifier.train(training_set) print("Original Naive Bayes Algo accuracy percent:", (nltk.classify.accuracy(classifier, testing_set))*100) classifier.show_most_informative_features(15) ############### save_classifier = open("pickled_algos/originalnaivebayes5k.pickle","wb") pickle.dump(classifier, save_classifier) save_classifier.close() MNB_classifier = SklearnClassifier(MultinomialNB()) MNB_classifier.train(training_set) print("MNB_classifier accuracy percent:", (nltk.classify.accuracy(MNB_classifier, testing_set))*100) save_classifier = open("pickled_algos/MNB_classifier5k.pickle","wb") pickle.dump(MNB_classifier, save_classifier) save_classifier.close() BernoulliNB_classifier = SklearnClassifier(BernoulliNB()) BernoulliNB_classifier.train(training_set) print("BernoulliNB_classifier accuracy percent:", (nltk.classify.accuracy(BernoulliNB_classifier, testing_set))*100) save_classifier = open("pickled_algos/BernoulliNB_classifier5k.pickle","wb") pickle.dump(BernoulliNB_classifier, save_classifier) save_classifier.close() LogisticRegression_classifier = SklearnClassifier(LogisticRegression()) LogisticRegression_classifier.train(training_set) print("LogisticRegression_classifier accuracy percent:", (nltk.classify.accuracy(LogisticRegression_classifier, testing_set))*100) save_classifier = open("pickled_algos/LogisticRegression_classifier5k.pickle","wb") pickle.dump(LogisticRegression_classifier, save_classifier) save_classifier.close() LinearSVC_classifier = SklearnClassifier(LinearSVC()) LinearSVC_classifier.train(training_set) print("LinearSVC_classifier accuracy percent:", (nltk.classify.accuracy(LinearSVC_classifier, testing_set))*100) save_classifier = open("pickled_algos/LinearSVC_classifier5k.pickle","wb") pickle.dump(LinearSVC_classifier, save_classifier) save_classifier.close() ##NuSVC_classifier = SklearnClassifier(NuSVC()) ##NuSVC_classifier.train(training_set) ##print("NuSVC_classifier accuracy percent:", (nltk.classify.accuracy(NuSVC_classifier, testing_set))*100) SGDC_classifier = SklearnClassifier(SGDClassifier()) SGDC_classifier.train(training_set) print("SGDClassifier accuracy percent:",nltk.classify.accuracy(SGDC_classifier, testing_set)*100) save_classifier = open("pickled_algos/SGDC_classifier5k.pickle","wb") pickle.dump(SGDC_classifier, save_classifier) save_classifier.close() 现在,你只需要运行一次。 如果你希望,你可以随时运行它,但现在,你已经准备好了创建情绪分析模块。 这是我们称为sentiment_mod.py的文件: #File: sentiment_mod.py import nltk import random #from nltk.corpus import movie_reviews from nltk.classify.scikitlearn import SklearnClassifier import pickle from sklearn.naive_bayes import MultinomialNB, BernoulliNB from sklearn.linear_model import LogisticRegression, SGDClassifier from sklearn.svm import SVC, LinearSVC, NuSVC from nltk.classify import ClassifierI from statistics import mode from nltk.tokenize import word_tokenize class VoteClassifier(ClassifierI): def __init__(self, *classifiers): self._classifiers = classifiers def classify(self, features): votes = [] for c in self._classifiers: v = c.classify(features) votes.append(v) return mode(votes) def confidence(self, features): votes = [] for c in self._classifiers: v = c.classify(features) votes.append(v) choice_votes = votes.count(mode(votes)) conf = choice_votes / len(votes) return conf documents_f = open("pickled_algos/documents.pickle", "rb") documents = pickle.load(documents_f) documents_f.close() word_features5k_f = open("pickled_algos/word_features5k.pickle", "rb") word_features = pickle.load(word_features5k_f) word_features5k_f.close() def find_features(document): words = word_tokenize(document) features = {} for w in word_features: features[w] = (w in words) return features featuresets_f = open("pickled_algos/featuresets.pickle", "rb") featuresets = pickle.load(featuresets_f) featuresets_f.close() random.shuffle(featuresets) print(len(featuresets)) testing_set = featuresets[10000:] training_set = featuresets[:10000] open_file = open("pickled_algos/originalnaivebayes5k.pickle", "rb") classifier = pickle.load(open_file) open_file.close() open_file = open("pickled_algos/MNB_classifier5k.pickle", "rb") MNB_classifier = pickle.load(open_file) open_file.close() open_file = open("pickled_algos/BernoulliNB_classifier5k.pickle", "rb") BernoulliNB_classifier = pickle.load(open_file) open_file.close() open_file = open("pickled_algos/LogisticRegression_classifier5k.pickle", "rb") LogisticRegression_classifier = pickle.load(open_file) open_file.close() open_file = open("pickled_algos/LinearSVC_classifier5k.pickle", "rb") LinearSVC_classifier = pickle.load(open_file) open_file.close() open_file = open("pickled_algos/SGDC_classifier5k.pickle", "rb") SGDC_classifier = pickle.load(open_file) open_file.close() voted_classifier = VoteClassifier( classifier, LinearSVC_classifier, MNB_classifier, BernoulliNB_classifier, LogisticRegression_classifier) def sentiment(text): feats = find_features(text) return voted_classifier.classify(feats),voted_classifier.confidence(feats) 所以在这里,除了最终的函数外,其实并没有什么新东西,这很简单。 这个函数是我们从这里开始与之交互的关键。 这个我们称之为“情感”的函数带有一个参数,即文本。 在这里,我们用我们早已创建的find_features函数,来分解这些特征。 现在我们所要做的就是,使用我们的投票分类器返回分类,以及返回分类的置信度。 有了这个,我们现在可以将这个文件,以及情感函数用作一个模块。 以下是使用该模块的示例脚本: import sentiment_mod as s print(s.sentiment("This movie was awesome! The acting was great, plot was wonderful, and there were pythons...so yea!")) print(s.sentiment("This movie was utter junk. There were absolutely 0 pythons. I don't see what the point was at all. Horrible movie, 0/10")) 正如预期的那样,带有python的电影的评论显然很好,没有任何python的电影是垃圾。 这两个都有 100% 的置信度。 我花了大约 5 秒钟的时间导入模块,因为我们保存了分类器,没有保存的话可能要花 30 分钟。 多亏了pickle 你的时间会有很大的不同,取决于你的处理器。如果你继续下去,我会说你可能也想看看joblib。 现在我们有了这个很棒的模块,它很容易就能工作,我们可以做什么? 我建议我们去 Twitter 上进行实时情感分析! 二十、NLTK Twitter 情感分析 现在我们有一个情感分析模块,我们可以将它应用于任何文本,但最好是短小的文本,比如 Twitter! 为此,我们将把本教程与 Twitter 流式 API 教程结合起来。 该教程的初始代码是: from tweepy import Stream from tweepy import OAuthHandler from tweepy.streaming import StreamListener #consumer key, consumer secret, access token, access secret. ckey="fsdfasdfsafsffa" csecret="asdfsadfsadfsadf" atoken="asdf-aassdfs" asecret="asdfsadfsdafsdafs" class listener(StreamListener): def on_data(self, data): print(data) return(True) def on_error(self, status): print status auth = OAuthHandler(ckey, csecret) auth.set_access_token(atoken, asecret) twitterStream = Stream(auth, listener()) twitterStream.filter(track=["car"]) 这足以打印包含词语car的流式实时推文的所有数据。 我们可以使用json模块,使用json.loads(data)来加载数据变量,然后我们可以引用特定的tweet: tweet = all_data["text"] 既然我们有了一条推文,我们可以轻易将其传入我们的sentiment_mod模块。 from tweepy import Stream from tweepy import OAuthHandler from tweepy.streaming import StreamListener import json import sentiment_mod as s #consumer key, consumer secret, access token, access secret. ckey="asdfsafsafsaf" csecret="asdfasdfsadfsa" atoken="asdfsadfsafsaf-asdfsaf" asecret="asdfsadfsadfsadfsadfsad" from twitterapistuff import * class listener(StreamListener): def on_data(self, data): all_data = json.loads(data) tweet = all_data["text"] sentiment_value, confidence = s.sentiment(tweet) print(tweet, sentiment_value, confidence) if confidence*100 >= 80: output = open("twitter-out.txt","a") output.write(sentiment_value) output.write('\n') output.close() return True def on_error(self, status): print(status) auth = OAuthHandler(ckey, csecret) auth.set_access_token(atoken, asecret) twitterStream = Stream(auth, listener()) twitterStream.filter(track=["happy"]) 除此之外,我们还将结果保存到输出文件twitter-out.txt中。 接下来,什么没有图表的数据分析是完整的? 让我们再结合另一个教程,从 Twitter API 上的情感分析绘制实时流式图。 二十一,使用 NLTK 绘制 Twitter 实时情感分析 现在我们已经从 Twitter 流媒体 API 获得了实时数据,为什么没有显示情绪趋势的活动图呢? 为此,我们将结合本教程和 matplotlib 绘图教程。 如果您想了解代码工作原理的更多信息,请参阅该教程。 否则: import matplotlib.pyplot as plt import matplotlib.animation as animation from matplotlib import style import time style.use("ggplot") fig = plt.figure() ax1 = fig.add_subplot(1,1,1) def animate(i): pullData = open("twitter-out.txt","r").read() lines = pullData.split('\n') xar = [] yar = [] x = 0 y = 0 for l in lines[-200:]: x += 1 if "pos" in l: y += 1 elif "neg" in l: y -= 1 xar.append(x) yar.append(y) ax1.clear() ax1.plot(xar,yar) ani = animation.FuncAnimation(fig, animate, interval=1000) plt.show() 二十二、斯坦福 NER 标记器与命名实体识别 Chuck Dishmon 的客座文章。 斯坦福 NER 标记器提供了 NLTK 的命名实体识别(NER)分类器的替代方案。这个标记器在很大程度上被看作是命名实体识别的标准,但是由于它使用了先进的统计学习算法,它的计算开销比 NLTK 提供的选项更大。 斯坦福 NER 标记器的一大优势是,为我们提供了几种不同的模型来提取命名实体。我们可以使用以下任何一个: 三类模型,用于识别位置,人员和组织 四类模型,用于识别位置,人员,组织和杂项实体 七类模型,识别位置,人员,组织,时间,金钱,百分比和日期 为了继续,我们需要下载模型和jar文件,因为 NER 分类器是用 Java 编写的。这些可从斯坦福自然语言处理小组免费获得。 NTLK 为了使我们方便,NLTK 提供了斯坦福标记器的包装,所以我们可以用最好的语言(当然是 Python)来使用它! 传递给StanfordNERTagger类的参数包括: 分类模型的路径(以下使用三类模型) 斯坦福标记器jar文件的路径 训练数据编码(默认为 ASCII) 以下是我们设置它来使用三类模型标记句子的方式: # -*- coding: utf-8 -*- from nltk.tag import StanfordNERTagger from nltk.tokenize import word_tokenize st = StanfordNERTagger('/usr/share/stanford-ner/classifiers/english.all.3class.distsim.crf.ser.gz', '/usr/share/stanford-ner/stanford-ner.jar', encoding='utf-8') text = 'While in France, Christine Lagarde discussed short-term stimulus efforts in a recent interview with the Wall Street Journal.' tokenized_text = word_tokenize(text) classified_text = st.tag(tokenized_text) print(classified_text) 一旦我们按照单词分词,并且对句子进行分类,我们就会看到标记器产生了如下的元组列表: [('While', 'O'), ('in', 'O'), ('France', 'LOCATION'), (',', 'O'), ('Christine', 'PERSON'), ('Lagarde', 'PERSON'), ('discussed', 'O'), ('short-term', 'O'), ('stimulus', 'O'), ('efforts', 'O'), ('in', 'O'), ('a', 'O'), ('recent', 'O'), ('interview', 'O'), ('with', 'O'), ('the', 'O'), ('Wall', 'ORGANIZATION'), ('Street', 'ORGANIZATION'), ('Journal', 'ORGANIZATION'), ('.', 'O')] 太好了! 每个标记都使用PERSON,LOCATION,ORGANIZATION或O标记(使用我们的三类模型)。 O只代表其他,即非命名的实体。 这个列表现在可以用于测试已标注数据了,我们将在下一个教程中介绍。 二十三、测试 NLTK 和斯坦福 NER 标记器的准确性 Chuck Dishmon 的客座文章。 我们知道了如何使用两个不同的 NER 分类器! 但是我们应该选择哪一个,NLTK 还是斯坦福大学的呢? 让我们做一些测试来找出答案。 我们需要的第一件事是一些已标注的参考数据,用来测试我们的 NER 分类器。 获取这些数据的一种方法是查找大量文章,并将每个标记标记为一种命名实体(例如,人员,组织,位置)或其他非命名实体。 然后我们可以用我们所知的正确标签,来测试我们单独的 NER 分类器。 不幸的是,这是非常耗时的! 好消息是,有一个手动标注的数据集可以免费获得,带有超过 16,000 英语句子。 还有德语,西班牙语,法语,意大利语,荷兰语,波兰语,葡萄牙语和俄语的数据集! 这是一个来自数据集的已标注的句子: Founding O member O Kojima I-PER Minoru I-PER played O guitar O on O Good I-MISC Day I-MISC , O and O Wardanceis I-MISC cover O of O a O song O by O UK I-LOC post O punk O industrial O band O Killing I-ORG Joke I-ORG . O 让我们阅读,分割和操作数据,使其成为用于测试的更好格式。 import nltk from nltk.tag import StanfordNERTagger from nltk.metrics.scores import accuracy raw_annotations = open("/usr/share/wikigold.conll.txt").read() split_annotations = raw_annotations.split() # Amend class annotations to reflect Stanford's NERTagger for n,i in enumerate(split_annotations): if i == "I-PER": split_annotations[n] = "PERSON" if i == "I-ORG": split_annotations[n] = "ORGANIZATION" if i == "I-LOC": split_annotations[n] = "LOCATION" # Group NE data into tuples def group(lst, n): for i in range(0, len(lst), n): val = lst[i:i+n] if len(val) == n: yield tuple(val) reference_annotations = list(group(split_annotations, 2)) 好的,看起来不错! 但是,我们还需要将这些数据的“整洁”形式粘贴到我们的 NER 分类器中。 让我们来做吧。 pure_tokens = split_annotations[::2] 这读入数据,按照空白字符分割,然后以二的增量(从第零个元素开始),取split_annotations中的所有东西的子集。 这产生了一个数据集,类似下面的(小得多)例子: ['Founding', 'member', 'Kojima', 'Minoru', 'played', 'guitar', 'on', 'Good', 'Day', ',', 'and', 'Wardanceis', 'cover', 'of', 'a', 'song', 'by', 'UK', 'post', 'punk', 'industrial', 'band', 'Killing', 'Joke', '.'] 让我们继续并测试 NLTK 分类器: tagged_words = nltk.pos_tag(pure_tokens) nltk_unformatted_prediction = nltk.ne_chunk(tagged_words) 由于 NLTK NER 分类器产生树(包括 POS 标签),我们需要做一些额外的数据操作来获得用于测试的适当形式。 #Convert prediction to multiline string and then to list (includes pos tags) multiline_string = nltk.chunk.tree2conllstr(nltk_unformatted_prediction) listed_pos_and_ne = multiline_string.split() # Delete pos tags and rename del listed_pos_and_ne[1::3] listed_ne = listed_pos_and_ne # Amend class annotations for consistency with reference_annotations for n,i in enumerate(listed_ne): if i == "B-PERSON": listed_ne[n] = "PERSON" if i == "I-PERSON": listed_ne[n] = "PERSON" if i == "B-ORGANIZATION": listed_ne[n] = "ORGANIZATION" if i == "I-ORGANIZATION": listed_ne[n] = "ORGANIZATION" if i == "B-LOCATION": listed_ne[n] = "LOCATION" if i == "I-LOCATION": listed_ne[n] = "LOCATION" if i == "B-GPE": listed_ne[n] = "LOCATION" if i == "I-GPE": listed_ne[n] = "LOCATION" # Group prediction into tuples nltk_formatted_prediction = list(group(listed_ne, 2)) 现在我们可以测试 NLTK 的准确率。 nltk_accuracy = accuracy(reference_annotations, nltk_formatted_prediction) print(nltk_accuracy) 哇,准确率为.8971! 现在让我们测试斯坦福分类器。 由于此分类器以元组形式生成输出,因此测试不需要更多的数据操作。 st = StanfordNERTagger('/usr/share/stanford-ner/classifiers/english.all.3class.distsim.crf.ser.gz', '/usr/share/stanford-ner/stanford-ner.jar', encoding='utf-8') stanford_prediction = st.tag(pure_tokens) stanford_accuracy = accuracy(reference_annotations, stanford_prediction) print(stanford_accuracy) .9223的准确率!更好! 如果你想绘制这个,这里有一些额外的代码。 如果你想深入了解这如何工作,查看 matplotlib 系列: import numpy as np import matplotlib.pyplot as plt from matplotlib import style style.use('fivethirtyeight') N = 1 ind = np.arange(N) # the x locations for the groups width = 0.35 # the width of the bars fig, ax = plt.subplots() stanford_percentage = stanford_accuracy * 100 rects1 = ax.bar(ind, stanford_percentage, width, color='r') nltk_percentage = nltk_accuracy * 100 rects2 = ax.bar(ind+width, nltk_percentage, width, color='y') # add some text for labels, title and axes ticks ax.set_xlabel('Classifier') ax.set_ylabel('Accuracy (by percentage)') ax.set_title('Accuracy by NER Classifier') ax.set_xticks(ind+width) ax.set_xticklabels( ('') ) ax.legend( (rects1[0], rects2[0]), ('Stanford', 'NLTK'), bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0. ) def autolabel(rects): # attach some text labels for rect in rects: height = rect.get_height() ax.text(rect.get_x()+rect.get_width()/2., 1.02*height, '%10.2f' % float(height), ha='center', va='bottom') autolabel(rects1) autolabel(rects2) plt.show() 二十四、测试 NLTK 和斯坦福 NER 标记器的速度 Chuck Dishmon 的客座文章。 我们已经测试了我们的 NER 分类器的准确性,但是在决定使用哪个分类器时,还有更多的问题需要考虑。 接下来我们来测试速度吧! 我们知道我们正在比较同一个东西,我们将在同一篇文章中进行测试。 使用 NBC 新闻里的这个片段吧: House Speaker John Boehner became animated Tuesday over the proposed Keystone Pipeline, castigating the Obama administration for not having approved the project yet. Republican House Speaker John Boehner says there's "nothing complex about the Keystone Pipeline," and that it's time to build it. "Complex? You think the Keystone Pipeline is complex?!" Boehner responded to a questioner. "It's been under study for five years! We build pipelines in America every day. Do you realize there are 200,000 miles of pipelines in the United States?" The speaker went on: "And the only reason the president's involved in the Keystone Pipeline is because it crosses an international boundary. Listen, we can build it. There's nothing complex about the Keystone Pipeline -- it's time to build it." Boehner said the president had no excuse at this point to not give the pipeline the go-ahead after the State Department released a report on Friday indicating the project would have a minimal impact on the environment. Republicans have long pushed for construction of the project, which enjoys some measure of Democratic support as well. The GOP is considering conditioning an extension of the debt limit on approval of the project by Obama. The White House, though, has said that it has no timetable for a final decision on the project. 首先,我们执行导入,通过阅读和分词来处理文章。 # -*- coding: utf-8 -*- import nltk import os import numpy as np import matplotlib.pyplot as plt from matplotlib import style from nltk import pos_tag from nltk.tag import StanfordNERTagger from nltk.tokenize import word_tokenize style.use('fivethirtyeight') # Process text def process_text(txt_file): raw_text = open("/usr/share/news_article.txt").read() token_text = word_tokenize(raw_text) return token_text 很棒! 现在让我们写一些函数来拆分我们的分类任务。 因为 NLTK NEG 分类器需要 POS 标签,所以我们会在我们的 NLTK 函数中加入 POS 标签。 # Stanford NER tagger def stanford_tagger(token_text): st = StanfordNERTagger('/usr/share/stanford-ner/classifiers/english.all.3class.distsim.crf.ser.gz', '/usr/share/stanford-ner/stanford-ner.jar', encoding='utf-8') ne_tagged = st.tag(token_text) return(ne_tagged) # NLTK POS and NER taggers def nltk_tagger(token_text): tagged_words = nltk.pos_tag(token_text) ne_tagged = nltk.ne_chunk(tagged_words) return(ne_tagged) 每个分类器都需要读取文章,并对命名实体进行分类,所以我们将这些函数包装在一个更大的函数中,使计时变得简单。 def stanford_main(): print(stanford_tagger(process_text(txt_file))) def nltk_main(): print(nltk_tagger(process_text(txt_file))) 当我们调用我们的程序时,我们调用这些函数。 我们将在os.times()函数调用中包装我们的stanford_main()和nltk_main()函数,取第四个索引,它是经过的时间。 然后我们将图绘制我们的结果。 if __name__ == '__main__': stanford_t0 = os.times()[4] stanford_main() stanford_t1 = os.times()[4] stanford_total_time = stanford_t1 - stanford_t0 nltk_t0 = os.times()[4] nltk_main() nltk_t1 = os.times()[4] nltk_total_time = nltk_t1 - nltk_t0 time_plot(stanford_total_time, nltk_total_time) 对于我们的绘图,我们使用time_plot()函数: def time_plot(stanford_total_time, nltk_total_time): N = 1 ind = np.arange(N) # the x locations for the groups width = 0.35 # the width of the bars stanford_total_time = stanford_total_time nltk_total_time = nltk_total_time fig, ax = plt.subplots() rects1 = ax.bar(ind, stanford_total_time, width, color='r') rects2 = ax.bar(ind+width, nltk_total_time, width, color='y') # Add text for labels, title and axes ticks ax.set_xlabel('Classifier') ax.set_ylabel('Time (in seconds)') ax.set_title('Speed by NER Classifier') ax.set_xticks(ind+width) ax.set_xticklabels( ('') ) ax.legend( (rects1[0], rects2[0]), ('Stanford', 'NLTK'), bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0. ) def autolabel(rects): # attach some text labels for rect in rects: height = rect.get_height() ax.text(rect.get_x()+rect.get_width()/2., 1.02*height, '%10.2f' % float(height), ha='center', va='bottom') autolabel(rects1) autolabel(rects2) plt.show() 哇,NLTK 像闪电一样快! 看来斯坦福更准确,但 NLTK 更快。 当平衡我们偏爱的精确度,和所需的计算资源时,这是需要知道的重要信息。 但是等等,还是有问题。我们的输出比较丑陋! 这是斯坦福大学的一个小样本: [('House', 'ORGANIZATION'), ('Speaker', 'O'), ('John', 'PERSON'), ('Boehner', 'PERSON'), ('became', 'O'), ('animated', 'O'), ('Tuesday', 'O'), ('over', 'O'), ('the', 'O'), ('proposed', 'O'), ('Keystone', 'ORGANIZATION'), ('Pipeline', 'ORGANIZATION'), (',', 'O'), ('castigating', 'O'), ('the', 'O'), ('Obama', 'PERSON'), ('administration', 'O'), ('for', 'O'), ('not', 'O'), ('having', 'O'), ('approved', 'O'), ('the', 'O'), ('project', 'O'), ('yet', 'O'), ('.', 'O') 以及 NLTK: (S (ORGANIZATION House/NNP) Speaker/NNP (PERSON John/NNP Boehner/NNP) became/VBD animated/VBN Tuesday/NNP over/IN the/DT proposed/VBN (PERSON Keystone/NNP Pipeline/NNP) ,/, castigating/VBG the/DT (ORGANIZATION Obama/NNP) administration/NN for/IN not/RB having/VBG approved/VBN the/DT project/NN yet/RB ./. 让我们在下个教程中,将它们转为可读的形式。 使用 BIO 标签创建可读的命名实体列表 Chuck Dishmon 的客座文章。 现在我们已经完成了测试,让我们将我们的命名实体转为良好的可读格式。 再次,我们将使用来自 NBC 新闻的同一篇新闻: House Speaker John Boehner became animated Tuesday over the proposed Keystone Pipeline, castigating the Obama administration for not having approved the project yet. Republican House Speaker John Boehner says there's "nothing complex about the Keystone Pipeline," and that it's time to build it. "Complex? You think the Keystone Pipeline is complex?!" Boehner responded to a questioner. "It's been under study for five years! We build pipelines in America every day. Do you realize there are 200,000 miles of pipelines in the United States?" The speaker went on: "And the only reason the president's involved in the Keystone Pipeline is because it crosses an international boundary. Listen, we can build it. There's nothing complex about the Keystone Pipeline -- it's time to build it." Boehner said the president had no excuse at this point to not give the pipeline the go-ahead after the State Department released a report on Friday indicating the project would have a minimal impact on the environment. Republicans have long pushed for construction of the project, which enjoys some measure of Democratic support as well. The GOP is considering conditioning an extension of the debt limit on approval of the project by Obama. The White House, though, has said that it has no timetable for a final decision on the project. 我们的 NTLK 输出已经是树了(只需要最后一步),所以让我们来看看我们的斯坦福输出。 我们将对标记进行 BIO 标记,B 分配给命名实体的开始,I 分配给内部,O 分配给其他。 例如,如果我们的句子是Barack Obama went to Greece today,我们应该把它标记为Barack-B Obama-I went-O to-O Greece-B today-O。 为此,我们将编写一系列条件来检查当前和以前的标记的O标签。 # -*- coding: utf-8 -*- import nltk import os import numpy as np import matplotlib.pyplot as plt from matplotlib import style from nltk import pos_tag from nltk.tag import StanfordNERTagger from nltk.tokenize import word_tokenize from nltk.chunk import conlltags2tree from nltk.tree import Tree style.use('fivethirtyeight') # Process text def process_text(txt_file): raw_text = open("/usr/share/news_article.txt").read() token_text = word_tokenize(raw_text) return token_text # Stanford NER tagger def stanford_tagger(token_text): st = StanfordNERTagger('/usr/share/stanford-ner/classifiers/english.all.3class.distsim.crf.ser.gz', '/usr/share/stanford-ner/stanford-ner.jar', encoding='utf-8') ne_tagged = st.tag(token_text) return(ne_tagged) # NLTK POS and NER taggers def nltk_tagger(token_text): tagged_words = nltk.pos_tag(token_text) ne_tagged = nltk.ne_chunk(tagged_words) return(ne_tagged) # Tag tokens with standard NLP BIO tags def bio_tagger(ne_tagged): bio_tagged = [] prev_tag = "O" for token, tag in ne_tagged: if tag == "O": #O bio_tagged.append((token, tag)) prev_tag = tag continue if tag != "O" and prev_tag == "O": # Begin NE bio_tagged.append((token, "B-"+tag)) prev_tag = tag elif prev_tag != "O" and prev_tag == tag: # Inside NE bio_tagged.append((token, "I-"+tag)) prev_tag = tag elif prev_tag != "O" and prev_tag != tag: # Adjacent NE bio_tagged.append((token, "B-"+tag)) prev_tag = tag return bio_tagged 现在我们将 BIO 标记后的标记写入树中,因此它们与 NLTK 输出格式相同。 # Create tree def stanford_tree(bio_tagged): tokens, ne_tags = zip(*bio_tagged) pos_tags = [pos for token, pos in pos_tag(tokens)] conlltags = [(token, pos, ne) for token, pos, ne in zip(tokens, pos_tags, ne_tags)] ne_tree = conlltags2tree(conlltags) return ne_tree 遍历并解析出所有命名实体: # Parse named entities from tree def structure_ne(ne_tree): ne = [] for subtree in ne_tree: if type(subtree) == Tree: # If subtree is a noun chunk, i.e. NE != "O" ne_label = subtree.label() ne_string = " ".join([token for token, pos in subtree.leaves()]) ne.append((ne_string, ne_label)) return ne 在我们的调用中,我们把所有附加函数聚到一起。 def stanford_main(): print(structure_ne(stanford_tree(bio_tagger(stanford_tagger(process_text(txt_file)))))) def nltk_main(): print(structure_ne(nltk_tagger(process_text(txt_file)))) 之后调用这些函数: if __name__ == '__main__': stanford_main() nltk_main() 这里是来自斯坦福的看起来不错的输出: [('House', 'ORGANIZATION'), ('John Boehner', 'PERSON'), ('Keystone Pipeline', 'ORGANIZATION'), ('Obama', 'PERSON'), ('Republican House', 'ORGANIZATION'), ('John Boehner', 'PERSON'), ('Keystone Pipeline', 'ORGANIZATION'), ('Keystone Pipeline', 'ORGANIZATION'), ('Boehner', 'PERSON'), ('America', 'LOCATION'), ('United States', 'LOCATION'), ('Keystone Pipeline', 'ORGANIZATION'), ('Keystone Pipeline', 'ORGANIZATION'), ('Boehner', 'PERSON'), ('State Department', 'ORGANIZATION'), ('Republicans', 'MISC'), ('Democratic', 'MISC'), ('GOP', 'MISC'), ('Obama', 'PERSON'), ('White House', 'LOCATION')] 以及来自 NLTK 的: [('House', 'ORGANIZATION'), ('John Boehner', 'PERSON'), ('Keystone Pipeline', 'PERSON'), ('Obama', 'ORGANIZATION'), ('Republican', 'ORGANIZATION'), ('House', 'ORGANIZATION'), ('John Boehner', 'PERSON'), ('Keystone Pipeline', 'ORGANIZATION'), ('Keystone Pipeline', 'ORGANIZATION'), ('Boehner', 'PERSON'), ('America', 'GPE'), ('United States', 'GPE'), ('Keystone Pipeline', 'ORGANIZATION'), ('Listen', 'PERSON'), ('Keystone', 'ORGANIZATION'), ('Boehner', 'PERSON'), ('State Department', 'ORGANIZATION'), ('Democratic', 'ORGANIZATION'), ('GOP', 'ORGANIZATION'), ('Obama', 'PERSON'), ('White House', 'FACILITY')] 分块在一起,可读性强。不错!

优秀的个人博客,低调大师

Netty深入浅出(一)入门

传统Socket中,NIO和IO的比较(Nio知识回顾) IO 阻塞点: server.accept(); 和 单线程情况下只能有一个客户端 用线程池可以有多个客户端连接,但是非常消耗性能 NIO selector.select()会产生阻塞的效果,但是它其实是非阻塞的 为什么呢? selector.select(1000); 1s检测一次 selector.wakeup(); 唤醒selector 可以任由我们控制休眠和唤醒操作,所以它其实是非阻塞型 要想更加了解NIO,请查看我的NIO专题 什么是netty netty可以运用在那些领域? 1分布式进程通信 例如: hadoop、dubbo、akka等具有分布式功能的框架,底层RPC通信都是基于netty实现的,这些框架使用的版本通常都还在用netty3.x 2、游戏服务器开发 最新的游戏服务器有部分公司可能已经开始采用netty4.x 或 netty5.x 1、netty服务端hello world案例 1. 创建Server类 package com.netty; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.handler.codec.string.StringDecoder; import java.net.InetSocketAddress; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Created by Fant.J. * 2018/2/2 21:28 */ public class Server { public static void main(String[] args) { //服务类 ServerBootstrap bootstrap = new ServerBootstrap(); //两个线程池 ExecutorService booss = Executors.newCachedThreadPool(); ExecutorService worker = Executors.newCachedThreadPool(); //设置niosocket工厂 bootstrap.setFactory(new NioServerSocketChannelFactory(booss,worker)); //设置管道工厂 bootstrap.setPipelineFactory(new ChannelPipelineFactory() { @Override public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = Channels.pipeline(); //将网络传输中的字节码(ChannelBuffer) 转换成String 可看源码 pipeline.addLast("decoder",new StringDecoder()); //将管道交给HelloHandler处理 pipeline.addLast("helloHandler",new HelloHandler()); return pipeline; } }); bootstrap.bind(new InetSocketAddress(10101)); System.out.println("server start"); } } 2. 创建HelloHandler类 需要继承SimpleChannelHandler类,然后重写几个基本方法 messageReceived() 接受消息 exceptionCaught() 捕获异常 channelConnected() 建立连接 channelDisconnected() 断开连接:必须是连接已经建立,关闭通道的时候才会触发。 channelClosed() 关闭通道 package com.netty; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.*; /** * 接受消息 * Created by Fant.J. * 2018/2/2 22:54 */ public class HelloHandler extends SimpleChannelHandler{ /** * Invoked when a message object (e.g: {@link ChannelBuffer}) was received * from a remote peer. * 接受消息 * @param ctx * @param e */ @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { // int i = 1/0; // System.out.println("messageReceived()"); // ChannelBuffer message = (ChannelBuffer) e.getMessage(); // String s = new String(message.array()); System.out.println(e.getMessage()); // System.out.println(s); //回复数据 ChannelBuffer channelBuffer = ChannelBuffers.copiedBuffer("hi".getBytes()); ctx.getChannel().write(channelBuffer); super.messageReceived(ctx, e); } /** * Invoked when an exception was raised by an I/O thread or a * {@link ChannelHandler}. * 捕获异常 * @param ctx * @param e */ @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { System.out.println("exceptionCaught()"); super.exceptionCaught(ctx, e); } /** * Invoked when a {@link Channel} is open, bound to a local address, and * connected to a remote address. * 建立连接 * @param ctx * @param e */ @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { System.out.println("channelConnected() "); super.channelConnected(ctx, e); } /** * Invoked when a {@link Channel} was disconnected from its remote peer. * 断开连接:必须是连接已经建立,关闭通道的时候才会触发。 * @param ctx * @param e */ @Override public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { System.out.println("channelDisconnected()"); super.channelDisconnected(ctx, e); } /** * Invoked when a {@link Channel} was closed and all its related resources * were released. * 关闭通道 * @param ctx * @param e */ @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { System.out.println("channelClosed()"); super.channelClosed(ctx, e); } } 因为网络之间传输是通过字节来传输,所以我们在messageReceived()方法里,获取到的message需要对其进行String转换。转换方法: //先拿到message对应的channelbuffer对象 ChannelBuffer message = (ChannelBuffer) e.getMessage(); String s = new String(message.array()); 同样,我们如果想要回复数据,也要将String转换成字节,这是实例中的一个例子: //前面管道的实例化 这里省略,直接贴出给管道进行StringDecoder()处理代码 pipeline.addLast("decoder",new StringDecoder()); 让我们来研究下原理,其实是这样转换的: //创建一个ChannelBuffer对象,并赋值 字节 ChannelBuffer channelBuffer = ChannelBuffers.copiedBuffer("hi".getBytes()); //获取到Channel并执行write()方法 ctx.getChannel().write(channelBuffer); github路径:https://github.com/jiaofanting/Java-nio-and-netty-spring-demo/tree/master/src/com/netty 2、netty客户端hello world案例 Client类 package com.netty.client; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.*; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec.string.StringEncoder; import java.net.InetSocketAddress; import java.util.Scanner; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Created by Fant.J. * 2018/2/3 10:59 */ public class Client { public static void main(String []args){ //服务类 ClientBootstrap bootstrap = new ClientBootstrap(); //线程池 ExecutorService boss = Executors.newCachedThreadPool(); ExecutorService worker = Executors.newCachedThreadPool(); //socket工厂 bootstrap.setFactory(new NioClientSocketChannelFactory(boss,worker)); //管道工厂 bootstrap.setPipelineFactory(new ChannelPipelineFactory() { @Override public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = Channels.pipeline(); pipeline.addLast("decoder",new StringDecoder()); pipeline.addLast("encoder",new StringEncoder()); pipeline.addLast("hiHandler",new HiHandler()); return pipeline; } }); //连接服务器 ChannelFuture connect = bootstrap.connect(new InetSocketAddress("127.0.0.1",10101)); Channel channel = connect.getChannel(); System.out.println("client start"); Scanner scanner = new Scanner(System.in); while (true){ System.out.println("please input string"); channel.write(scanner.next()); } } } HiHandler类 package com.netty.client; import org.jboss.netty.channel.*; /** * 消息接受处理器 * Created by Fant.J. * 2018/2/3 10:59 */ public class HiHandler extends SimpleChannelHandler{ /** * 接收消息 */ @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { String s = (String) e.getMessage(); System.out.println(s); super.messageReceived(ctx, e); } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { System.out.println("exceptionCaught()"); super.exceptionCaught(ctx, e); } @Override public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { System.out.println("channelOpen()"); super.channelOpen(ctx, e); } @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { System.out.println("channelConnected()"); super.channelConnected(ctx, e); } @Override public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { System.out.println("channelDisconnected()"); super.channelDisconnected(ctx, e); } @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { System.out.println("channelClosed()"); super.channelClosed(ctx, e); } }

优秀的个人博客,低调大师

SpringBoot入门系列: Spring Boot的测试

Spring Boot的测试,和普通项目的测试类同,可以继续使用我们熟悉的测试工具。当然,这里的测试,主要还是后台代码的测试。 主要需要注意的地方仅有三点: 1、依赖包的引入:pom.xml中仅依赖spring-boot-starter-test,它把相关的依赖全部引入。 2、在测试类上的注解,常用的注解有三个 @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = Application.class) @WebAppConfiguration 这三个注解,只要注意第二个注解括号内的Application.class就行,把它替换为项目的启动类即可。 我们前面spring-boot-sample-mysql工程的启动类为SpringBootSampleMysqlApplication,那么测试类上的注解就是 @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = SpringBootSampleMysqlApplication.class) @WebAppConfiguration 3、测试类的文件结构,保持src/test/java和src/main/java结构一直,即:包+文件夹。 如:com.example包service中类的测试,那么在src/test/java也是建立com.example包,再在包下建立文件夹service. 注:由于我们测试的启动类用的是项目的启动类,所以Spring Boot项目的测试配置文件任然用src/main/resources的。 下面贴两个个测试类代码 1、服务类的 [java]view plaincopy packagecom.example.service; importjava.util.List; importorg.junit.Assert; importorg.junit.Test; importorg.junit.runner.RunWith; importorg.springframework.beans.factory.annotation.Autowired; importorg.springframework.boot.test.SpringApplicationConfiguration; importorg.springframework.test.context.junit4.SpringJUnit4ClassRunner; importorg.springframework.test.context.web.WebAppConfiguration; importcom.example.Application; importcom.example.domain.TestPOJO; importcom.example.dto.HotelDto; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes=Application.class) @WebAppConfiguration publicclassTestServicesTest{ @Autowired TestServicestestServices; @Test publicvoidtestShow(){ StringexpectedResult="helloworld!"; Stringresult=testServices.show(); Assert.assertTrue("数据一致",expectedResult.equals(result)); Assert.assertFalse("数据不一致",!expectedResult.equals(result)); } @Test publicvoidtestShowDao(){ List<TestPOJO>testPOJOList=testServices.showDao(10); Assert.assertTrue("数据集不对",testPOJOList.size()==1); Assert.assertTrue("数据一致",testPOJOList.get(0).getName().equals("nice")); } @Test publicvoidtestFindByCountry(){ List<HotelDto>testPOJOList=testServices.findByCountry("US"); Assert.assertTrue("数据集不对",testPOJOList.size()==1); Assert.assertTrue("数据一致",testPOJOList.get(0).getCityName().equals("SanFrancisco")); } } 2、controller类的 [java]view plaincopy packagecom.example.controller; importjava.util.List; importorg.junit.Assert; importorg.junit.Before; importorg.junit.Test; importorg.junit.runner.RunWith; importorg.springframework.beans.factory.annotation.Autowired; importorg.springframework.boot.test.SpringApplicationConfiguration; importorg.springframework.http.MediaType; importorg.springframework.test.context.junit4.SpringJUnit4ClassRunner; importorg.springframework.test.context.web.WebAppConfiguration; importorg.springframework.test.web.servlet.MockMvc; importorg.springframework.test.web.servlet.MvcResult; importorg.springframework.test.web.servlet.request.MockMvcRequestBuilders; importorg.springframework.test.web.servlet.setup.MockMvcBuilders; importorg.springframework.web.context.WebApplicationContext; importcom.example.Application; importcom.example.domain.TestPOJO; importcom.example.dto.HotelDto; importcom.example.service.TestServices; importcom.fasterxml.jackson.core.JsonProcessingException; importcom.fasterxml.jackson.databind.ObjectMapper; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes=Application.class) @WebAppConfiguration publicclassTestControllerTest{ MockMvcmvc; @Autowired WebApplicationContextwebApplicationConnect; @Autowired TestServicestestServices; StringexpectedJson; @Before publicvoidsetUp()throwsJsonProcessingException{ mvc=MockMvcBuilders.webAppContextSetup(webApplicationConnect).build(); } @Test publicvoidtestShow()throwsException{ StringexpectedResult="helloworld!"; Stringuri="/show"; MvcResultmvcResult=mvc.perform(MockMvcRequestBuilders.get(uri).accept(MediaType.APPLICATION_JSON)) .andReturn(); intstatus=mvcResult.getResponse().getStatus(); Stringcontent=mvcResult.getResponse().getContentAsString(); Assert.assertTrue("错误,正确的返回值为200",status==200); Assert.assertFalse("错误,正确的返回值为200",status!=200); Assert.assertTrue("数据一致",expectedResult.equals(content)); Assert.assertFalse("数据不一致",!expectedResult.equals(content)); } protectedStringObj2Json(Objectobj)throwsJsonProcessingException{ ObjectMappermapper=newObjectMapper(); returnmapper.writeValueAsString(obj); } @Test publicvoidtestShowDaoInt()throwsException{ List<TestPOJO>testPOJOList=testServices.showDao(10); expectedJson=Obj2Json(testPOJOList); Stringuri="/showDao?age=10"; MvcResultmvcResult=mvc.perform(MockMvcRequestBuilders.get(uri).accept(MediaType.APPLICATION_JSON)).andReturn(); intstatus=mvcResult.getResponse().getStatus(); Stringcontent=mvcResult.getResponse().getContentAsString(); Assert.assertTrue("错误,正确的返回值为200",status==200); Assert.assertFalse("错误,正确的返回值为200",status!=200); Assert.assertTrue("数据一致",expectedJson.equals(content)); Assert.assertFalse("数据不一致",!expectedJson.equals(content)); } @Test publicvoidtestShowDaoString()throwsException{ List<HotelDto>hotelDtoList=testServices.findByCountry("US"); expectedJson=Obj2Json(hotelDtoList); Stringuri="/country/US"; MvcResultmvcResult=mvc.perform(MockMvcRequestBuilders.get(uri).accept(MediaType.APPLICATION_JSON)).andReturn(); intstatus=mvcResult.getResponse().getStatus(); Stringcontent=mvcResult.getResponse().getContentAsString(); Assert.assertTrue("错误,正确的返回值为200",status==200); Assert.assertFalse("错误,正确的返回值为200",status!=200); Assert.assertTrue("数据一致",expectedJson.equals(content)); Assert.assertFalse("数据不一致",!expectedJson.equals(content)); } } controller类的,为了MockMvc,注入了WebApplicationContext。 原文地址http://www.bieryun.com/833.html

优秀的个人博客,低调大师

开发VS2008 AddIn 入门Sample

本文主要介绍的是VS2008插件开发 环境要求:VS2008;.Net3.5 目标:开发插件功能为“在VS中创建文本文档,并在文本开头输入//This code was createdFor Testing” 1,Create new project(Visual Studio Add-In) 2,按照wizard一步一步操作: 选择使用C#编写Addin 选择在.NET IDE 和Macro IDE中都可以使用AddIn 输入name和description 选中确定需要AddIn在Tool中显示 选择需要About Information summary Finish 生成solution 此时debug(F5)这个solution,会跳出另外一个VS2008窗口,并且你会发现在Tool工具栏下有^-^笑脸: 3 将Connect类中的Exec方法改为: 代码 4 在connect类中增加方法: 代码 5 build and debug 当按下Tool中的AddIn工具时候会发现文本已经创建,并且文字也已经加入到文本中: 至此,VS AddIn开发完成。 PS:本文示例参考:http://www.c-sharpcorner.com/uploadfile/mgold/addins11292005015631am/addins.aspx 本文转自轩脉刃博客园博客,原文链接:http://www.cnblogs.com/yjf512/archive/2010/06/05/1752401.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Java正则系列: (1)入门教程

本文简要介绍Java的正则表达式及其实现方式,并通过实例讲解正则表达式的具体用法。 1. 正则表达式 1.1. 简介 正则表达式(Regular Expression), 简称 正则, 也翻译为 正规式, 用来表示文本搜索模式。英文缩写是 regex(reg-ex). 搜索模式(search pattern)可能多种多样, 如, 单个字符(character), 特定字符串(fixed string), 包含特殊含义的复杂表达式等等. 对于给定的字符串, 正则表达式可能匹配一到多次, 也可能一次都不匹配。 正则表达式一般用来查找、编辑和替换文本(text), 本质上, text(文本) 和 string(字符串) 是一回事。 用正则表达式来分析/修改文本的过程, 称为: 应用于文本/字符串的正则表达式 。正则表达式扫描字符串的顺序是从左到右. 每个字符都只能被匹配成功一次, 下次匹配扫描就会从后面开始。例如, 正则表达式 aba, 匹配字符串 ababababa 时, 只会扫描到两个匹配(aba_aba__)。 1.2. 示例 最简单的例子是字母串。例如, 正则表达式 Hello World 能匹配的就是字符串 “Hello World”。 正则表达式中, 点号 .(dot,英文句号)属于通配符, 点号匹配任意一个字符(character); 例如, “a” 或者 “1”; 当然, 默认情况下点号不能匹配换行 \n, 需要特殊标识指定才行。 下表列举了一些简单的正则表达式,和对应的匹配模式。 正则表达式 Matches this is text 完全匹配 “this is text” this\s+is\s+text 匹配的内容为: “this”, 加上1到多个空白符(whitespace character, 如空格,tab,换行等), 加上 “is”, 加上1到多个空白符, 再加上 “text”. ^\d+(\.\d+)? 正则表达式以转义字符 ^(小尖号)打头, 表示这行必须以小尖号后面的字符模式开始, 才会达成匹配. \d+ 匹配1到多个数字. 英文问号 ? 表示可以出现 0~1次. \. 匹配的是字符 “.”, 小括号(parentheses) 表示一个分组. 所以这个正则表达式可以匹配正整数或者小数,如: “5”, “66.6” 或者 “5.21” 等等. 说明,中文的全角空格( )字符不属于空白字符(whitespace characters), 可以认为其属于一个特殊的汉字。 1.3. 编程语言对正则表达式的支持 大多数编程语言都支持正则表达式, 如 Java、Perl, Groovy 等等。但各种语言的正则表达式写法略有一些不同。 2. 预备知识 本教程要求读者具备Java语言相关的基础知识。 下面的一些示例通过 JUnit 来验证执行结果。如果不想使用JUnit, 也可以改写相关代码。关于JUnit的知识请参考 JUnit教程: http://www.vogella.com/tutorials/JUnit/article.html。 3. 语法规则 本章介绍各种正则元素的范本, 我们会先介绍什么是元字符(meta character)。 3.1. 通用表达式简介 正则表达式 说明 . 点号(.), 匹配任意一个字符 ^regex 小尖号(^), 起始标识, 前面不能出现其他字符. regex$ 美元符号($,dollar,美刀), 结束标识,后面不能再出现其他字符. [abc] 字符组(set), 匹配 a 或 b 或 c. [abc][vz] 字符组(set), 匹配 a 或 b 或 c,紧接着是 v 或 z. [^abc] 如果小尖号(^, caret, 此处读作 非) 出现在中括号里面的第一位, 则表示否定(negate). 这里匹配: 除 a, b, c 之外的其他任意字符. [a-d1-7] 范围表示法: 匹配 a 到 d 之间的单个字符, 或者 1 到 7之间的单个字符, 整体只匹配单个字符, 而不是 d1 这种组合. X|Z 匹配 X 或者 Z. XZ 匹配XZ, X和Z必须按顺序全部出现. $ 判断一行是否结束. 3.2. 元字符 下面这些是预定义的元字符(Meta characters), 可用于提取通用模式, 如 \d 可以代替 [0-9], 或者[0123456789]。 正则表达式 说明 \d 单个数字, 等价于 [0-9] 但更简洁 \D 非数字, 等价于 [^0-9] 但更简洁 \s 空白字符(whitespace), 等价于 [ \t\n\x0b\r\f] \S 非空白字符, 等价于 [^\s] \w 反斜线加上小写w, 表示单个标识符,即字母数字下划线, 等价于 [a-zA-Z_0-9] \W 非单词字符, 等价于 [^\w] \S+ 匹配1到多个非空白字符 \b 匹配单词外边界(word boundary), 单词字符指的是 [a-zA-Z0-9_] 这些元字符主要取自于对应单词的英文首字母, 例如: digit(数字), space(空白), word (单词), 以及 boundary(边界)。对应的大写字符则用来表示取反。 3.3. 量词 量词(Quantifier)用来指定某个元素可以出现的次数。?, *, + 和 {} 等符号定义了正则表达式的数量。 正则表达式 说明 示例 * 0到多次, 等价于 {0,} X* 匹配0到多个连续的X, .* 则匹配任意字符串 + 1到多次, 等价于 {1,} X+ 匹配1到多个连续的X ? 0到1次, 等价于 {0,1} X? 匹配0个,后者1个X {n} 精确匹配 n 次 {} 前面序列出现的次数 \d{3} 匹配3位数字, .{10} 匹配任意10个字符. {m, n} 出现 m 到 n 次, \d{1,4} 匹配至少1位数字,至多4位数字. *? 在量词后面加上 ?, 表示懒惰模式(reluctant quantifier). 从左到右慢慢扫描, 找到第一个满足正则表达式的地方就暂停搜索, 用来尝试匹配最少的字符串. 3.4. 分组和引用 可以对正则表达式进行分组(Grouping), 用圆括号 () 括起来。这样就可以对括号内的整体使用量词。 当然, 在进行替换的时候, 还可以对分组进行引用。也就是捕获组(captures the group)。向后引用(back reference) 指向匹配中该分组所对应的字符串。进行替换时可以通过 $ 来引用。 使用 $ 来引用一个捕获组。例如 $1 表示第一组, $2 表示第二组, 以此类推, $0则表示整个正则所匹配的部分。 例如, 想要去掉单词后面, 句号/逗号(point or comma)前面的空格。可以把句号/逗号写入正则中, 然后原样输出到结果中即可。 // 去除单词与 `.|,` 之间的空格 String pattern = "(\\w)(\\s+)([\\.,])"; System.out.println(EXAMPLE_TEST.replaceAll(pattern, "$1$3")); 提取 标签的内容: // 提取 <title> 标签的内容 pattern = "(?i)(<title.*?>)(.+?)()"; String updated = EXAMPLE_TEST.replaceAll(pattern, "$2"); 3.5. 环视 环视(lookaround), 分为顺序环视(Lookahead)与逆序环视(lookbehind), 属于零宽度断言(zero-length assertion)。 类似于行起始标识(^)和结束标识($); 或者单词边界(\b)一类的位置标识。 顺序否定环视(Negative look ahead), 用于在匹配的同时, 排除掉某些情形。也就是说其后面不能是符合某种特征的字符串。 顺序否定环视(Negative look ahead) 使用 (?!pattern) 这种格式定义。例如, 下面的正则, 只匹配后面不是 b 字母的 “a” 字母。 a(?!b) 类似的, 顺序环视(look ahead), 也叫顺序肯定环视。 如,只匹配a字母, 但要求后面只能是 b 字母, 否则这个 a 就不符合需要: a(?=b) 注意,环视 是一种向前/后查找的语法: (?=exp), 会查找后面位置的 exp; 所环视的内容却不包含在正则表达式匹配中。 环视(lookaround)是一种高级技巧, 环视的部分不会匹配到结果之中, 但却要求匹配的字符串前面/后面具备环视部分的特征。 如果将等号换成感叹号, 就是环视否定 (?!exp), 变成否定语义,也就是说查找的位置的后面不能是exp。 逆序肯定环视, (?<=exp), 表示所在位置左侧能够匹配 exp 逆序否定环视, (?<!exp), 表示所在位置左侧不能匹配 exp 详情请参考: 正则应用之——逆序环视探索: http://blog.csdn.net/lxcnn/article/details/4954134 参考: 利用正则表达式排除特定字符串 http://www.cnblogs.com/wangqiguo/archive/2012/05/08/2486548.html 3.6. 正则表达式的模式 在正则表达式开头可以指定模式修饰符(mode modifier)。还可以组合多种模式, 如 (?is)pattern。 (?i) 正则表达式匹配时不区分大小写。 (?s) 单行模式(single line mode), 使点号(.) 匹配所有字符, 包括换行(\n)。 (?m) 多行模式(multi-line mode), 使 小尖号(^,caret) 和 美元符号($, dollar) 匹配目标字符串中每一行的开始和结束。 3.7. Java中的反斜杠 在Java字符串中, 反斜杠(\, backslash) 是转义字符, 有内置的含义。在源代码级别, 需要使用两个反斜杠\\来表示一个反斜杠字符。如果想定义的正则表达式是 \w, 在 .java 文件源码中就需要写成 \\w。 如果想要匹配文本中的1个反斜杠, 则源码中需要写4个反斜杠 \\\\。 4. String类正则相关的方法 4.1. String 类重新定义了正则相关的方法 Java中 String 类内置了4个支持正则的方法, 即: matches(), split(), replaceFirst() 和replaceAll() 方法。 需要注意, replace() 是纯字符串替换, 不支持正则表达式。 这些方法并没有对性能进行优化。稍后我们将讨论优化过的类。 方法 说明 s.matches("regex") 判断字符串 s 是否能匹配正则 "regex". 只有整个字符串匹配正则才返回 true . s.split("regex") 用正则表达式 "regex" 作为分隔符来拆分字符串, 返回结果是 String[] 数组. 注意 "regex" 对应的分隔符并不包含在返回结果中. s.replaceFirst("regex", "replacement") 替换第一个匹配 "regex" 的内容为 "replacement. s.replaceAll("regex", "replacement") 将所有匹配 "regex" 的内容替换为 "replacement. 下面是对应的示例。 package de.vogella.regex.test; public class RegexTestStrings { public static final String EXAMPLE_TEST = "This is my small example " + "string which I'm going to " + "use for pattern matching."; public static void main(String[] args) { System.out.println(EXAMPLE_TEST.matches("\\w.*")); String[] splitString = (EXAMPLE_TEST.split("\\s+")); System.out.println(splitString.length);// should be 14 for (String string : splitString) { System.out.println(string); } // 将所有空白符(whitespace) 替换为 tab System.out.println(EXAMPLE_TEST.replaceAll("\\s+", "\t")); } } 4.2. 示例 下面给出一些正则表达式的使用示例。请参照注释信息。 If you want to test these examples, create for the Java project de.vogella.regex.string. 如果想测试这些示例, 请将java文件放到一个Java包下, 如 de.vogella.regex.string。 package de.vogella.regex.string; public class StringMatcher { // 如果字符串完全匹配 "`true`", 则返回 true public boolean isTrue(String s){ return s.matches("true"); } // 如果字符串完全匹配 "`true`" 或 "`True`", 则返回 true public boolean isTrueVersion2(String s){ return s.matches("[tT]rue"); } // 如果字符串完全匹配 "`true`" 或 "`True`" // 或 "`yes`" 或 "`Yes`", 则返回 true public boolean isTrueOrYes(String s){ return s.matches("[tT]rue|[yY]es"); } // 如果包含字符串 "`true`", 则返回 true public boolean containsTrue(String s){ return s.matches(".*true.*"); } // 如果包含3个字母, 则返回 true public boolean isThreeLetters(String s){ return s.matches("[a-zA-Z]{3}"); // 当然也等价于下面这种比较土的方式 // return s.matches("[a-Z][a-Z][a-Z]"); } // 如果不以数字开头, 则返回 true public boolean isNoNumberAtBeginning(String s){ // 可能 "^\\D.*" 更好一点 return s.matches("^[^\\d].*"); } // 如果包含了 `b` 之外的字符, 则返回 true public boolean isIntersection(String s){ return s.matches("([\\w&&[^b]])*"); } // 如果包含的某串数字小于300, 则返回 true public boolean isLessThenThreeHundred(String s){ return s.matches("[^0-9]*[12]?[0-9]{1,2}[^0-9]*"); } } And a small JUnit Test to validates the examples. 我们通过 JUnit 测试来验证。 package de.vogella.regex.string; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; public class StringMatcherTest { private StringMatcher m; @Before public void setup(){ m = new StringMatcher(); } @Test public void testIsTrue() { assertTrue(m.isTrue("true")); assertFalse(m.isTrue("true2")); assertFalse(m.isTrue("True")); } @Test public void testIsTrueVersion2() { assertTrue(m.isTrueVersion2("true")); assertFalse(m.isTrueVersion2("true2")); assertTrue(m.isTrueVersion2("True"));; } @Test public void testIsTrueOrYes() { assertTrue(m.isTrueOrYes("true")); assertTrue(m.isTrueOrYes("yes")); assertTrue(m.isTrueOrYes("Yes")); assertFalse(m.isTrueOrYes("no")); } @Test public void testContainsTrue() { assertTrue(m.containsTrue("thetruewithin")); } @Test public void testIsThreeLetters() { assertTrue(m.isThreeLetters("abc")); assertFalse(m.isThreeLetters("abcd")); } @Test public void testisNoNumberAtBeginning() { assertTrue(m.isNoNumberAtBeginning("abc")); assertFalse(m.isNoNumberAtBeginning("1abcd")); assertTrue(m.isNoNumberAtBeginning("a1bcd")); assertTrue(m.isNoNumberAtBeginning("asdfdsf")); } @Test public void testisIntersection() { assertTrue(m.isIntersection("1")); assertFalse(m.isIntersection("abcksdfkdskfsdfdsf")); assertTrue(m.isIntersection("skdskfjsmcnxmvjwque484242")); } @Test public void testLessThenThreeHundred() { assertTrue(m.isLessThenThreeHundred("288")); assertFalse(m.isLessThenThreeHundred("3288")); assertFalse(m.isLessThenThreeHundred("328 8")); assertTrue(m.isLessThenThreeHundred("1")); assertTrue(m.isLessThenThreeHundred("99")); assertFalse(m.isLessThenThreeHundred("300")); } } 5. Pattern与Matcher简介 For advanced regular expressions the java.util.regex.Pattern and java.util.regex.Matcher classes are used. 要支持正则表达式的高级特性, 需要借助 java.util.regex.Pattern 和 java.util.regex.Matcher 类。 首先创建/编译 Pattern 对象, 用来定义正则表达式。对 Pattern 对象, 给定一个字符串, 则产生一个对应的 Matcher 对象。通过 Matcher 对象就可以对 String 进行各种正则相关的操作。 package de.vogella.regex.test; import java.util.regex.Matcher; import java.util.regex.Pattern; public class RegexTestPatternMatcher { public static final String EXAMPLE_TEST = "This is my small example string which I'm going to use for pattern matching."; public static void main(String[] args) { Pattern pattern = Pattern.compile("\\w+"); // 如需忽略大小写, 可以使用: // Pattern pattern = Pattern.compile("\\w+", Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher(EXAMPLE_TEST); // 查找所有匹配的结果 while (matcher.find()) { System.out.print("Start index: " + matcher.start()); System.out.print(" End index: " + matcher.end() + " "); System.out.println(matcher.group()); } // 将空格替换为 tabs Pattern replace = Pattern.compile("\\s+"); Matcher matcher2 = replace.matcher(EXAMPLE_TEST); System.out.println(matcher2.replaceAll("\t")); } } 6. 正则表达式示例 下面列出了常用的正则表达式使用情景。希望读者根据实际情况进行适当的调整。 6.1 或(Or) 任务: 编写正则表达式, 用来匹配包含单词 “Joe” 或者 “Jim” , 或者两者都包含的行。 创建 de.vogella.regex.eitheror 包和下面的类。 package de.vogella.regex.eitheror; import org.junit.Test; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; public class EitherOrCheck { @Test public void testSimpleTrue() { String s = "humbapumpa jim"; assertTrue(s.matches(".*(jim|joe).*")); s = "humbapumpa jom"; assertFalse(s.matches(".*(jim|joe).*")); s = "humbaPumpa joe"; assertTrue(s.matches(".*(jim|joe).*")); s = "humbapumpa joe jim"; assertTrue(s.matches(".*(jim|joe).*")); } } 6.2. 匹配电话号码 任务: 编写正则表达式, 匹配各种电话号码。 假设电话号码(Phone number)的格式为 “7位连续的数字”; 或者是 “3位数字加空格/横线, 再加上4位数字”。 package de.vogella.regex.phonenumber; import org.junit.Test; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; public class CheckPhone { @Test public void testSimpleTrue() { String pattern = "\\d\\d\\d([,\\s])?\\d\\d\\d\\d"; String s= "1233323322"; assertFalse(s.matches(pattern)); s = "1233323"; assertTrue(s.matches(pattern)); s = "123 3323"; assertTrue(s.matches(pattern)); } } 6.3. 判断特定数字范围 以下示例用来判断文本中是否具有连续的3位数字。 创建 de.vogella.regex.numbermatch 包和下面的类。 package de.vogella.regex.numbermatch; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.junit.Test; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; public class CheckNumber { @Test public void testSimpleTrue() { String s= "1233"; assertTrue(test(s)); s= "0"; assertFalse(test(s)); s = "29 Kasdkf 2300 Kdsdf"; assertTrue(test(s)); s = "99900234"; assertTrue(test(s)); } public static boolean test (String s){ Pattern pattern = Pattern.compile("\\d{3}"); Matcher matcher = pattern.matcher(s); if (matcher.find()){ return true; } return false; } } 6.4. 校验超链接 假设需要从网页中找出所有的有效链接。当然,需要排除 “javascript:” 和 “mailto:” 开头的情况。 创建 de.vogella.regex.weblinks 包, 以及下面的类: package de.vogella.regex.weblinks; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; public class LinkGetter { private Pattern htmltag; private Pattern link; public LinkGetter() { htmltag = Pattern.compile("<a\\b[^>]*href=\"[^>]*>(.*?)</a>"); link = Pattern.compile("href=\"[^>]*\">"); } public List<String> getLinks(String url) { List<String> links = new ArrayList<String>(); try { BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(new URL(url).openStream())); String s; StringBuilder builder = new StringBuilder(); while ((s = bufferedReader.readLine()) != null) { builder.append(s); } Matcher tagmatch = htmltag.matcher(builder.toString()); while (tagmatch.find()) { Matcher matcher = link.matcher(tagmatch.group()); matcher.find(); String link = matcher.group().replaceFirst("href=\"", "") .replaceFirst("\">", "") .replaceFirst("\"[\\s]?target=\"[a-zA-Z_0-9]*", ""); if (valid(link)) { links.add(makeAbsolute(url, link)); } } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return links; } private boolean valid(String s) { if (s.matches("javascript:.*|mailto:.*")) { return false; } return true; } private String makeAbsolute(String url, String link) { if (link.matches("http://.*")) { return link; } if (link.matches("/.*") && url.matches(".*$[^/]")) { return url + "/" + link; } if (link.matches("[^/].*") && url.matches(".*[^/]")) { return url + "/" + link; } if (link.matches("/.*") && url.matches(".*[/]")) { return url + link; } if (link.matches("/.*") && url.matches(".*[^/]")) { return url + link; } throw new RuntimeException("Cannot make the link absolute. Url: " + url + " Link " + link); } } 6.5. 查找重复的单词 下面的正则表达式用来匹配重复的单词。 \b(\w+)\s+\1\b \b 是单词边界, \1 则引用第一个分组, 此处的第一个分组为前一个单词 (\w+)。 (?!-in)\b(\w+) \1\b 通过环视否定, 来匹配前面不是 “-in” 开始的重复单词。 提示: 可以在最前面加上 (?s) 标志来执行跨行搜索。 6.6. 查找每行起始位置的元素 下面的正则, 用来查找一行开头的单词 “title”, 前面允许有空格。 (\n\s*)title 6.7. 找到非Javadoc风格的语句 有时候, 在Java代码中会出现非Javadoc风格(Non-Javadoc)的语句; 如 Java 1.6 中的 @Override 注解, 用于告诉IDE该方法覆写了超类方法。这种是可以从源码中清除的。下面的正则用来找出这类注解。 (?s) /\* \(non-Javadoc\).*?\*/ 6.7.1. 用 Asciidoc 替换 DocBook 声明 例如有下面这样的XML: <programlisting language="java"> <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="./examples/statements/MyClass.java" /> </programlisting> 可以用下面的正则来匹配: `\s+<programlisting language="java">\R.\s+<xi:include xmlns:xi="http://www\.w3\.org/2001/XInclude" parse="text" href="\./examples/(.*).\s+/>\R.\s+</programlisting>` 替换目标可以是下面这样的regex: `\R[source,java]\R----\R include::res/$1[]\R---- 7. 在Eclipse中使用正则表达式 在Eclipse或者其他编辑器中, 可以使用正则来执行查找和替换。一般使用快捷键 Ctrl+H 打开 搜索/Search 对话框。 选择 File Search 选项卡, 并勾选 Regular expression 标识, 则可以进行正则查找/替换。当然, 还可以指定文件类型, 以及查找/替换的目录范围。 下图展示了如何查找XML标签 <![CDATA[]]]> 和前面的空格, 以及如何去除这些空格。 在结果对话框中可以查看有哪些地方会被替换, 可以去掉不想替换的元素。没问题的话, 点击 OK 按钮, 就会进行替换。 8. 相关链接 示例代码下载: http://www.vogella.com/code/index.html Regular-Expressions.info on Using Regular Expressions in Java Regulare xpressions examples The Java Tutorials: Lesson: Regular Expressions 原文链接: http://www.vogella.com/tutorials/JavaRegularExpressions/article.html 原文日期: 2016.06.24 翻译日期: 2017-12-28 翻译人员: 铁锚 http://blog.csdn.net/renfufei/

优秀的个人博客,低调大师

Q#语言入门1 操作operation

Q# 程序会包含一个或多个操作(operation)。操作描述了量子操作带来的影响。 还可以包含一个或多个方法(function)。方法用来操作经典数据,只用来计算。 每个操作还可以调用其他操作(这不就是java里的方法吗?说对了一半,是java里的静态方法)。 Q#文件被编译后,每个操作都会是一个.net的类。所以Q#的操作可以被.net的其他语言调用。 一个操作会有一个输入、一个输出,会有一个body体。 下面定义一个操作: operation BitFlip(target : Qubit) : () { body { X(target); } } 它的输出是一个空的元组,类似与void,或者F#里的unit。

优秀的个人博客,低调大师

jsp自定义标记入门

JSP自定义标记为在动态 Web 页中将页面表示与业务逻辑分离提供了一种标准化的机制,使页面设计者可以将注意力放到页面表示上,而应用程序开发人员则专注于编写后端的代码。您可能听说现在有上百种不同的方式,但是在开发 Web 应用程序时将表示逻辑与业务逻辑分离是很重要的。近年来,Java 平台已经发展为在体系结构层次上加入了这种分离。例如,在 JSP 体系结构中加入 JavaBean 组件使开发人员使用 JSP 标记获得和设置经过特别编码的 java 组件上的属性。这些组件或者 JavaBean 再代表表示层执行后端业务处理。 JSP 自定义标记是 JSP/JavaBean 体系结构的产物。像 JavaBean 技术一样,自定义标记有助于将表示逻辑与业务逻辑分离。并且自定义标记成了 Web 设计者的 HTML、XML 和 Javascript 世界与软件工程师的 Java 代码、SQL 调用和算法世界之间的桥梁。 JSP 自定义标记 JSP 自定义标记 是用户定义的标记,它遵循 JSP JavaBean 标记(即 useBean、getProperty 和 setProperty)所使用的一种特殊的 xml 语法。当 servlet 容器处理自定义标记时,会调用一个或者多个 Java 类文件处理它,与用 Java 类文件处理 JSP 页面的 JavaBean 调用的方式基本一样。处理标记以后,容器将取其名字和属性、以及标记正文中可能有的任何内容,并将它传递给一个或者多个类文件进行处理。 Java 开发人员编写标记处理程序类以处理标记并处理所有需要的 Java 代码和数据操作。对于 Web 设计者来说,自定义标记与标准 html 标记除了都可以利用后端动态数据外,它们看上去与使用起来没什么区别。正确编写自定义标记可以让 Web 设计者创建、查询和操作数据而无需编写一行 Java 代码。正确使用自定义标记使 Java 开发人员不必再在编码过程中考虑表示层。这样应用程序开发小组的每一位成员都可以关注于他或者她最擅长的事物。 实现 JSP 自定义标记 JSP 体系结构需要以下组件以实现自定义标记: 在每一页中有一个 JSP 声明 Web 应用程序描述符(web.xml)中的一个项 一个包含特殊 XML 文件和为处理自定义标记而调用的 Java 类的 JAR 文件 要想成功实现 JSP 自定义标记,您需要采取下面四个步骤: 编写标记处理程序类。 创建标记库描述符(TLD)。 引用标记库。 在 JSP 页面中使用标记。 那我们就以经典的"Hello,World"开始吧。。。 第 1 步. 编写标记处理程序类 我们要做的第一件事是编写标记处理程序类。在执行引用自定义标记的 JSP 页面时,JSP 容器判断每一个自定义标记。当容器遇到一个标记时,它调用与这个自定义标记相关联的标记处理程序,我们将在后面更多地讨论这个过程。然后,每一个标记处理程序实现 JSP API中的一个特殊接口。标记有两种类型:可以处理标记内容(或者正文)的标记和不能处理标记内容的标记: <abc:tagWithNoBody attribute="value"/> <abc:tagWithBody attribute="value"> This is some body content that the tag handler can operate upon. </abc:tagWithBody> 在 例子中不需要加入正文内容,因为它只显示一个字符串。因此,我们的处理程序类将实现 Tag 接口(一般是通过扩展 TagSupport 类)。如果我们要创建一个可以处理正文的标记,那么我们就需要实现 BodyTag 接口(一般是通过扩展 BodyTagSupport 类)。 清单 1. 标记处理程序类 package com.vitamin.taglib; import javax.servlet.jsp.tagext.*; import javax.servlet.jsp.*; import java.io.*; public class HelloTag implements Tag { private PageContext context = null;//页面上下文 public HelloTag() { super(); // TODO 自动生成构造函数存根 } public void setPageContext(PageContext pageContext) { this.context = pageContext; } public void setParent(Tag tag) { } public Tag getParent() { return null; } public int doStartTag()throws JspException { try { this.context.getOut().println("hello,world"); } catch(IOException ex) { throw new JspException(ex.getMessage()); } return Tag.SKIP_BODY; } public int doEndTag() { return Tag.SKIP_PAGE; } public void release() { } } 当然在这里值得注意的是,我这是采用了实现Tag接口的方法来做的,其实更好的方式是继承自TagSupport类。因为 TagSupport 类是简单的、具体类,它完全实现了在 Tag 接口中声明的方法,我们可以只实现那些在自定义标记中要使用的方法。 第 2 步. 创建 TLD 下一步是定义包含自定义标记与处理它的 Java 类(或多个类)之间的映射的库。这个库是在一个名为标记库描述符(TLD)的 XML 文档中定义的。 清单 2. mytag.tld 文件 <?xml version="1.0" encoding="UTF-8"?> <taglib> <tlibversion>1.0</tlibversion> <jspversion>1.1</jspversion> <shortname>hello</shortname> <tag> <name>sayHello</name> <tagclass>com.vitamin.taglib.HelloTag</tagclass> <bodycontent>empty</bodycontent> </tag> </taglib> 所有关键信息都包含在 Tag 标记中,在这里映射了标记名和处理程序类,我们声明了标记对于正文内容的敏感性。对于更复杂的情况,我们可以使用其他的 XML 标记以提供有关库和标记的更多信息。在一个库中定义多个标记也很常见。 第 3 步. 引用这个标记库 有两种方法声明 JSP 页面与其库之间的引用。可以通过 Web 应用程序描述符(web.xml)声明一个静态引用,也可以直接在页面中声明一个动态引用。(可奇怪的是,我在用静态引用时,居然失败,web.xml里面放进去声明时就会报错。。。) 为了进行动态引用,只需在所有需要使用这个库的页面中加入一个 JSP 声明即可: <%@ taglib uri="/WEB-INF/mytag.tld" prefix="hello" %> 静态引用与动态引用的比较 在进行标记库的静态引用时,JSP 声明必须查询 web.xml 文件以执行库查询。这意味着如果移动或者重命名了库,或者希望在 web.xml 文件中加入更多的库,就必须停止服务器、更新 web.xml 文件、然后重新启动服务器。动态方法让 JSP 页直接指向 TLD 位置,因而是在解释 JSP 页面时进行处理。 静态方法提供了页面与库的实际名和位置之间一定程度的非直接性,这可以为您提供一些改变这些属性而不修改页面的灵活性。另一方面,动态方法提供了更大的灵活性,让您可以在运行时增加和移动标记声明。如果您对动态方法感兴趣,但是又担心做了一些改变后、有可能要更新多个页面的维护负担,那么您可以始终将 JSP 声明放到一个单独的 JSP 文件中,并在每一个要访问 Web 应用程序的自定义库的页面中加入这一页。这使您具有在运行时只需要更新信息一次就可以增加库的灵活性。 第 4 步. 在 JSP 页面中使用标记 完成了所有这些准备工作后,我们就可以在 JSP 页面中使用这些自定义标记了。 清单 3. 带有自定义标记的 JSP 页 <%@ page language="java" import="java.util.*" pageEncoding="GBK"%> <%@ taglib uri="/WEB-INF/mytag.tld" prefix="hello" %> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <hello:sayHello/> </body> </html> 用JSTL 节省时间 您所需要的自定义标记功能中也许有多达百分之八十已经由 J2EE 团体创建并标准化了。使用现有的标记库而不是从头创建所有东西会使您节省大量时间和精力。尽管在公共域有数十种库,不过业界汇集了一个特定的自定义库。Java 标准标记库(JSTL)是由 Java Community Process 设计的,其参考实现是由 Apache Group 通过 Jakarta Taglibs 项目所开发和维护的. JSTL 定义了针对常见 Web 应用程序处理需求,如变量支持、流程控制、URL 管理、XML 操作、国际化、数据库访问等等的标记。除了一组丰富的标记外,JSTL 还定义了自己的表达式语言(EL)。EL 使我们可以容易地访问应用程序数据并更容易在不使用脚本或者请求时表达式的条件下操作这些数据。 除了节省您从头开发所有标记的时间和精力,JSTL 还具有标准化和业界承认的所有好处。这些好处包括厂商支持、大量介绍文字、以及有很大的机会找到具有 JSTL 经验的雇员或者承包商。 结束语 在 J2EE Web 开发中越来越多地需要将业务和表示逻辑分离,JSP 自定义标记提供了替代简单的老 JavaBean 和 Java 脚本的一个有吸引力的方法。更好的是在 JSTL 中已存在一组已定义的标准的自定义标记库。 另外,标记库技术虽然解决了java代码和html混合的问题,但却带来了另一个问题,就是使用了标记库的页面不能进行可视化设计了!!!因为开发工具根本不能运行你后台的代码,所以就显示不出来页面的结果了。于是,JSF就出现了。它一改以往的基于Web的Request-Response处理机制,而是采用了类似Swing的的事件驱动处理机制。它简化了Web表单的有效性验证,Request参数解析,状态管理和多线程支持等任务,我们只需要实现具体的事件处理模块和事件逻辑模块就可以了。 本文转自Phinecos(洞庭散人)博客园博客,原文链接:http://www.cnblogs.com/phinecos/archive/2006/06/25/435236.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

swift:入门知识之协议与扩展

swift中使用protocol声明一个协议接口 swift中类、枚举和结构体都可以实现协议接口 swift中类中的方法都可以修改成员变量的值 swift中结构体中的方法默认是不能修改成员变量的,添加mutating关键字后就可以修改了 swift中使用extension来为现有的类型添加功能。你可以使用扩展来给任意类型添加协议,甚至是你从外部库或者框架中导入的类型 swift中协议接口的委托代理模式和Objective-C基本上是一样的,都是主方设置一个代理人,然后将事情的处理委托给这个代理人去办,而主方自己只需要声明协议的规则即可。记住,代理人必须按照主方设定的规则去处理这些需要做的事情。不管代理人是谁,只要遵从协议就可以成为主方的委托者。 Swift 中的扩展可以: 1. 添加计算型属性和计算静态属性 2. 定义实例方法和类型方法 3. 提供新的构造器 4. 定义下标 5. 定义和使用新的嵌套类型 6. 使一个已有类型符合某个接口 具体举例如下: //声明一个ExampleProtocol协议,有一个成员变量和一个默认必须实现的方法 //声明一个协议 protocol ExampleProtocol{ //声明一个成员变量,并设置一个getter方法 var simpleDescription:String{get} mutating func adjust() } //定义一个SimpleClass类继承ExampleProtocol协议 //定义一个类继承协议 class SimpleClass: ExampleProtocol { var simpleDescription:String = "A very simple class" func adjust() { simpleDescription += " adjust" } } var simpleclass = SimpleClass() //创建对象 simpleclass.adjust() //实现下一中的必须实现的方法 simpleclass.simpleDescription //用get方法获取属性值 "A very simple class adjust" //定义一个SimpleStruct结构体继承ExampleProtocol协议 //定义一个结构体继承协议 struct SimpleStruct:ExampleProtocol { var simpleDescription:String = "A very simple struct" //必须用关键词mutating修饰,才能修改属性值 mutating func adjust() { simpleDescription += "struct" } } var simplestruct = SimpleStruct() //创建结构体成员变量 simplestruct.adjust() //实现下一中的必须实现的方法 simplestruct.simpleDescription //用get方法获取属性值 "A very simple structstruct --------------------------------------------------------------------------------------------------------- //声明一个Myprotocol协议,有一个成员变量和一个默认必须实现的方法,还有一个可选的方法 //定义一个有可选方法的协议 @objc protocol MyProtocol{ //声明一个成员变量,并设置一个getter和setter方法 var contentDescription:String {get set} func method() //可选的方法 optional func adjust() } //定义一个Boy类继承Myprotocol这个协议 class Boy:MyProtocol{ var contentDescription:String = "he is a boy" //实现可选的方法 func method() { contentDescription += ",good dood study" } //实现必须实现的方法 func adjust(){ contentDescription += ",okay" } } let boy = Boy() boy.contentDescription = "Tom" //set方法赋值 boy.method() //实现必须实现的方法 boy.adjust() //实现可选的方法 boy.contentDescription //get方法取值 "Tom ,good good study,okay" --------------------------------------------------------------------------------------------------------- //定义一个扩展继承ExampleProtocol协议 //定义一个类扩展 extension Int:ExampleProtocol{ var simpleDescription:String{ return "The number \(self)" } mutating func adjust(){ self += 24 } } 7.simpleDescription // 7 //自定义一个扩展 程序猿神奇的手,每时每刻,这双手都在改变着世界的交互方式! 分类: Swift开发技术 本文转自当天真遇到现实博客园博客,原文链接: http://www.cnblogs.com/XYQ-208910/p/4905128.html如需转载请自行联系原作者

优秀的个人博客,低调大师

Docker 从入门到放弃(一)安装

前言 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。 Docker采用 C/S架构 Docker daemon 作为服务端接受来自客户的请求,并处理这些请求(创建、运行、分发容器)。 客户端和服务端既可以运行在一个机器上,也可通过 socket 或者RESTful API 来进行通信。 Docker daemon 一般在宿主主机后台运行,等待接收来自客户端的消息。 Docker 客户端则为用户提供一系列可执行命令,用户用这些命令实现跟 Docker daemon 交互。 安装 前提条件 Docker 要求 Ubuntu 系统的内核版本高于 3.10 ,查看本页面的前提条件来验证你的 Ubuntu 版本是否支持 Docker。 通过 uname -r 命令查看你当前的内核版本 # uname -r 4.4.0-93-generic 使用脚本安装 Docker 1、获取最新版本的 Docker 安装包 # wget -qO- https://get.docker.com/ | sh # Executing docker install script, commit: 11aa13e + sh -c apt-get update -qq >/dev/null + sh -c apt-get install -y -qq apt-transport-https ca-certificates curl software-properties-common >/dev/null + sh -c curl -fsSL "https://download.docker.com/linux/ubuntu/gpg" | apt-key add -qq - >/dev/null + sh -c echo "deb [arch=amd64] https://download.docker.com/linux/ubuntu trusty edge" > /etc/apt/sources.list.d/docker.list + [ ubuntu = debian ] + sh -c apt-get update -qq >/dev/null + sh -c apt-get install -y -qq --no-install-recommends docker-ce >/dev/null + sh -c docker version Client: Version: 17.11.0-ce API version: 1.34 Go version: go1.8.3 Git commit: 1caf76c Built: Mon Nov 20 18:36:37 2017 OS/Arch: linux/amd64 Server: Version: 17.11.0-ce API version: 1.34 (minimum version 1.12) Go version: go1.8.3 Git commit: 1caf76c Built: Mon Nov 20 18:35:10 2017 OS/Arch: linux/amd64 Experimental: false If you would like to use Docker as a non-root user, you should now consider adding your user to the "docker" group with something like: sudo usermod -aG docker your-user Remember that you will have to log out and back in for this to take effect! WARNING: Adding a user to the "docker" group will grant the ability to run containers which can be used to obtain root privileges on the docker host. Refer to https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface for more information. 安装完成后有个提示: 当要以非root用户可以直接运行docker时,需要执行 sudo usermod -aG docker runoob 命令,然后重新登陆,否则会报错 2、启动docker 后台服务 sudo service docker start start: Job is already running: docker 3、用Hello World校验Docker的安装 用Docker运行Hello World镜像,命令如下: # docker run hello-world Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world ca4f61b1923c: Pull complete Digest: sha256:be0cd392e45be79ffeffa6b05338b98ebb16c87b255f48e297ec7f98e123905c Status: Downloaded newer image for hello-world:latest Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://cloud.docker.com/ For more examples and ideas, visit: https://docs.docker.com/engine/userguide/ 可见,Docker注册服务器从Docker Hub获取到最新的Hello World镜像,下载到了本地。可以再次运行Hello World镜像。 # docker run hello-world Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://cloud.docker.com/ For more examples and ideas, visit: https://docs.docker.com/engine/userguide/ 二、使用 1、Docker Hello World Docker 允许你在容器内运行应用程序, 使用 docker run 命令来在容器内运行一个应用程序 root@aliyunTinywan:~# docker run ubuntu:15.10 /bin/echo "Hello world" Unable to find image 'ubuntu:15.10' locally 15.10: Pulling from library/ubuntu 7dcf5a444392: Pull complete 759aa75f3cee: Pull complete 3fa871dc8a2b: Pull complete 224c42ae46e7: Pull complete Digest: sha256:02521a2d079595241c6793b2044f02eecf294034f31d6e235ac4b2b54ffc41f3 Status: Downloaded newer image for ubuntu:15.10 Hello world Docker首先从本地主机上查找镜像是否存在,如果不存在,Docker 就会从镜像仓库 Docker Hub 下载公共镜像。这里发现镜像ubuntu:15.10 不存在,正在从镜像仓库下载 参数解析: docker:Docker 的二进制执行文件。 run:与前面的 docker 组合来运行一个容器。 ubuntu:15.10:指定要运行的镜像,Docker首先从本地主机上查找镜像是否存在,如果不存在,Docker 就会从镜像仓库Docker Hub下载公共镜像。 /bin/echo "Hello world":在启动的容器里执行的命令 root@aliyunTinywan:~# docker run ubuntu:15.10 /bin/echo "Hello world" Hello world 以上命令完整的意思可以解释为:Docker 以 ubuntu15.10 镜像创建一个新容器,然后在容器里执行 bin/echo "Hello world",然后输出结果。 2、运行交互式的容器 通过docker的两个参数 -i -t,让docker运行的容器实现"对话"的能力 root@aliyunTinywan:~# docker run -i -t ubuntu:15.10 /bin/bash root@aliyunTinywan:/# 参数解析: -t:在新容器内指定一个伪终端或终端。 -i:允许你对容器内的标准输入 (STDIN) 进行交互。 此时我们已进入一个 ubuntu15.10系统的容器,尝试在容器中运行命令 cat /proc/version 和 ls 分别查看当前系统的版本信息和当前目录下的文件列表 root@aliyunTinywan:/# cat /proc/version Linux version 4.4.0-93-generic (buildd@lcy01-28) (gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.3) ) #116~14.04.1-Ubuntu SMP Mon Aug 14 16:07:05 UTC 2017 root@aliyunTinywan:/# cat /etc/issue Ubuntu 15.10 \n \l root@aliyunTinywan:/# ls bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var 可以通过运行exit命令或者使用CTRL+D来退出容器,查看当前真实的服务器系统版本 root@18c5f2d5476b:/# exit exit root@iZ235mi4a64Z:~# cat /etc/issue Ubuntu 14.04.5 LTS \n \l 3、启动容器(后台模式) 使用以下命令创建一个以进程方式运行的容器 root@iZ235mi4a64Z:~# docker run -d ubuntu:15.10 /bin/sh -c "while true; do echo hello world; sleep 1; done" 6ddd469230b5402251c4fd3214b63f6a6af7d9e2711f8944a9d74b36346bbd5a 在输出中,我们没有看到期望的"hello world",而是一串长字符 2b1b7a428627c51ab8810d541d759f072b4fc75487eed05812646b8534a2fe63 这个长字符串叫做容器ID,对每个容器来说都是唯一的,我们可以通过容器ID来查看对应的容器发生了什么。 首先,我们需要确认容器有在运行,可以通过 docker ps 来查看 root@iZ235mi4a64Z:~# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6ddd469230b5 ubuntu:15.10 "/bin/sh -c 'while t…" About a minute ago Up About a minute romantic_visvesvaraya CONTAINER ID:容器ID NAMES:自动分配的容器名称 在容器内使用docker logs命令,查看容器内的标准输出 (1)使用ID root@iZ235mi4a64Z:~# docker logs 6ddd469230b5 hello world hello world hello world ... (2)使用NAMES root@iZ235mi4a64Z:~# docker logs romantic_visvesvaraya hello world hello world ... 发现结果是一样的,输出了同样的结果 4、停止容器 使用 docker stop 命令来停止容器,让然啦,要指定停止的容器对象啦,不然会这样子 root@iZ235mi4a64Z:~# docker stop "docker stop" requires at least 1 argument. See 'docker stop --help'. Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...] [flags] Stop one or more running containers 指定一个容器 root@iZ235mi4a64Z:~# docker stop 6ddd469230b5 6ddd469230b5 通过 docker ps 查看,容器已经停止工作 root@iZ235mi4a64Z:~# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 也可以用下面的NAMES命令来停止 docker stop romantic_visvesvaraya

优秀的个人博客,低调大师

python spark 决策树 入门demo

Refer to theDecisionTreePython docsandDecisionTreeModelPython docsfor more details on the API. from pyspark.mllib.tree import DecisionTree, DecisionTreeModel from pyspark.mllib.util import MLUtils # Load and parse the data file into an RDD of LabeledPoint. data = MLUtils.loadLibSVMFile(sc, 'data/mllib/sample_libsvm_data.txt') # Split the data into training and test sets (30% held out for testing) (trainingData, testData) = data.randomSplit([0.7, 0.3]) # Train a DecisionTree model. # Empty categoricalFeaturesInfo indicates all features are continuous. model = DecisionTree.trainClassifier(trainingData, numClasses=2, categoricalFeaturesInfo={}, impurity='gini', maxDepth=5, maxBins=32) # Evaluate model on test instances and compute test error predictions = model.predict(testData.map(lambda x: x.features)) labelsAndPredictions = testData.map(lambda lp: lp.label).zip(predictions) testErr = labelsAndPredictions.filter(lambda (v, p): v != p).count() / float(testData.count()) print('Test Error = ' + str(testErr)) print('Learned classification tree model:') print(model.toDebugString()) # Save and load model model.save(sc, "target/tmp/myDecisionTreeClassificationModel") sameModel = DecisionTreeModel.load(sc, "target/tmp/myDecisionTreeClassificationModel") Find full example code at "examples/src/main/python/mllib/decision_tree_classification_example.py" in the Spark repo. classpyspark.mllib.tree.DecisionTree[source] Learning algorithm for a decision tree model for classification or regression. New in version 1.1.0. classmethodtrainClassifier( data, numClasses, categoricalFeaturesInfo, impurity='gini', maxDepth=5, maxBins=32, minInstancesPerNode=1, minInfoGain=0.0) [source] Train a decision tree model for classification. Parameters: data– Training data: RDD of LabeledPoint. Labels should take values {0, 1, ..., numClasses-1}. numClasses– Number of classes for classification. categoricalFeaturesInfo– Map storing arity of categorical features. An entry (n -> k) indicates that feature n is categorical with k categories indexed from 0: {0, 1, ..., k-1}. impurity– Criterion used for information gain calculation. Supported values: “gini” or “entropy”. (default: “gini”) maxDepth– Maximum depth of tree (e.g. depth 0 means 1 leaf node, depth 1 means 1 internal node + 2 leaf nodes). (default: 5) maxBins– Number of bins used for finding splits at each node. (default: 32) minInstancesPerNode– Minimum number of instances required at child nodes to create the parent split. (default: 1) minInfoGain– Minimum info gain required to create a split. (default: 0.0) Returns: DecisionTreeModel. Example usage: >>> from numpy import array >>> from pyspark.mllib.regression import LabeledPoint >>> from pyspark.mllib.tree import DecisionTree >>> >>> data = [ ... LabeledPoint(0.0, [0.0]), ... LabeledPoint(1.0, [1.0]), ... LabeledPoint(1.0, [2.0]), ... LabeledPoint(1.0, [3.0]) ... ] >>> model = DecisionTree.trainClassifier(sc.parallelize(data), 2, {}) >>> print(model) DecisionTreeModel classifier of depth 1 with 3 nodes >>> print(model.toDebugString()) DecisionTreeModel classifier of depth 1 with 3 nodes If (feature 0 <= 0.0) Predict: 0.0 Else (feature 0 > 0.0) Predict: 1.0 >>> model.predict(array([1.0])) 1.0 >>> model.predict(array([0.0])) 0.0 >>> rdd = sc.parallelize([[1.0], [0.0]]) >>> model.predict(rdd).collect() [1.0, 0.0] 摘自:https://spark.apache.org/docs/latest/api/python/pyspark.mllib.html#pyspark.mllib.tree.DecisionTree 本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/bonelee/p/7150483.html ,如需转载请自行联系原作者

优秀的个人博客,低调大师

centos6 - elk基础入门搭建

1 2 3 4 5 6 7 [root@host-192-168-53-108~] #rm-rf/etc/yum.repos.d/* [root@host-192-168-53-108~] #wget-O/etc/yum.repos.d/CentOS-Base.repohttp://mirrors.aliyun.com/repo/Centos-6.repo [root@host-192-168-53-108~] #yumcleanall [root@host-192-168-53-108~] #yum-yinstalljava-1.8.0-openjdk* [root@host-192-168-53-108~] #wgethttps://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.5.0.rpm [root@host-192-168-53-108~] #rpm-ivhelasticsearch-5.5.0.rpm [root@host-192-168-53-108~] #chkconfig--addelasticsearch 1 2 [root@host-192-168-53-108~] #cat/etc/hosts 192.168.53.108elk1 1 2 3 4 5 6 7 8 9 [root@host-192-168-53-108~] #cat/etc/elasticsearch/elasticsearch.yml node.name:elk1 network.host:192.168.53.108 http.port:9200 bootstrap.memory_lock: false bootstrap.system_call_filter: false discovery.zen. ping .unicast.hosts:[elk1] http.cors.enabled: true http.cors.allow-origin: "*" 1 2 3 4 [root@host-192-168-53-108~] #cat/etc/elasticsearch/jvm.options|grep-v'^#'|grep-v^$ #修改 -Xms6g -Xmx6g 1 2 3 4 5 [root@host-192-168-53-108~] #vim/etc/security/limits.conf *softnofile1000000 *hardnofile1000000 *softnproc1000000 *hardnproc1000000 1 2 3 [root@host-192-168-53-108~] #cat/etc/security/limits.d/90-nproc.conf *softnproc100000 rootsoftnprocunlimited 1 2 3 4 5 6 [root@host-192-168-53-108~] #cd/usr/local/ [root@host-192-168-53-108 local ] #gitclonegit://github.com/mobz/elasticsearch-head.git [root@host-192-168-53-108 local ] #wgethttps://nodejs.org/dist/v8.2.0/node-v8.2.0-linux-x64.tar.gz--no-check-certificate [root@host-192-168-53-108 local ] #tarzxfnode-v8.2.0-linux-x64.tar.gz [root@host-192-168-53-108 local ] #ln-s/usr/local/node-v8.2.0-linux-x64/bin/node/usr/sbin/node [root@host-192-168-53-108 local ] #ln-s/usr/local/node-v8.2.0-linux-x64/bin/npm/usr/sbin/npm 1 2 3 4 5 #设置npm代理镜像 [root@host-192-168-53-108 local ] #npmconfigsetregistryhttps://registry.npm.taobao.org [root@host-192-168-53-108 local ] #npminstall-ggrunt [root@host-192-168-53-108 local ] #ln-s/usr/local/node-v8.2.0-linux-x64/lib/node_modules/grunt/bin/grunt/usr/sbin/grunt [root@host-192-168-53-108 local ] #cdelasticsearch-head/ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 [root@host-192-168-53-108elasticsearch- head ] #npminstall Errormakingrequest. Error:connectETIMEDOUT52.216.1.0:443 atObject.exports._errnoException(util.js:1024:11) atexports._exceptionWithHostPort(util.js:1047:20) atTCPConnectWrap.afterConnect[asoncomplete](net.js:1150:14) Pleasereportthisfulllogathttps: //github .com /Medium/phantomjs npmWARNelasticsearch- head @0.0.0licenseshouldbeavalidSPDXlicenseexpression npmWARNoptionalSKIPPINGOPTIONALDEPENDENCY:fsevents@1.1.2(node_modules /fsevents ): npmWARNnotsupSKIPPINGOPTIONALDEPENDENCY:Unsupportedplatform for fsevents@1.1.2:wanted{ "os" : "darwin" , "arch" : "any" }(current:{ "os" : "linux" , "arch" : "x64" }) npmERR!codeELIFECYCLE npmERR!errno1 npmERR!phantomjs-prebuilt@2.1.14 install :`node install .js` npmERR!Exitstatus1 npmERR! npmERR!Failedatthephantomjs-prebuilt@2.1.14 install script. npmERR!Thisisprobablynotaproblemwithnpm.Thereislikelyadditionalloggingoutputabove. npmERR!Acompletelogofthisruncanbefound in : npmERR! /root/ .npm /_logs/2017-07-26T11_29_47_063Z-debug .log 1 2 [root@host-192-168-53-108elasticsearch- head ] #npminstallphantomjs-prebuilt@2.1.14--ignore-scripts [root@host-192-168-53-108elasticsearch- head ] #npminstall 1 2 3 4 [root@host-192-168-53-108elasticsearch- head ] #vim/usr/local/elasticsearch-head/_site/app.js #把localhost改为ip this.base_uri=this.config.base_uri||this.prefs.get( "app-base_uri" )|| "http://localhost:9200" ; this.base_uri=this.config.base_uri||this.prefs.get( "app-base_uri" )|| "http://192.168.53.108:9200" ; 1 2 3 4 5 6 7 8 9 10 11 [root@host-192-168-53-108elasticsearch- head ] #vim/usr/local/elasticsearch-head/Gruntfile.js connect:{ server:{ options:{ hostname : "0.0.0.0" , #添加此行 port:9100, base: '.' , keepalive: true } } } 1 2 3 4 [root@host-192-168-53-108elasticsearch- head ] #gruntserver& [root@host-192-168-53-108elasticsearch- head ] #echo"cd/usr/local/elasticsearch-head;gruntserver&">>/etc/rc.local [root@host-192-168-53-108elasticsearch- head ] #cd [root@host-192-168-53-108~] #wgethttps://artifacts.elastic.co/downloads/logstash/logstash-5.5.0.rpm 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 [root@host-192-168-53-108~] #vim/etc/logstash/conf.d/system.conf input{ file { path=> "/var/log/messages" type => "systemlog" start_position=> "beginning" stat_interval=> "2" } } output{ elasticsearch{ hosts=>[ "192.168.53.108:9200" ] index=> "logstash-systemlog-%{+YYYY.MM.dd}" } } 1 [root@host-192-168-53-108~] #/usr/share/logstash/bin/logstash-f/etc/logstash/conf.d/system.conf 1 2 #在Elasticsearch中查看 #浏览器访问http://192.168.53.108:9100/选择基本查询搜素 1 2 [root@host-192-168-53-108~] #wgethttps://artifacts.elastic.co/downloads/kibana/kibana-5.5.0-x86_64.rpm [root@host-192-168-53-108~] #rpm-ivhkibana-5.5.0-x86_64.rpm 1 2 3 4 [root@host-192-168-53-108~] #cat/etc/kibana/kibana.yml|grep-v'^#'|grep-v^$ server.port:5601 server.host: "0.0.0.0" elasticsearch.url: "http://elk1:9200" 1 2 [root@host-192-168-53-108~] #/etc/init.d/kibanastart [root@host-192-168-53-108~] #chkconfig--addkibana 本文转自谢无赖51CTO博客,原文链接:http://blog.51cto.com/xieping/1951765,如需转载请自行联系原作者

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册