python机器学习——NLTK及分析文本数据(自然语言处理基础)

NLTK

NLTK(Natural Language Toolkit),自然语言处理工具包,在NLP(自然语言处理)领域中,最常使用的一个Python库。自带语料库,词性分类库。自带分类,分词功能。
NLTK安装
安装:pip install NLTK
测试:import nltk
Anaconda不用安装
安装语料库:

import nltk
nltk.download()

执行代码后,会出现包管理器,我们下载NLTK数据,这些数据中包含很多语料和训练模型这里写图片描述
安装过程:
这里写图片描述
安装完成:
这里写图片描述
NLTK功能:
这里写图片描述
NLTK自带的语料库:
corpus语料库的集合,导入布朗语料库。
categoryies()查看种类
sents()句子数量
words()词数
这里写图片描述
如果导入的时候出现import错误,说明语料库没有下载,重新下载好,再导入。

文本处理
分词(Tokenize):word_tokenize生成一个词的列表

>>> import nltk
>>> sentence="I Love China !"
>>> tokens=nltk.word_tokenize(sentence)
>>> tokens
['I', 'Love', 'China', '!']
>>>

中文分词:用jieba

>>> import jieba
>>> seg_list=jieba.cut("我正在学习机器学习",cut_all=True)
>>> print("全模式:","/".join(seg_list))
全模式: 我/正在/学习/学习机/机器/学习
>>> seg_list=jieba.cut("我正在学习机器学习",cut_all=False)
>>> print("精确模式:","/".join(seg_list))
精确模式: 我/正在/学习/机器/学习
>>> seg_list=jieba.cut("我正在学习自然语言处理")
>>> print("默认是精确模式:","/".join(seg_list))
默认是精确模式: 我/正在/学习/自然语言/处理
>>> seg_list=jieba.cut_for_search("文本分析和自然语言处理是现在人工智能系统不可分割的一部分")
>>> print("/".join(seg_list))
文本/分析//自然/语言/自然语言/处理/是/现在/人工/智能/人工智能/系统/不可/可分/分割/不可分割/的/一部/部分/一部分
>>>

但是有时候分词并没有那么容易。文本中可能会含有各种各样的字符,如社交网络上的文本。

from nltk.tokenize import word_tokenize
tweet = 'RT @angelababy: love you baby! :D http://ah.love #168cm' 
print(word_tokenize(tweet))
 # ['RT', '@', 'angelababy', ':', 'love', 'you', 'baby', '!', ':', # ’D', 'http', ':', '//ah.love', '#', '168cm']

这时候就需要正则表达式。正则表达式参考文档:http://www.regexlab.com/zh/regref.htm

import re
emoticons_str = r"""  
  (?: 
        [:=;] # 眼睛  
        [oO\-]? # ⿐鼻⼦子
        [D\)\]\(\]/\\OpP] # 嘴
    )"""
regex_str = [
    emoticons_str,
    r'<[^>]+>',  # HTML tags  
    r'(?:@[\w_]+)',  # @某⼈人   
    r"(?:\#+[\w_]+[\w\'_\-]*[\w_]+)",  # 话题标签
    r'http[s]?://(?:[a-z]|[0-9]|[$-_@.&amp;+]|[!*\(\),]|(?:%[0-9a-f][0-9a-f]))+',  # URLs 
    r'(?:(?:\d+,?)+(?:\.?\d+)?)',  # 数字 
    r"(?:[a-z][a-z'\-_]+[a-z])",  # 含有 - 和 ‘ 的单词    
    r'(?:\S)'  # 其他 
]

tokens_re = re.compile(r'(' + '|'.join(regex_str) + ')',re.VERBOSE | re.IGNORECASE)
emoticon_re = re.compile(r'^' + emoticons_str + '$',re.VERBOSE | re.IGNORECASE)

def tokenize(s):
    return tokens_re.findall(s)
def preprocess(s, lowercase=False):
    tokens = tokenize(s)
    if lowercase:
        tokens = [token if emoticon_re.search(token) else token.lower()for token in tokens ]
    return tokens


tweet = 'RT @angelababy: love you baby! :D http://ah.love #168cm'
print(preprocess(tweet))

运行结果:

['R', 'T', '@angelababy', ':', 'love', 'you', 'baby', '!', ':D', 'http://ah.love', '#168cm']

提取文本数据的词干(Stemming 词⼲提取):
处理文本文档时,可能会碰到单词的不同形式。如“paly”这个词会以各种形式出现,“play”,“plays”,“player”,“playing”等。这些是具有同样含义的单词家族,在文本分析中,提取这些词的原形非常有用,它有助于我们提取一些统计信息来分析整个文本。词干提取的目标是将不同词性的单词都变成其原形。
词干提取使用启发式处理方法截取单词的尾部,以提取单词的原形。
NLTK实现Stemmin(参照《python机器学习经典实例》分析文本数据)

from nltk.stem.porter import PorterStemmer
from nltk.stem.lancaster import LancasterStemmer
from nltk.stem.snowball import SnowballStemmer

words = ['table', 'probably', 'wolves', 'playing', 'is', 
        'dog', 'the', 'beaches', 'grounded', 'dreamt', 'envision']

#比较不同的词干提取方法
stemmers = ['PORTER', 'LANCASTER', 'SNOWBALL']
stemmer_porter = PorterStemmer()
stemmer_lancaster = LancasterStemmer()
stemmer_snowball = SnowballStemmer('english')

formatted_row = '{:>16}' * (len(stemmers) + 1)
print ('\n', formatted_row.format('WORD', *stemmers), '\n')
for word in words:
    stemmed_words = [stemmer_porter.stem(word), 
            stemmer_lancaster.stem(word), stemmer_snowball.stem(word)]
    print (formatted_row.format(word, *stemmed_words))

运行结果:
这里写图片描述

比较:3种词干提取算法的本质目标都是提取出词干,消除词影响。它们的不同之处在于操作的严格程度不同。Lancaster词干提取器比其他两个词干提取器更严格,Porter词干提取器是最宽松的。Lancaster词干提取器得到的词干往往比较模糊,难以理解。Lancaster词干提取器的速度很快,但是它会减少单词的很大部分,因此通常会选择Snowball词干提取器。

用词性还原的方法还原文本的基本形式(Lemmatization 词形归⼀):
词形还原的目标也是将单词转化为其原形,但它是一个更结构化的方法。词形还原通过对单词进行词汇和语法分析来实现,输出结果取决于标记是一个动词还是一个名词。
NLTK实现Lemm(参照《python机器学习经典实例》分析文本数据)

from nltk.stem import WordNetLemmatizer

words = ['table', 'probably', 'wolves', 'playing', 'is', 
        'dog', 'the', 'beaches', 'grounded', 'dreamt', 'envision']

# 对比不同词形的还原器
lemmatizers = ['NOUN LEMMATIZER', 'VERB LEMMATIZER']
lemmatizer_wordnet = WordNetLemmatizer()

formatted_row = '{:>24}' * (len(lemmatizers) + 1)
print('\n', formatted_row.format('WORD', *lemmatizers), '\n')
for word in words:
    lemmatized_words = [lemmatizer_wordnet.lemmatize(word, pos='n'),
           lemmatizer_wordnet.lemmatize(word, pos='v')]
    print (formatted_row.format(word, *lemmatized_words))

运行结果:
这里写图片描述

Stopwords停用词
在信息检索中,为节省存储空间和提高搜索效率,在自然语言数据(或文本)之前或之后会自动过滤某些字或词,这些字词即被称为“StopWords”。这类词基本上在任何场合任何时候都会有,因此不会影响数据的分析结果,反而对数据处理来说,是一种多余。因此,我们在进行分词和处理高频词汇的时候,一定要将其剔除。

全体stopwords列表 http://www.ranks.nl/stopwords

NLTK去除stopwords
首先要下载词库

>>> import nltk
>>> nltk.download('stopwords')

这里写图片描述

NLTK在自然语言处理中的应用

创建文本分类器

文本分类的目的是将文本文档分为不同的类,这是NLP中非常重要的手段。这里将使用一种技术,它基于一种叫作tf-idf的统计数据,它表示词频-逆文档频率。这个统计工具有助于理解一个单词在一组文档中对某一个文档的重要性。它可以作为特征向量来做文档分类。

tf-idf技术常用于信息检索领域,目的是了解文档中每个单词的重要性。如果想要识别在文档中多次出现的单词,同时像“is”和“be”这样的普通词汇并不能真正反映内容的本质,因此仅需要提供提取出具有实际意义的那些词。词频越大,则表示这个词越重要,同时,如果这个词经常出现,那么这个词频也会增加,这两个因素互相平衡。提取出每个句子的词频,然后将其转化为特征向量,用分类器来对这些句子进行分类。

详细步骤及代码(步骤在代码注释中)

from sklearn.datasets import fetch_20newsgroups

#选择一个类型列表,并用词典映射的方式定义
#这些类型是加载的新闻组数据集的一部分
category_map = {'misc.forsale': 'Sales', 'rec.motorcycles': 'Motorcycles', 
        'rec.sport.baseball': 'Baseball', 'sci.crypt': 'Cryptography', 
        'sci.space': 'Space'}
#基于刚刚定义的类型加载训练数据
training_data = fetch_20newsgroups(subset='train', 
        categories=category_map.keys(), shuffle=True, random_state=7)

#特征提取
from sklearn.feature_extraction.text import CountVectorizer

#用训练数据提取特征
vectorizer = CountVectorizer()
X_train_termcounts = vectorizer.fit_transform(training_data.data)
print("\nDimensions of training data:", X_train_termcounts.shape)

# 训练分类器
from sklearn.naive_bayes import MultinomialNB
from sklearn.feature_extraction.text import TfidfTransformer
#定义一些随机输入的句子
input_data = [
    "The curveballs of right handed pitchers tend to curve to the left", 
    "Caesar cipher is an ancient form of encryption",
    "This two-wheeler is really good on slippery roads"
]

# tf-idf 变换器
tfidf_transformer = TfidfTransformer()
X_train_tfidf = tfidf_transformer.fit_transform(X_train_termcounts)

# 多项式朴素贝叶斯分类器
classifier = MultinomialNB().fit(X_train_tfidf, training_data.target)
#用词频统计转换输入数据
X_input_termcounts = vectorizer.transform(input_data)
#用tf-idf变换器变换输入数据
X_input_tfidf = tfidf_transformer.transform(X_input_termcounts)

#预测输出类型
predicted_categories = classifier.predict(X_input_tfidf)

#打印输出
for sentence, category in zip(input_data, predicted_categories):
    print ('\nInput:', sentence, '\nPredicted category:', \
            category_map[training_data.target_names[category]])

运行结果:
这里写图片描述

识别性别

在NPL中,通过姓名识别性别是一个有趣的任务。这里用启发式方法,即姓名的最后几个字符可以界定性别特征。如名字以“la”结尾,那么可能是一个女性的名字,如“Angela”,“Layla”。如果以“im”结尾,可能是一个男性的名字,如“Tim”,“Jim”。

详细步骤及代码(步骤在 代码注释中)

import random
from nltk.corpus import names
from nltk import NaiveBayesClassifier
from nltk.classify import accuracy as nltk_accuracy

#定义一个用于提取输入单词的特征函数
#提取输入单词的特征
def gender_features(word, num_letters=2):
    return {'feature': word[-num_letters:].lower()}


#定义主函数,需要一些带标记的训练数据
if __name__=='__main__':
    #提取标记名称
    labeled_names = ([(name, 'male') for name in names.words('male.txt')] +
            [(name, 'female') for name in names.words('female.txt')])

    #设置随机生成数的种子值,并混合搅乱训练数据
    random.seed(7)
    random.shuffle(labeled_names)
    #定义一些输入的名字
    input_names = ['Leonardo', 'Amy', 'Sam']

#因为不知道需要多少个末尾字符,这里将这个参数设置为1~5。每次循环执行,都会截取相应大小的末尾字符个数
    #搜索参数空间
    for i in range(1, 5):
        print ('\nNumber of letters:', i)
        featuresets = [(gender_features(n, i), gender) for (n, gender) in labeled_names]
        #将数据分为训练数据集和测试数据集
        train_set, test_set = featuresets[500:], featuresets[:500]
        #用朴素贝叶斯分类器做分类
        classifier = NaiveBayesClassifier.train(train_set)
        #用参数空间的每一个值评分类器的效果
        # 打印分类器的准确性
        print ('Accuracy ==>', str(100 * nltk_accuracy(classifier, test_set)) + str('%'))

        # 为新输入预测输出结果
        for name in input_names:
            print (name, '==>', classifier.classify(gender_features(name, i)))

运行结果:
这里写图片描述

分析句子的情感

情感分析是NLP最受欢迎的应用之一。情感分析是指确定一段给定的文本是积极还是消极的过程。有一些场景中,我们还会将“中性“作为第三个选项。情感分析常用于发现人们对于一个特定主题的看法。情感分析用于分析很多场景中用户的情绪,如营销活动、社交媒体、电子商务客户等。

import nltk.classify.util
from nltk.classify import NaiveBayesClassifier
from nltk.corpus import movie_reviews

 #定义一个用于提取特征的函数
def extract_features(word_list):
    return dict([(word, True) for word in word_list])


 #我们需要训练数据,这里将用NLTK提供的电影评论数据
if __name__=='__main__':
    # 加载积极与消极评论 
    positive_fileids = movie_reviews.fileids('pos')
    negative_fileids = movie_reviews.fileids('neg')

    #将这些评论数据分成积极评论和消极评论 
    features_positive = [(extract_features(movie_reviews.words(fileids=[f])), 
            'Positive') for f in positive_fileids]
    features_negative = [(extract_features(movie_reviews.words(fileids=[f])), 
            'Negative') for f in negative_fileids]

    #分成训练数据集(80%)和测试数据集(20%)
    threshold_factor = 0.8
    threshold_positive = int(threshold_factor * len(features_positive))
    threshold_negative = int(threshold_factor * len(features_negative))
     #提取特征
    features_train = features_positive[:threshold_positive] + features_negative[:threshold_negative]
    features_test = features_positive[threshold_positive:] + features_negative[threshold_negative:]  
    print ("\nNumber of training datapoints:", len(features_train))
    print ("Number of test datapoints:", len(features_test))

    #训练朴素贝叶斯分类器
    classifier = NaiveBayesClassifier.train(features_train)
    print ("\nAccuracy of the classifier:", nltk.classify.util.accuracy(classifier, features_test))

    print ("\nTop 10 most informative words:")
    for item in classifier.most_informative_features()[:10]:
        print (item[0])

    # 输入一些简单的评论
    input_reviews = [
        "It is an amazing movie", 
        "This is a dull movie. I would never recommend it to anyone.",
        "The cinematography is pretty great in this movie", 
        "The direction was terrible and the story was all over the place" 
    ]
#运行分类器,获得预测结果
    print ("\nPredictions:")
    for review in input_reviews:
        print ("\nReview:", review)
        probdist = classifier.prob_classify(extract_features(review.split()))
        pred_sentiment = probdist.max()
        #打印输出
        print ("Predicted sentiment:", pred_sentiment) 
        print ("Probability:", round(probdist.prob(pred_sentiment), 2))

运行结果:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_41251963/article/details/81702821
今日推荐