栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

自然语言处理——NLP基础

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

自然语言处理——NLP基础

目录

语料库

文本处理流程

分词(Tokenize)

英文

中文

预处理

社交语言

纷繁复杂的词性

Stemming词干提取

Lemmatization词形归一

词性标注

Stopwords(歧义太多的词)

NLTK在NLP上的经典应用

情感分析

关键词打分

配上ML的情感分析

文本相似度

文本分类

Kaggle竞赛题


语料库

NLTK : pip install nltk

NLTK :: Natural Language Toolkit

(40条消息) NLTK安装方法一脑子RMC136的博客-CSDN博客nltk安装教程

文本处理流程

句子→预处理→分词(Tokenize)→特征工程(make features)→机器学习(machine learning)

分词(Tokenize)

把长句子拆成“有意义”的小部件

英文
from nltk.tokenize import word_tokenize
sentences = 'hello world'
token = word_tokenize(sentences)
print(token)

中文
import jieba
seg_list = jieba.cut('我到北京清华大学',cut_all=True)
print('full mode:','/'.join(seg_list)) # 全模式
seg_list = jieba.cut('我到北京清华大学',cut_all=False)
print('default mode:','/'.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']

如何做呢?

import re :正则表达式 → 常用于字符串处理

对照表:正则表达式参考文档 - Regular Expression Syntax Reference

#### re.compile 是变为方法 去判定,符合条件的筛选出来
import re
emotions_str = r"""
    (?:
        [:=;] # 眼睛
        [oO-]? # 鼻子
        [D)]<]/\OpP] # 嘴
    )"""
# []表示里面任何一个都可以,[]?表示可存在可不存在
regex_str = [
    emotions_str,
    r'<[^>]+>', # HTML tags
    r'(?:@[w_]+)', # @某人
    r"(?:#+[w_]+[w'_-]*[w_]+)", # 话题标签
    r'http[s]?://(?:[a-z][0-9]|[$-_@.&:+]|[!*(),]|(?:%[0-9a-f][0-9a-f]))+', # URLs
    r'(?:(?:d+,?)+(?:.?d+)?)', # 数字
    r"(?:[a-z][a-z'-_]+[a-z])", # 含有-和‘的单词
    r'(?:[w_]+)', # 其他
    r'(?:s)', # 其他
]
emotion_re = re.compile(r'^'+emotions_str+'$',re.VERBOSE | re.IGNORECASE)
tokens_re = re.compile(r'('+'|'.join(regex_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 emotion_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))
['RT', ' ', '@angelababy', ' ', 'love', ' ', 'you', ' ', 'baby', ' ', ':D', ' ', 'http://ah.love', ' ', '#168cm']

纷繁复杂的词性
  • Inflection(不影响词性):walk→walking→walked

  • derivation(影响词性):nation(noun)→national(objective)→nationalize(verb)

Stemming词干提取

一般来说,就是把不影响词性的inflection的小尾巴砍掉——词根

walking→walk、walked→walk

PorterStemmer

from nltk.stem.porter import PorterStemmer
P = PorterStemmer() # 类调用之前要初始化
print(P.stem('maximum'))
print(P.stem('walking'))
maximum
walk

SnowballStemmer

from nltk.stem import SnowballStemmer
S = SnowballStemmer('english')
print(S.stem('maximum'))
print(S.stem('walking'))
maxim
walk

LancasterStemmer

from nltk.stem.lancaster import LancasterStemmer
L = LancasterStemmer()
print(L.stem('maximum'))
print(L.stem('walking'))
maxim
walk

Lemmatization词形归一

把各种类型的词的变形,都归为一个形式——语料库

went→go、are→be

需要经常更新

from nltk.stem import WordNetLemmatizer
W = WordNetLemmatizer()
print(W.lemmatize('went',pos='v'))
print(W.lemmatize('are',pos='v'))
go
be

词性标注
import nltk
text = nltk.word_tokenize('what does the fox say')
print(text)
tag = nltk.pos_tag(text)
print(tag)
['what', 'does', 'the', 'fox', 'say']
[('what', 'WDT'), ('does', 'VBZ'), ('the', 'DT'), ('fox', 'NNS'), ('say', 'VBP')]

Stopwords(歧义太多的词)

一个he有一千种指代,一个the有一千种事 → 把这些词删掉

如果只需要考虑词义,可以去掉停止词;但是面对查重或者检查句子是否通顺,就不能去掉停止词。

全体stopwords列表(英文) Stopwords

import nltk
from nltk.corpus import stopwords
"""
先token一把,得到一个word_list
...
再filter一把
"""
word_list = nltk.word_tokenize('what does the fox say')
print(word_list)
filtered_words = [word for word in word_list if word not in stopwords.words('english')]
print(filtered_words)
['what', 'does', 'the', 'fox', 'say']
['fox', 'say']

NLTK在NLP上的经典应用
  • 情感分析

  • 文本相似度

  • 文本分类

情感分析

关键词打分

关键词打分机制表(AFINN-111)AFINN

import nltk
words = nltk.word_tokenize('bad')
sentiment_dictionary = {}
for line in open('AFINN/AFINN-111.txt'):
    word,score = line.split('t')
    sentiment_dictionary[word] = int(score)
total_score = sum(sentiment_dictionary.get(word,0) for word in words)
print(total_score)
-3

配上ML的情感分析

新词怎么办?特殊词汇怎么办?更深层次的怎么办?

from nltk.classify import NaiveBayesClassifier
# 随手造点训练集
s1 = 'this is a good book'
s2 = 'this is a awesome book'
s3 = 'this is a bad book'
s4 = 'this is a terrible book'
def preprocess(s):
    #句子处理,这里是用split(),把每个单词都分开,没有用到tokenize,因为例子比较简单。
    return {word: True for word in s.lower().split()}
    #{fname,fval} 这里用true是最简单的存储形式,fval 每个文本单词对应的值,高级的可以用word2vec来得到fval。
#训练 this is terrible good awesome bad book 这样一次单词长列(1,1,0,1,0,0,1)如s1对应的向量
training_data = [[preprocess(s1),'pos'],
                 [preprocess(s2), 'pos'],
                 [preprocess(s3), 'neg'],
                 [preprocess(s4), 'neg']]
model = NaiveBayesClassifier.train(training_data)
print(model.classify(preprocess('this is a good book')))
pos

文本相似度

用元素频率表示文本特征

把文本变成相同长度的向量,用余弦定理判断相似性(相似度越高,夹角越小)先点成再叉乘

import nltk
from nltk import FreqDist
# 做个词库先
corpus = 'this is my sentence'
            'this is my life'
            'this is my day'
# 可以作任何prepocessing
tokens = nltk.word_tokenize(corpus)
print(tokens)
# 借用NLTK的FreqDist统计一下单词出现的次数
fdist = FreqDist(tokens)
print(fdist['is'])
# 把常用的50个词拿出来,得到一个常用词频率对照表
standard_freq_vector = fdist.most_common(50)
size = len(standard_freq_vector)
print(standard_freq_vector)
# 按照频率出现大小,记录每个单词的位置
def position_lookup(v):
    res = {}
    counter = 0
    for word in v:
        res[word[0]] = counter
        counter += 1
    return res
# 得到一个位置对照表
standard_position_dict = position_lookup(standard_freq_vector)
print(standard_position_dict)
# 新句子
sentence = 'this is cool'
# 新建一个和标准vector同样大小的向量
freq_vector = [0] * size
tokens = nltk.word_tokenize(sentence)
for word in tokens:
    try:
        # 如果在我们的词库出现过,就在标准词库位置+1
        freq_vector[standard_position_dict[word]] += 1
    except KeyError:
        # 如果是个新词,就pass掉
        continue
print(freq_vector)
['this', 'is', 'my', 'sentencethis', 'is', 'my', 'lifethis', 'is', 'my', 'day']
3
[('is', 3), ('my', 3), ('this', 1), ('sentencethis', 1), ('lifethis', 1), ('day', 1)]
{'is': 0, 'my': 1, 'this': 2, 'sentencethis': 3, 'lifethis': 4, 'day': 5}
[1, 0, 1, 0, 0, 0]

文本分类

TF(Term Frequency),一个单词在一个文档中出现的有多频繁。

TF(t) = t出现在文档中的次数/文档中的单词总数

IDF(Inverse Document Frequency),衡量一个term有多重要,如 'is' 'the' 这些不重要——所以需要把罕见的权值弄高,把常见的词权值弄低。

IDF(t)=log_e(文档总数/含有t的文档总数)

举个栗子

一个文档有100个单词,其中单词baby出现了3次。

TF(baby)=(3/100)=0.03

如果有10M文档,baby出现在其中的1000个文档中。

IDF(baby)=log_e(10,000,000/1,000)=4
TF-IDF(baby)=TF(babyIDF(baby)=0.03×4=0.12
from nltk.text import TextCollection
# 首首先, 把所有的文文档放到TextCollection类中。这个类会自自动帮你断句句, 做统计, 做计算
corpus = TextCollection(['this is sentence one',
                        'this is sentence two',
                        'this is sentence three'])
# 直接就能算出tfidf (term: 一句话中的某个term, text: 这句话)
print(corpus.tf_idf('one', 'this is sentence one')) # 如果是0,那么这个词出现频率太高,每句话都有
# 同理, 怎么得到一个标准大小的vector来表示所有的句子?
# 对于每个新句子
new_sentence = 'this is sentence five'
# 遍历一一遍所有的vocabulary中的词:---语料库
for word in standard_vocab:
    print(corpus.tf_idf(word, new_sentence))
    # 我们会得到一一个巨⻓长(=所有vocab⻓长度)的向量量

内存不够用迭代器读进来

Kaggle竞赛题

https://www.kaggle.com/c/home-depot-product-search-relevance

Home Depot Product Search Relevance

import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestRegressor,BaggingRegressor
from nltk.stem.snowball import SnowballStemmer
​
# 读入训练集、测试集,产品介绍
df_train = pd.read_csv('./home-depot-product-search-relevance/train.csv',encoding="ISO-8859-1")
df_test = pd.read_csv('./home-depot-product-search-relevance/test.csv',encoding="ISO-8859-1")
df_desc = pd.read_csv('./home-depot-product-search-relevance/product_descriptions.csv')
# 看起来不需要复杂的处理,于是合并测试训练集,以便于统一做进一步的文本预处理 (240760, 5)
df_all = pd.concat((df_train,df_test),axis=0,ignore_index=True) # 上下拼接
df_all = pd.merge(df_all,df_desc,how='left',on='product_uid')
​
# 文本预处理:去掉停止词,纠正拼写,去掉数字,去掉表情等等
stemmer = SnowballStemmer('english')
def str_stemmer(s):
    return " ".join([stemmer.stem(word) for word in s.lower().split()]) # s.lower()小写化
# 为了计算【关键词】的有效性,我们可以native的直接看【出现了几次】
def str_common_word(str1,str2):
    return sum(int(str2.find(word)>=0) for word in str1.split())
# 把每一个与文本有关的列都跑一遍,清洗所有文本
df_all['search_term'] = df_all['search_term'].map(lambda x:str_stemmer(x)) # 放到str_stemmer里面进行词干提取
df_all['product_title'] = df_all['product_title'].map(lambda x:str_stemmer(x))
df_all['product_description'] = df_all['product_description'].map(lambda x:str_stemmer(x))
​
# 自制文本特征——脑洞大开,想到什么加什么
# 关键词的长度:
df_all['len_of_query'] = df_all['search_term'].map(lambda x:len(x.split())).astype(np.int64)
# 商品标题中有多少关键词重合
df_all['commons_in_title'] = df_all.apply(lambda x:str_common_word(x['search_term'],x['product_title']),axis=1)
# 商品描述中有多少关键词重合
df_all['commons_in_desc'] = df_all.apply(lambda x:str_common_word(x['search_term'],x['product_description']),axis=1)
# 然后把不能被机器学习处理的column给drop掉
df_all = df_all.drop(['search_term','product_title','product_description'],axis=1)
​
# 重塑训练集,测试集---数据处理也是这样,搞完一圈之后,让数据重回原本的样貌
# 分开训练集和测试集
df_train = df_all.loc[df_train.index]
df_test = df_all.loc[df_test.index]
# 记录下测试集的id
test_idx = df_test['id']
# 分离出y_train
y_train = df_train['relevance'].values
# 把原数据集中的label删除,否则就cheating了
X_train = df_train.drop(['id','relevance'],axis=1).values
X_test = df_test.drop(['id','relevance'],axis=1).values
​
#  建立模型---用个最简单的模型:RandomForest回归模型
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import cross_val_score
# 用cv结果保证公正客观性;并调试不同的alpha值
params = [1,3,5,6,7,8,9,10]
test_scores = []
for param in params:
    clf = RandomForestRegressor(n_estimators=30, max_depth=param)
    test_score = np.sqrt(-cross_val_score(clf, X_train, y_train, cv=5, scoring='neg_mean_squared_error')) # 5折交叉验证
    test_scores.append(np.mean(test_score))
# 可视化
import matplotlib.pyplot as plt
plt.plot(params, test_scores)
plt.title("Param vs CV Error")
​
# 用我们测试出的最优解建立模型,并跑跑测试集
rf = RandomForestRegressor(n_estimators=30, max_depth=6)
rf.fit(X_train, y_train)
y_pred = rf.predict(X_test)
# 把拿到的结果,放进PD,做成CSV上传
pd.DataFrame({"id": test_idx, "relevance": y_pred}).to_csv('submission.csv',index=False)

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/858814.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号