zoukankan      html  css  js  c++  java
  • 《python数据分析(第2版)-阿曼多.凡丹戈》读书笔记第9章-分析文本数据和社交媒体

    python数据分析个人学习读书笔记-目录索引

    第9章分析文本数据和社交媒体

       在前几章中,我们着重讨论了结构化数据的分析,主要涉及列表格式的数据。实际上,跟结构化数据一样,纯文本也是最常见的格式之一。文本分析需要用到词频分布分析、模式识别、标注、链接和关联分析(link and association analysis)、情感分析和可视化等。这里将借助Python自然语言工具包(The Python Natural Language Toolkit,NLTK)来分析文本。NLTK自身带有一个文本样本集,这个样本集名为corpora。同时,scikitlearn程序库也提供了许多文本分析工具,本章也会对这些工具进行简要的介绍。

      此外,在本章中还会举例说明网络分析。本章涉及的主题如下。

    • 安装NLTK
    • NLTK简介
    • 滤除停用字、姓名和数字
    • 词袋模型
    • 词频分析
    • 朴素贝叶斯分类
    • 情感分析
    • 创建词云
    • 社交网络分析

    9.1NLTK

      安装NLTK:

    1 pip3 install nltk scikit-learn

    9.2NLTK简介

       NLTK是一个用来分析自然语言文本(如英文句子)的Python应用程序接口。NLTK起源于2001年,最初设计是用来进行教学的。

      虽然我们在9.1节安装了NLTK,但还不够:还需要下载NLTK语料库。需要注意的是,这里的下载量相对较大(约1.8 GB),但是只需要下载一次。除非我们确切地知道自己需要哪种语料库,否则最好下载所有可用的语料库。从Python shell下载语料库的命令如下。

    1 $ python3
    2 >>> import nltk
    3 >>> nltk.download()

      这时,会出现一个GUI应用程序,你可以指定要下载的文件以及放到何处,如图9-1所示。

     邀月工作室

      如果是NLTK新手,最方便的方法就是选择默认选项并下载所有内容。在本章中,我们将需要用到停用词、电影评论、名字和古腾堡语料库。所以,我们鼓励读者根据ch-09.ipynb文件中的代码来学习下列部分。

        Tips:如果安装NLTK方面有疑惑,这篇文章或许对你有帮助《数据分析实战-托马兹.卓巴斯》读书笔记第9章--自然语言处理NLTK(分析文本、词性标注、主题抽取、文本数据分类)

    9.3滤除停用字、姓名和数字

       进行文本分析时,我们经常需要对停用字(Stopwords)进行剔除。这里所谓的停用字,就是那些经常见、但是没有多大信息含量的词。NLTK为很多语种都提供了停用字语料库。下面加载英语停用字语料并输出部分单词。

    1 sw = set(nltk.corpus.stopwords.words('english'))
    2 print("Stop words:", list(sw)[:7])

      下面是输出的部分常用字。

    Stop words: ['yours', 'off', 'own', 'so', "won't", 'all', 'doing']

      请注意,这个语料库中的所有单词都是小写的。

      此外,NLTK还提供了一个Gutenberg语料库。Gutenberg项目是一个数字图书馆计划,供人们在互联网上阅读图书。

      下面加载Gutenberg语料库并输出部分文件的名称。

    1 gb = nltk.corpus.gutenberg
    2 print("Gutenberg files:
    ", gb.fileids()[-5:])

      下面是输出的某些书籍的名称,其中有些你可能比较熟悉。

    Gutenberg files:
     ['milton-paradise.txt', 'shakespeare-caesar.txt', 'shakespeare-hamlet.txt', 'shakespeare-macbeth.txt', 'whitman-leaves.txt']

      现在,从milton-paradise.txt文件中提取前两句内容,供下面过滤使用。下面给出具体代码。

    1 text_sent = gb.sents("milton-paradise.txt")[:2]
    2 print("Unfiltered:", text_sent)

      下面是输出的句子。

    Unfiltered: [['[', 'Paradise', 'Lost', 'by', 'John', 'Milton', '1667', ']'], ['Book', 'I']]

      现在,过滤掉下面的停用字。

    1 for sent in text_sent:
    2     filtered = [w for w in sent if w.lower() not in sw]
    3     print("Filtered:
    ", filtered)

      对于第一句,过滤后变成以下格式。

    Filtered:
     ['[', 'Paradise', 'Lost', 'John', 'Milton', '1667', ']']

      注意,与之前相比,单词by已经被过滤掉了,因为它出现在停用字语料库中了。有时,我们希望将文本中的数字和姓名也删掉。我们可以根据词性(Part of Speech,POS)标签来删除某些单词。在这个标注方案中,数字对应着基数(Cardinal Number,CD)标签。

      姓名对应着单数形式的专有名词(the proper noun singular,NNP)标签。标注是基于启发式方法进行处理的,当然,这不可能非常精确。这个主题过于宏大,恐怕需要整本书来进行描述,详见前言部分。在过滤文本时,我们可以使用pos_tag()函数获取文本内所含的标签,具体如下。

    1     tagged = nltk.pos_tag(filtered)
    2     print("Tagged:
    ", tagged)

      对于我们的文本,将得到如下各种标签。

    Tagged:
     [('[', 'JJ'), ('Paradise', 'NNP'), ('Lost', 'NNP'), ('John', 'NNP'), ('Milton', 'NNP'), ('1667', 'CD'), (']', 'NN')]

      上面的pos_tag()函数将返回一个元组列表,其中各元组的第二个元素就是文本对应的标签。可见,一些单词虽然被标注为NNP,但是它们并不是。这里所谓的启发式方法,就是如果单词的第一个字母是大写的,那么就将其标注为NNP。如果将上面的文本全部转换为小写,那么就会得到不同的结果,这个留给读者自行练习。实际上,我们很容易就能利用NNP和CD标签来删除列表中的单词,代码如下。

    1     words= []
    2     for word in tagged:
    3         if word[1] != 'NNP' and word[1] != 'CD':
    4            words.append(word[0]) 
    5 
    6     print("Words:
    ",words)

      下列代码摘自本书代码包中的ch-09.ipynb文件。

     1 import nltk
     2 from nltk import data
     3 data.path.append(r'D:download
    ltk_data') # 这里的路径需要换成自己数据文件下载的路径
     4 for sent in text_sent:
     5     filtered = [w for w in sent if w.lower() not in sw]
     6     print("Filtered:
    ", filtered)
     7     tagged = nltk.pos_tag(filtered)
     8     print("Tagged:
    ", tagged)
     9 
    10     words= []
    11     for word in tagged:
    12         if word[1] != 'NNP' and word[1] != 'CD':
    13            words.append(word[0]) 
    14 
    15     print("Words:
    ",words)

    9.4词袋模型

       所谓词袋模型,即它认为一篇文档是由其中的词构成的一个集合(即袋子),词与词之间没有顺序以及先后的关系。对于文档中的每个单词,我们都要计算它出现的次数,即单词计数(word counts)。据此,我们可以进行类似垃圾邮件识别之类的统计分析。

      如果有一批文档,那么每个唯一字(unique word)都可以视为语料库中的一个特征。这里所谓的“特征”,可以理解为参数或者变量。利用所有的单词计数,我们可以为每个文档建立一个特征向量这里的“向量”一词借用的是其数学含义。如果一个单词存在于语料库中,但是不存在于文档中,那么这个特征的值就为0。令人惊讶的是,NLTK至今尚未提供可以方便创建特征向量的实用程序。不过,我们可以借用Python机器学习库scikit-learn中的CountVectorizer类来轻松创建特征向量。第10章将对scikit-learn进行更详尽的介绍。

      下面从NLTK的Gutenberg语料库加载两个文本文档,代码如下。

    1 hamlet = gb.raw("shakespeare-hamlet.txt")
    2 macbeth = gb.raw("shakespeare-macbeth.txt")

      现在我们去掉英语停用词并创建特征向量,代码如下。

    1 cv = sk.feature_extraction.text.CountVectorizer(stop_words='english')
    2 print("Feature vector:
    ", cv.fit_transform([hamlet, macbeth]).toarray())

      下面是两个文档对应的特征向量。

    Feature vector:
     [[ 1  0  1 ... 14  0  1]
     [ 0  1  0 ...  1  1  0]]

      下面,我们输出部分特征(唯一字)值。

    1 print("Features:
    ", cv.get_feature_names()[:5])

      这些特征是按字母顺序排序的。

    Features:
     ['1599', '1603', 'abhominably', 'abhorred', 'abide']

      下列代码摘自本书代码包中的ch-09.ipynb文件。

     1 import nltk
     2 import sklearn as sk
     3 from nltk import data
     4 data.path.append(r'D:download
    ltk_data') # 这里的路径需要换成自己数据文件下载的路径
     5 
     6 hamlet = gb.raw(“shakespeare-hamlet.txt”)
     7 macbeth = gb.raw(“shakespeare-macbeth.txt”)
     8 
     9 cv = sk.feature_extraction.text.CountVectorizer(stop_words=’english’)
    10 
    11 print(“Feature vector:
    ”, cv.fit_transform([hamlet, macbeth]).toarray())
    12 
    13 print(“Features:
    ”, cv.get_feature_names()[:5])

    9.5词频分析

       NLTK提供的FreqDist类可以用来将单词封装成字典并计算给定单词列表中各个单词出现的次数。下面,我们来加载Gutenberg项目中莎士比亚的Julius Caesar中的文本。

      首先,把停用词和标点符号剔除掉,代码如下。

    1 punctuation = set(string.punctuation)
    2 filtered = [w.lower() for w in words if w.lower() not in sw and w.lower() not in punctuation]

      然后,创建一个FreqDist对象并输出频率最高的键和值,代码如下。

    1 fd = nltk.FreqDist(filtered)
    2 print("Words", list(fd.keys())[:5])
    3 print("Counts", list(fd.values())[:5])

      输出的键和值如下。

    Words ['tragedie', 'julius', 'caesar', 'william', 'shakespeare']
    Counts [2, 1, 190, 1, 1]

      很明显,这个列表中的第一个字并非英语单词,因此需要添加一种启发式搜索(Heuristic)方法,只选择最少含有两个字符的单词。对于NLTK提供的FreqDist类,我们既可以使用类似于字典的访问方法,也可以使用更便利的其他方法。下面,我们要提取最常出现的单词以及对应的出现次数。

    1 print("Max", fd.max())
    2 print("Count", fd['d'])

      对应下面的结果,你肯定不会感到吃惊。

    Max caesar
    Count 0

      目前,我们只是针对单个单词构成的词汇进行了分析,不过可以推而广之,将分析扩展到含有两个单词和3个单词的词汇上,对于后面这两种,我们分别称之为双字词和三字词。对于这两种分析,分别有对应的函数,即bigrams()函数和trigrams()函数。现在,我们再次进行文本分析,不过,这次针对的是双字词。

    1 fd = nltk.FreqDist(nltk.bigrams(filtered))
    2 print("Bigrams", list(fd.keys())[:5])
    3 print("Counts", list(fd.values())[:5])
    4 print("Bigram Max", fd.max())
    5 print("Bigram count", fd[('let', 'vs')])

      结果如下。

    Bigrams [('tragedie', 'julius'), ('julius', 'caesar'), ('caesar', 'william'), ('william', 'shakespeare'), ('shakespeare', '1599')]
    Counts [1, 1, 1, 1, 1]
    Bigram Max ('let', 'vs')
    Bigram count 16

      下列代码摘自本书代码包中的ch-09.ipynb文件。

     1 import nltk
     2 import string
     3 from nltk import data
     4 data.path.append(r'D:download
    ltk_data') # 这里的路径需要换成自己数据文件下载的路径
     5 
     6 
     7 gb = nltk.corpus.gutenberg
     8 words = gb.words("shakespeare-caesar.txt")
     9 
    10 sw = set(nltk.corpus.stopwords.words('english'))
    11 punctuation = set(string.punctuation)
    12 filtered = [w.lower() for w in words if w.lower() not in sw and w.lower() not in punctuation]
    13 fd = nltk.FreqDist(filtered)
    14 print("Words", list(fd.keys())[:5])
    15 print("Counts", list(fd.values())[:5])
    16 print("Max", fd.max())
    17 print("Count", fd['d'])
    18 
    19 fd = nltk.FreqDist(nltk.bigrams(filtered))
    20 print("Bigrams", list(fd.keys())[:5])
    21 print("Counts", list(fd.values())[:5])
    22 print("Bigram Max", fd.max())
    23 print("Bigram count", fd[('let', 'vs')])

    9.6朴素贝叶斯分类

       分类算法是机器学习算法中的一种,用来判断给定数据项所属的类别,即种类或类型。比如,我们可以根据某些特征来分辨一部电影属于哪个流派等。这样,流派就是我们要预测的类别。第10章还会对机器学习做进一步介绍。此刻,我们要讨论的是一个名为朴素贝叶斯分类的流行算法,它常常用于进行文本文档的分析。

      朴素贝叶斯分类是一个概率算法,它基于概率与数理统计中的贝叶斯定理。贝叶斯定理给出了利用新证据修正某事件发生的概率的方法。例如,假设一个袋子里装有一些巧克力和其他物品,但是这些我们没法看到。这时,我们可以用P(D)表示从袋子中掏出一块深色巧克力的概率。同时,我们用P©代表掏出一块巧克力的概率。当然,因为全概率是1,所以P(D)和P©的最大取值也只能是1。贝叶斯定理指出,后验概率与先验概率和相似度的乘积成正比,具体公式如下。

      P(D|C)

      在上面的公式中,P(D|C)是在事件C发生的情况下事件D发生的可能性。在我们还没有掏出任何物品之前,P(D) = 0.5,因为我们尚未获得任何信息。实际应用这个公式时,我们必须知道P(C|D)和P(C),或者能够间接求出这两个概率。

      朴素贝叶斯分类之所以称为朴素,是因为它简单假设特征之间是相互独立的。实践中,朴素贝叶斯分类的效果通常都会很好,说明这个假设得到了一定程度的保证。近来,人们发现这个假设之所以有意义,理论上是有依据的。不过,由于机器学习领域发展迅猛,现在已经发明了多种效果更佳的算法。

      下面,我们将利用停用词或标点符号对单词进行分类。这里,我们将字长作为一个特征,因为停用词和标点符号往往都比较短。

      为此,我们需要定义如下所示的函数。

    1 def word_features(word):
    2    return {'len': len(word)}
    3 
    4 def isStopword(word):
    5     return word in sw or word in punctuation

      下面,我们对取自古登堡项目的shakespeare-caesar.txt中的单词进行标注,以区分是否为停用词,代码如下。

    1 labeled_words = ([(word.lower(), isStopword(word.lower())) for 
    2 word in words])
    3 random.seed(42)
    4 random.shuffle(labeled_words)
    5 print(labeled_words[:5])

      下面显示了5个标注后的单词。

    [('i', True), ('is', True), ('in', True), ('he', True), ('ambitious', False)]

      对于每个单词,我们可以求出其长度。

    1 featuresets = [(word_features(n), word) for (n, word) in 
    2 labeled_words]

      前几章我们介绍过拟合以及通过训练数据集和测试数据集的交叉验证来避免这种情况的方法。下面我们将要训练一个朴素贝叶斯分类器,其中90%的单词用于训练,剩下的10%用于测试。首先,创建训练数据集和测试数据集并针对数据展开训练,代码如下。

    1 cutoff = int(.9 * len(featuresets))
    2 train_set, test_set = featuresets[:cutoff], featuresets[cutoff:]
    3 classifier = nltk.NaiveBayesClassifier.train(train_set)

      现在,我们拿出一些单词,检查该分类器的效果。

    1 classifier = nltk.NaiveBayesClassifier.train(train_set)
    2 print("'behold' class", classifier.classify(word_features('behold')))
    3 print("'the' class", classifier.classify(word_features('the')))

      幸运的是,这些单词的分类完全正确:

    'behold' class False
    'the' class True

      然后,根据测试数据集来计算分类器的准确性,代码如下。

    1 print("Accuracy", nltk.classify.accuracy(classifier, test_set))

      这个分类器的准确度非常高,几乎达到85%。下面来看哪些特征的贡献最大。

    1 print(classifier.show_most_informative_features(5))

      结果显示如图9-2所示,在分类过程中字长的作用最大。

     邀月工作室

      下列代码摘自本书代码包中的ch-09.ipynb文件。

     1 mport nltk
     2 from nltk import data
     3 data.path.append(r'D:download
    ltk_data') # 这里的路径需要换成自己数据文件下载的路径
     4 import string
     5 import random
     6 
     7 sw = set(nltk.corpus.stopwords.words('english'))
     8 punctuation = set(string.punctuation)
     9 
    10 def word_features(word):
    11    return {'len': len(word)}
    12 
    13 def isStopword(word):
    14     return word in sw or word in punctuation
    15 gb = nltk.corpus.gutenberg
    16 words = gb.words("shakespeare-caesar.txt")
    17 
    18 labeled_words = ([(word.lower(), isStopword(word.lower())) for 
    19 word in words])
    20 random.seed(42)
    21 random.shuffle(labeled_words)
    22 print(labeled_words[:5])
    23 
    24 featuresets = [(word_features(n), word) for (n, word) in 
    25 labeled_words]
    26 cutoff = int(.9 * len(featuresets))
    27 train_set, test_set = featuresets[:cutoff], featuresets[cutoff:]
    28 classifier = nltk.NaiveBayesClassifier.train(train_set)
    29 print("'behold' class", classifier.classify(word_features('behold')))
    30 print("'the' class", classifier.classify(word_features('the')))
    31 
    32 print("Accuracy", nltk.classify.accuracy(classifier, test_set))
    33 print(classifier.show_most_informative_features(5))

    9.7情感分析

      随着社交媒体、产品评论网站及论坛的兴起,用来自动抽取意见的观点挖掘或情感分析也随之变成一个炙手可热的新研究领域。通常情况下,我们希望知道某个意见的性质是正面的、中立的还是负面的。当然,这种类型的分类我们前面就曾遇到过。也就是说,我们有大量的分类算法可用。还有一个方法就是,通过半自动的(经过某些人工编辑)方法来编制一个单词列表,每个单词赋予一个情感分,即一个数值(如单词“good”的情感分为5,而单词“bad”的情感分为−5)。如果有了这样一张表,就可以给文本文档中的所有单词打分,从而得出一个情感总分。当然,类别的数量可以大于3,如五星级评级方案。

      我们会应用朴素贝叶斯分类方法对NLTK的影评语料库进行分析,从而将影评分为正面的或负面的评价。首先,加载影评语料库并过滤掉停用词和标点符号。这些步骤在此略过,因为之前就介绍过了。也可以考虑更精细的过滤方案,不过,需要注意的是,如果过滤得过火了,就会影响准确性。下面通过categories()方法对影评文档进行标注,代码如下。

    1 labeled_docs = [(list(movie_reviews.words(fid)), cat)
    2         for cat in movie_reviews.categories()
    3         for fid in movie_reviews.fileids(cat)]

     完整的语料库拥有数以万计的唯一字,这些唯一字都可以用作特征,不过,这样做会极大地影响效率。这里,我们选用词频最高的前5%的单词作为特征。

    1 words = FreqDist(filtered)
    2 N = int(.05 * len(words.keys()))
    3 word_features = list(words.keys())[:N]

      对于每个文档,可以通过一些方法来提取特征,其中包括以下方法:

    • 检查给定文档是否含有某个单词;
    • 求出某个单词在给定文档中出现的次数;
    • 正则化单词计数,使得正则化后的最大单词计数小于或等于1;
    • 将上面的数值加1,然后取对数。这里之所以加1,是为了防止对0取对数;
    • 利用上面的数值组成一个度量指标。

      俗话说“条条大路通罗马”,不过,这其中肯定不乏有些道路能够让我们更安全,也能更快地到达罗马。下面定义一个函数,该函数会使用原始单词计数来作为度量指标,代码为如下。

    1 def doc_features(doc):
    2     doc_words = FreqDist(w for w in doc if not isStopWord(w))
    3     features = {}
    4     for word in word_features:
    5         features['count (%s)' % word] = (doc_words.get(word, 0))
    6     return features

      现在,可以训练我们的分类器了,具体方法与前面的例子相似。这里准确性达到78%,这个成绩已经相当不错了,非常接近情感分析成绩的上限。因为据研究发现,即便是人类,也无法对给定文档的表达出的感情的看法达成一致。因此,要想让情感分析软件获得满分是不可能的事情。

    下面的图9-3给出包含信息量最大的特征。

    邀月工作室

      如果仔细检查这个列表,我们很容易发现有一些褒义词,如“wonderful(妙不可言的)”和“outstanding(杰出的)”。而单词“bad(恶劣的)”“stupid(愚蠢的)”和“boring(无趣的)”则明显是一些贬义词。如果有兴趣,读者也可以分析其他的那些特征,这将作为一个作业留给读者自己完成。以下代码摘自本书代码包中的sentiment.py文件。

     1 import random
     2 from nltk import data
     3 data.path.append(r'D:download
    ltk_data') # 这里的路径需要换成自己数据文件下载的路径
     4 from nltk.corpus import movie_reviews
     5 from nltk.corpus import stopwords
     6 from nltk import FreqDist
     7 from nltk import NaiveBayesClassifier
     8 from nltk.classify import accuracy
     9 import string
    10 
    11 labeled_docs = [(list(movie_reviews.words(fid)), cat)
    12         for cat in movie_reviews.categories()
    13         for fid in movie_reviews.fileids(cat)]
    14 random.seed(42)
    15 random.shuffle(labeled_docs)
    16 
    17 review_words = movie_reviews.words()
    18 print("# Review Words", len(review_words))
    19 
    20 sw = set(stopwords.words('english'))
    21 punctuation = set(string.punctuation)
    22 
    23 def isStopWord(word):
    24     return word in sw or word in punctuation
    25 
    26 filtered = [w.lower() for w in review_words if not isStopWord(w.lower())]
    27 print("# After filter", len(filtered))
    28 words = FreqDist(filtered)
    29 N = int(.05 * len(words.keys()))
    30 word_features = list(words.keys())[:N]
    31 
    32 def doc_features(doc):
    33     doc_words = FreqDist(w for w in doc if not isStopWord(w))
    34     features = {}
    35     for word in word_features:
    36         features['count (%s)' % word] = (doc_words.get(word, 0))
    37     return features
    38 
    39 featuresets = [(doc_features(d), c) for (d,c) in labeled_docs]
    40 train_set, test_set = featuresets[200:], featuresets[:200]
    41 classifier = NaiveBayesClassifier.train(train_set)
    42 print("Accuracy", accuracy(classifier, test_set))
    43 
    44 print(classifier.show_most_informative_features())

    9.8创建词云

       阅读本书前,我们也许已在Wordle或其他地方见过词云了;如果没见过也不要紧,因为可以在本章看个够了。虽然Python有两个程序库都可以用来生成词云,但是它们生成词云的效果尚不能与Wordle网站的效果相媲美。所以,我们不妨利用Wordle网站的页面来创建词云。利用Wordle生成词云时,需要提供一个单词列表及其对应的权值,具体格式如下。

    Word1 : weight
    Word2 : weight

      现在,对前面例子中的代码稍作修改,让它输出这个字表。这里,我们将使用词频作为度量指标,选取词频排名靠前的单词。实际上,这里不需要任何新的代码,具体内容可以参考本书代码包中的ch-09.ipynb文件。

     1 from nltk import data
     2 data.path.append(r'D:download
    ltk_data') # 这里的路径需要换成自己数据文件下载的路径
     3 from nltk.corpus import movie_reviews
     4 from nltk.corpus import stopwords
     5 from nltk import FreqDist
     6 import string
     7 
     8 sw = set(stopwords.words('english'))
     9 punctuation = set(string.punctuation)
    10 
    11 def isStopWord(word):
    12     return word in sw or word in punctuation
    13 review_words = movie_reviews.words()
    14 filtered = [w.lower() for w in review_words if not isStopWord(w.lower())]
    15 
    16 words = FreqDist(filtered)
    17 N = int(.01 * len(words.keys()))
    18 tags = list(words.keys())[:N]
    19 
    20 for tag in tags:
    21     print(tag, ':', words[tag])

      将上面代码的输出结果复制粘贴到上面提到的Wordle页面,就能得到如图9-4所示的词云了。

    plot : 1513
    two : 1911
    teen : 151
    couples : 27
    go : 1113
    church : 69
    party : 183
    drink : 32
    drive : 105
    get : 1949
    accident : 104
    one : 5852
    guys : 268
    dies : 104
    girlfriend : 218
    continues : 88
    see : 1749
    life : 1586
    nightmares : 26
    deal : 219
    watch : 603
    movie : 5771
    sorta : 10
    find : 782
    critique : 61
    mind : 451
    fuck : 17
    generation : 96
    touches : 55
    cool : 208
    idea : 386
    presents : 78
    bad : 1395
    package : 30
    makes : 992
    review : 295
    even : 2565
    harder : 33
    write : 119
    since : 768
    generally : 103
    applaud : 10
    films : 1536
    attempt : 263
    break : 175
    mold : 14
    mess : 159
    head : 387
    lost : 409
    highway : 28
    memento : 10
    good : 2411
    ways : 189
    making : 602
    types : 48
    folks : 74
    snag : 2
    correctly : 17
    seem : 574
    taken : 225
    pretty : 528
    neat : 32
    concept : 114
    executed : 46
    terribly : 58
    problems : 293
    well : 1906
    main : 399
    problem : 396
    simply : 428
    jumbled : 12
    starts : 316
    normal : 111
    downshifts : 2
    fantasy : 97
    world : 1037
    audience : 914
    member : 126
    going : 888
    dreams : 131
    characters : 1859
    coming : 275
    back : 1060
    dead : 418
    others : 288
    look : 835
    like : 3690
    strange : 185
    apparitions : 5
    disappearances : 3
    looooot : 1
    chase : 159
    scenes : 1274
    tons : 21
    weird : 100
    things : 852
    happen : 220
    explained : 70
    personally : 44
    trying : 566
    unravel : 9
    film : 9517
    every : 947
    give : 561
    clue : 45
    kind : 559
    fed : 29
    biggest : 149
    obviously : 228
    got : 470
    big : 1064
    secret : 184
    hide : 40
    seems : 1033
    want : 560
    completely : 440
    final : 380
    five : 284
    minutes : 644
    make : 1642
    entertaining : 314
    thrilling : 46
    engaging : 79
    meantime : 19
    really : 1558
    sad : 108
    part : 714
    arrow : 29
    dig : 19
    flicks : 81
    actually : 837
    figured : 29
    half : 535
    way : 1693
    point : 685
    strangeness : 6
    start : 312
    little : 1501
    bit : 568
    sense : 555
    still : 1047
    guess : 226
    bottom : 93
    line : 435
    movies : 1206
    always : 586
    sure : 523
    given : 502
    password : 4
    enter : 68
    understanding : 57
    mean : 242
    showing : 147
    melissa : 12
    sagemiller : 8
    running : 323
    away : 655
    visions : 31
    20 : 98
    throughout : 302
    plain : 82
    lazy : 34
    okay : 125
    people : 1455
    chasing : 43
    know : 1217
    need : 316
    giving : 214
    us : 1073
    different : 430
    offering : 38
    insight : 54
    apparently : 209
    studio : 163
    took : 164
    director : 1237
    chopped : 5
    shows : 410
    might : 635
    decent : 164
    somewhere : 127
    suits : 45
    decided : 104
    turning : 80
    music : 480
    video : 322
    edge : 104
    would : 2109
    actors : 706
    although : 795
    wes : 50
    bentley : 9
    seemed : 212
    playing : 362
    exact : 64
    character : 2020
    american : 559
    beauty : 135
    new : 1292
    neighborhood : 21
    kudos : 21
    holds : 90
    entire : 408
    feeling : 225
    unraveling : 2
    overall : 160
    stick : 69
    entertain : 53
    confusing : 94
    rarely : 102
    excites : 2
    feels : 216
    redundant : 14
    runtime : 8
    despite : 352
    ending : 423
    explanation : 69
    craziness : 4
    came : 185
    oh : 216
    horror : 473
    slasher : 84
    flick : 196
    packaged : 3
    someone : 401
    assuming : 15
    genre : 268
    hot : 127
    kids : 328
    also : 1967
    wrapped : 39
    production : 300
    years : 846
    ago : 199
    sitting : 93
    shelves : 13
    ever : 776
    whatever : 136
    skip : 45
    joblo : 30
    nightmare : 60
    elm : 14
    street : 140
    3 : 222
    7 : 115
    10 : 449
    blair : 98
    witch : 108
    2 : 439
    crow : 55
    9 : 75
    salvation : 14
    4 : 190
    stir : 27
    echoes : 31
    8 : 140
    happy : 215
    bastard : 46
    quick : 139
    damn : 88
    y2k : 4
    bug : 81
    starring : 184
    jamie : 42
    lee : 266
    curtis : 37
    another : 1121
    baldwin : 89
    brother : 268
    william : 206
    time : 2411
    story : 2169
    regarding : 31
    crew : 214
    tugboat : 2
    comes : 733
    across : 221
    deserted : 21
    russian : 68
    tech : 29
    ship : 264
    kick : 52
    power : 238
    within : 227
    gore : 110
    bringing : 81
    action : 1172
    sequences : 293
    virus : 77
    empty : 67
    flash : 62
    substance : 73
    middle : 222
    nowhere : 98
    origin : 8
    pink : 24
    flashy : 41
    thing : 809
    hit : 285
    mir : 7
    course : 648
    donald : 38
    sutherland : 39
    stumbling : 15
    around : 903
    drunkenly : 2
    hey : 70
    let : 425
    robots : 27
    acting : 695
    average : 119
    likes : 99
    likely : 164
    work : 1020
    halloween : 60
    h20 : 7
    wasted : 118
    real : 915
    star : 761
    stan : 12
    winston : 4
    robot : 45
    design : 87
    schnazzy : 1
    cgi : 50
    occasional : 62
    shot : 348
    picking : 28
    brain : 93
    body : 269
    parts : 207
    turn : 363
    otherwise : 156
    much : 2049
    sunken : 4
    jaded : 12
    viewer : 218
    thankful : 7
    invention : 11
    timex : 1
    indiglo : 1
    based : 389
    late : 238
    1960 : 22
    television : 220
    show : 741
    name : 392
    mod : 17
    squad : 40
    tells : 255
    tale : 216
    three : 695
    reformed : 7
    criminals : 35
    employ : 16
    police : 241
    undercover : 28
    however : 989
    wrong : 385
    evidence : 66
    gets : 865
    stolen : 58
    immediately : 163
    suspicion : 19
    ads : 33
    cuts : 60
    claire : 70
    dane : 5
    nice : 344
    hair : 109
    cute : 134
    outfits : 21
    car : 321
    chases : 50
    stuff : 208
    blowing : 26
    sounds : 133
    first : 1836
    fifteen : 64
    quickly : 255
    becomes : 526
    apparent : 100
    certainly : 361
    slick : 39
    looking : 501
    complete : 197
    costumes : 71
    enough : 910
    best : 1333
    described : 57
    cross : 111
    hour : 355
    long : 836
    cop : 208
    stretched : 19
    View Code

         https://wordart.com/create

    邀月工作室

      仔细研究这个词云,会发现它远非完美,还有很大的改进空间。因此,我们不妨做进一步的尝试。

      进一步过滤:我们应当剔除包含数字符号和姓名的那些单词。这时,可以借助NLTK的names语料库。此外,对于在所有语料库中仅出现一次的那些单词,我们也可以置之不理,因为它们不大可能提供足够有价值的信息。

      使用更好的度量指标:词频和逆文档频率(The Term Frequency-Inverse Document Frequency,TF-IDF)看起来是一个不错的选择。

      度量指标TF-IDF可以通过对语料库中的单词进行排名并据此赋予这些单词相应的权重。这个权重的值与单词在特定文档中出现的次数即词频成正比。同时,它还与语料库中含有该单词的文档数量成反比,即逆文档频率。TF-IDF的值为词频和逆文档频率之积。如果需要自己动手实现TF-IDF,那么还必须考虑对数标定处理。幸运的是,实际上我们根本无需考虑这些实现方面的细节,因为scikit-learn已经为我们准备好了一个TfidfVectorizer类,它有效地实现了TF-IDF。该类能够生成一个稀疏的SciPy矩阵,用术语来说就是一个词条-文档矩阵,这个矩阵存放的是单词和文档的每种可能组合的TF-IDF值。因此,对于一个含有2 000个文档和25 000个不重复的词的语料库,可以得到一个2 000×25 000的矩阵。由于大部分矩阵值都为0,我们将它作为一个稀疏矩阵来处理比较省劲。对每个单词来说,其最终的排名权重可以通过对其TF-IDF值求和来得到。

    下面我们通过isalpha()方法和姓名语料库来改善过滤效果,代码如下。

    1 all_names = set([name.lower() for name in names.words()])
    2 
    3 def isStopWord(word):
    4     return (word in sw or word in punctuation) or not word.isalpha() or word in all_names

      下面创建一个NLTK的FreqDist类,从而过滤掉那些只出现一次的单词。对于TfidfVectorizer类,需要为其提供一个字符串列表来指出语料库中的各个文档。

      下面创建这个列表,代码如下。

    1 for fid in movie_reviews.fileids():
    2     texts.append(" ".join([w.lower() for w in movie_reviews.words(fid) if not isStopWord(w.lower()) and words[w.lower()]

      创建向量化程序,为了保险起见,令其忽略停用词。

    1 vectorizer = TfidfVectorizer(stop_words='english')

      创建稀疏的词条-文档矩阵。

    1 matrix = vectorizer.fit_transform(texts)

      为每个单词的TF-IDF值求和并将结果存放到NumPy数组中。

    1 sums = np.array(matrix.sum(axis=0)).ravel()

      下面通过单词的排名权值来创建一个Pandas DataFrame并进行相应的排序,代码如下。

    1 ranks = []
    2 
    3 for word, val in zip(vectorizer.get_feature_names(), sums):
    4     ranks.append((word, val))
    5 
    6 df = pd.DataFrame(ranks, columns=["term", "tfidf"])
    7 df = df.sort_values(['tfidf'])
    8 print(df.head())

      排名最低的值将被输出,同时供将来过滤用。

                     term    tfidf
    19963  superintendent  0.03035
    8736            greys  0.03035
    14010           ology  0.03035
    2406          briefer  0.03035
    2791      cannibalize  0.03035
    matter : 10.160156320157853
    review : 10.162109208095815
    seeing : 10.193962242951153
    jokes : 10.195055387739588
    past : 10.229789978743266
    romantic : 10.270767948140588
    directed : 10.27679275085064
    start : 10.302358509215921
    finally : 10.315385095902199
    video : 10.356897657857315
    despite : 10.36356758711268
    ship : 10.370281211670585
    beautiful : 10.415601266078719
    scream : 10.421970655899635
    sequence : 10.461140540373234
    supposed : 10.473608248283002
    shot : 10.497822532176006
    face : 10.520647846526677
    turn : 10.535466043788666
    lives : 10.536265259335323
    later : 10.536596993112912
    tell : 10.54178804022045
    camera : 10.580870634146848
    works : 10.585001927065935
    children : 10.59229934724306
    live : 10.658879764040353
    daughter : 10.685408819519905
    earth : 10.6855987888017
    mr : 10.711280266859085
    car : 10.715492238654587
    believe : 10.724994487616465
    maybe : 10.738295943695265
    person : 10.766043701757003
    book : 10.799070874951035
    worst : 10.801808893863994
    hand : 10.815936702218032
    named : 10.818013961831461
    game : 10.86383795127332
    fight : 10.865544776692566
    use : 10.88431817114859
    used : 10.955534955009918
    killer : 11.000641030461054
    certainly : 11.001525429842374
    begins : 11.070728771014815
    perfect : 11.096242361915083
    relationship : 11.102758849863765
    said : 11.108251601369561
    nice : 11.124424984182713
    days : 11.138293311572346
    kids : 11.181482360800292
    called : 11.192445668887236
    run : 11.198723318188565
    playing : 11.216003589219902
    final : 11.223074577571513
    tries : 11.242871986273729
    unfortunately : 11.295825206128804
    group : 11.326924605147562
    comic : 11.389992817954504
    left : 11.438340356187926
    entire : 11.444592282847251
    idea : 11.461929302207174
    based : 11.487214286939588
    head : 11.516296149111216
    wrong : 11.562368605644979
    second : 11.585319233830582
    summer : 11.586686728126798
    shows : 11.63522507695588
    main : 11.660671883754478
    soon : 11.711290550319069
    true : 11.754181091867876
    turns : 11.821623440558202
    getting : 11.874446133551853
    human : 11.899923970603947
    problem : 11.99620702280271
    written : 12.006014424193982
    hour : 12.018041625879004
    different : 12.151447465665578
    boy : 12.202291415418031
    performances : 12.239403934569973
    house : 12.251961733491308
    simply : 12.29153134772739
    war : 12.297910070957098
    mind : 12.324864356668593
    small : 12.327723933187466
    especially : 12.352783302524191
    rest : 12.359092724325766
    tv : 12.368538157058103
    lost : 12.399034233379663
    completely : 12.435026821722477
    looks : 12.4500832891327
    humor : 12.480741394166033
    line : 12.531463602753462
    reason : 12.549615155979115
    dead : 12.550701937661323
    friend : 12.554066106444134
    let : 12.557077785028916
    thought : 12.650011584913317
    stars : 12.688790737853829
    couple : 12.731565830451245
    alien : 12.811802155159485
    moments : 12.890094530509302
    evil : 12.90918008264871
    wants : 12.91523366454186
    friends : 12.971455692528544
    night : 12.972118832796
    mother : 13.069867009873525
    given : 13.163657271730541
    ending : 13.241085606272085
    play : 13.241256041448459
    feel : 13.260355813064143
    gives : 13.541933025342574
    got : 13.58120683575867
    watching : 13.633462479391907
    death : 13.638264772375894
    looking : 13.717090584113414
    girl : 13.728552228886974
    instead : 13.774615981791037
    probably : 13.808813918690175
    city : 13.842578473593091
    school : 13.897593833405203
    father : 14.066422069009711
    music : 14.075762648197905
    help : 14.120498729117202
    sure : 14.145480680268529
    dialogue : 14.23176869122043
    kind : 14.399967422476037
    black : 14.447741822146453
    actor : 14.522615872729146
    sense : 14.629745462015816
    want : 14.725766439030554
    pretty : 14.809940495890388
    making : 14.817117131361535
    series : 14.821081643716946
    set : 14.887819969400011
    half : 14.89251185190553
    money : 14.901355104392845
    bit : 14.934268735728764
    home : 14.976582330659667
    place : 15.049919713647064
    trying : 15.114785990368087
    times : 15.118763478807493
    sex : 15.166419440553032
    american : 15.359810523477407
    hard : 15.454208298004339
    picture : 15.506551578323716
    woman : 15.639843619779164
    hollywood : 15.650704478670258
    horror : 15.688047135511049
    far : 15.758603032319007
    watch : 15.781648059164944
    fun : 15.799106034203923
    special : 15.894929367222112
    course : 15.931964229777236
    away : 15.944636479597987
    takes : 15.954305763102612
    men : 16.036233030752417
    wife : 16.103810528049053
    interesting : 16.110566312034386
    screen : 16.330798169836488
    goes : 16.355214344649127
    minutes : 16.578665989245824
    point : 16.593231934007573
    quite : 16.743903021148146
    lot : 16.7556321332947
    comes : 16.945112986149024
    high : 16.96333443299414
    day : 17.469931907378594
    young : 17.61907491805685
    come : 17.710951023055475
    plays : 17.825218944178573
    actors : 17.841139061718554
    acting : 18.056556176317212
    effects : 18.156452985282307
    fact : 18.358966964131444
    family : 18.436351324270554
    cast : 18.462652990794695
    right : 18.51721470872539
    look : 18.709286795233268
    original : 18.815142636940738
    played : 18.96169328195863
    years : 19.058321835992686
    long : 19.063431217630267
    actually : 19.081359841119173
    thing : 19.347634515439985
    script : 19.466362068961164
    old : 19.68484647913068
    things : 19.711840751606182
    gets : 19.789969444538826
    think : 19.79997034212867
    role : 19.829843863051224
    performance : 19.991860531957602
    better : 20.069030711347395
    audience : 20.229377054374694
    going : 20.384999917030928
    year : 20.404754669356507
    seen : 20.741715274906582
    real : 20.782565933126254
    makes : 20.916315796004714
    work : 21.48974389558135
    funny : 22.184963867355552
    world : 22.430195409736793
    end : 22.501145434405117
    comedy : 22.724158274326264
    big : 23.394018499746736
    director : 23.689769490697007
    great : 24.489611034104875
    scenes : 25.243560471583756
    know : 25.25908281181752
    new : 25.424409388545484
    movies : 25.46489805929262
    best : 25.793314078809164
    scene : 26.65609949406872
    man : 27.271016365028732
    people : 27.772749971079577
    action : 27.8317318022786
    little : 27.912251658495467
    make : 28.36244923373348
    films : 29.081817882359086
    bad : 29.1633844710237
    plot : 29.81049966927315
    really : 30.211353157494234
    life : 30.844185813234848
    characters : 33.204457851658944
    character : 33.73419369933767
    story : 36.69429364590541
    time : 36.76869565644592
    good : 38.945456240101606
    like : 49.087665729852674
    movie : 80.3332102380712
    film : 109.34008874939663
    View Code

    接下来,我们输出排名靠前的单词,这样就可以利用Wordle网站生成如图9-5所示的词云了。

    邀月工作室

      令人遗憾的是,我们必须亲自运行代码,才能看到上面词云中的不同色彩。相较于单调的词频而言,TF-IDF度量指标更富于变化,因此我们就能得到更加丰富的色彩。此外,这样还能使得云雾中的单词看起来联系更加紧密。下列代码摘自本书代码包中的ch-09.ipynb文件。

     1 from nltk import data
     2 data.path.append(r'D:download
    ltk_data') # 这里的路径需要换成自己数据文件下载的路径
     3 from nltk.corpus import movie_reviews
     4 from nltk.corpus import stopwords
     5 from nltk.corpus import names
     6 from nltk import FreqDist
     7 from sklearn.feature_extraction.text import TfidfVectorizer
     8 import itertools
     9 import pandas as pd
    10 import numpy as np
    11 import string
    12 
    13 sw = set(stopwords.words('english'))
    14 punctuation = set(string.punctuation)
    15 all_names = set([name.lower() for name in names.words()])
    16 
    17 def isStopWord(word):
    18     return (word in sw or word in punctuation) or not word.isalpha() or word in all_names
    19 
    20 review_words = movie_reviews.words()
    21 filtered = [w.lower() for w in review_words if not isStopWord(w.lower())]
    22 
    23 words = FreqDist(filtered)
    24 
    25 texts = []
    26 
    27 for fid in movie_reviews.fileids():
    28     texts.append(" ".join([w.lower() for w in movie_reviews.words(fid) if not isStopWord(w.lower()) and words[w.lower()] > 1]))
    29 
    30 vectorizer = TfidfVectorizer(stop_words='english')
    31 matrix = vectorizer.fit_transform(texts)
    32 sums = np.array(matrix.sum(axis=0)).ravel()
    33 
    34 ranks = []
    35 
    36 for word, val in zip(vectorizer.get_feature_names(), sums):
    37     ranks.append((word, val))
    38 
    39 df = pd.DataFrame(ranks, columns=["term", "tfidf"])
    40 df = df.sort_values(['tfidf'])
    41 print(df.head())
    42 
    43 N = int(.01 * len(df))
    44 df = df.tail(N)
    45 
    46 for term, tfidf in zip(df["term"].values, df["tfidf"].values):
    47     print(term, ":", tfidf)

    9.9社交网络分析

       所谓社交网络分析,实际上就是利用网络理论来研究社会关系,其中,网络中的节点代表的是网络中的参与者。节点之间的连线代表的是参与者之间的相互关系。

      严格来讲,这应该称为一个图。本书仅介绍如何利用流行的Python库NetworkX来分析简单的图。这里,通过Python库matplotlib来对这些网络图进行可视化。

      为了安装NetworkX,可以使用如下命令。

    1 $ pip3 install networkx

      关于Networkx,也可以参照这篇文章《数据分析实战-托马兹.卓巴斯》读书笔记第8章--图(NetworkX、Gephi)修订版

      下面导入NetworkX并指定一个简单的别名。

    1 Import networkx as nx

      NetworkX提供了许多示例图,下面将其列出,代码如下。

    1 print([s for s in dir(nx) if s.endswith('graph')])

      下面导入Davis Southern women图并绘制出各个节点的度的柱状图,代码如下。

    1 G = nx.davis_southern_women_graph()
    2 plt.hist(list(nx.degree(G).values())) #AttributeError: 'DegreeView' object has no attribute 'values',去掉values即可,邀月注。
    3 plt.show()

      最终得到如图9-6所示的柱状图。

    邀月工作室

      下面来绘制带有节点标签的网络图,所需命令如下。

    1 plt.figure(figsize=(8,8))
    2 pos = nx.spring_layout(G)
    3 nx.draw(G, node_size=10)
    4 nx.draw_networkx_labels(G, pos)
    5 plt.show()

      得到的图形如图9-7所示。

    邀月工作室

         图像的可读性可以再优化:

    1 plt.figure(figsize=(8,8))
    2 print(help(nx.spring_layout))
    3 pos = nx.spring_layout(G, scale=2)
    4 
    5 nx.draw(G)
    6 nx.draw_networkx_labels(G, pos)
    7 plt.show()

      效果如下图:

    邀月工作室

      虽然这个例子很短,但是对于简单体验NetworkX的功能特性来说已经足够了。我们可以借助NetworkX来探索、可观化和分析社交媒体网络,如Twitter、Facebook以及LinkedIn等。当然,本节讲述的方法不仅适用于社交网络,实际上,所有类似的网络图都可以使用NetworkX来处理。

    9.10小结

       本章讲述了文本分析方面的知识。首先,我们给出了文本分析中剔除停用词的一个最佳实践。

      介绍词袋模型时,我们还创建了一个词袋来存放文档内出现的单词。此外,我们还根据所有的单词计数,为每个文档生成了一个特征向量。

      分类算法是机器学习算法中的一种,用来给特定事物进行分类。朴素贝叶斯分类是一种概率算法,它基于概率与数理统计中的贝叶斯定理。这里,贝叶斯定理指出,后验概率与先验概率和相似度之积成正比。

      第10章将对机器学习进行更深入的介绍,因为这是一个充满了无限希望的研究领域。也许有一天,它将完全替代人类劳动力。届时,以气象数据为例,来说明Python机器学习库scikit-learn的具体使用方法。

     第9章完。

    python数据分析个人学习读书笔记-目录索引

    随书源码官方下载:
    https://www.ptpress.com.cn/shopping/buy?bookId=bae24ecb-a1a1-41c7-be7c-d913b163c111

    需要登录后免费下载。

  • 相关阅读:
    Matlab中tic和toc用法
    matlab 哪个函数可以从一组数据中随机抽取一部分出来
    matlab中rep函数的用法
    WinCE平台搭建数据库(wince6.0+vs2008+sqlce)熙熙
    熙熙如何在WinCE里上QQ(天嵌WinCE开发板,PocketPC仿真模拟器,QQ)
    数学建模方法灰色预测法
    数学建模方法层次分析法
    数学建模方法多属性决策模型
    数学建模方法Floyd算法
    数学建模方法Dijkstra算法
  • 原文地址:https://www.cnblogs.com/downmoon/p/12635314.html
Copyright © 2011-2022 走看看