自然语言处理——word2vec项目实战—— NLP理论基础_非零因子的博客-程序员宝宝_自然语言处理实战项目

技术标签: python  自然语言处理  word2vec  

NLP理论基础

语料库

NLTK : pip install nltk

http://www.nltk.org//

(40条消息) NLTK安装方法_一脑子RMC136的博客-程序员宝宝_nltk安装教程

文本处理流程

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

分词(Tokenize)

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

英文

from nltk.tokenize import word_tokenize
sentences = 'hello world'
token = word_tokenize(sentences)
print(token)
['hello', 'world']

中文

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)) # 搜素引擎模式
full mode: 我/到/北京/清华/清华大学/华大/大学
default mode: 我/到/北京/清华大学
我/到/北京/清华大学
我/到/北京/清华/华大/大学/清华大学

预处理

社交语言

举例:

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 :正则表达式 → 常用于字符串处理

对照表:http://www.regexlab.com/zh/regref.htm

#### 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]|[[email protected]&amp:+]|[!*\(\),]|(?:%[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列表(英文) http://www.ranks.nl/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)http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6010

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

文本相似度

用元素频率表示文本特征

把文本变成相同长度的向量,用余弦定理判断相似性(相似度越高,夹角越小)先点成再叉乘
s i m i l a r i t y = c o s ( θ ) − A ⋅ B ∥ A ∥ ∥ B ∥ similarity=cos(\theta)-\frac{A\cdot{B}}{\|A\|\|B\|} similarity=cos(θ)ABAB

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-IDF

TF(Term Frequency),一个单词在一个文档中出现的有多频繁。
T F ( t ) = t 出 现 在 文 档 中 的 次 数 / 文 档 中 的 单 词 总 数 TF(t) = t出现在文档中的次数/文档中的单词总数 TF(t)=t/
IDF(Inverse Document Frequency),衡量一个term有多重要,如 ‘is’ ‘the’ 这些不重要——所以需要把罕见的权值弄高,把常见的词权值弄低。
I D F ( t ) = l n ( 文 档 总 数 / 含 有 t 的 文 档 总 数 ) IDF(t)=ln(文档总数/含有t的文档总数) IDF(t)=ln(/t)

T F − I D F ( t ) = T F ( t ) × I D F ( t ) TF-IDF(t)=TF(t)\times{IDF(t)} TFIDF(t)=TF(t)×IDF(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)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_46489969/article/details/124716672

智能推荐

Python: 使用 ORM 向 MySQL 数据库写入数据_星海浮生的博客-程序员宝宝_python orm 字段写入数据库

本文根据模型端的上线经验,简要介绍 Python 语言使用 ORM 向 MySQL 数据库写入数据的方式。

孤荷凌寒自学python第五天初识python的列表_weixin_30740295的博客-程序员宝宝

孤荷凌寒自学python第五天 列表(完整学习过程屏幕记录视频地址在文末,手写笔记在文末)粗俗地区分列表,可以这样理解,定义或print列表后显示时,列表中的各元素都是用一个方括号[]括起来的。即列表看起来总是这样的:lstA=[1,3,5,7,9]lstB=[‘我’,’爱’,’祖’,’国’]同其它序列一样,要访问列表的元素,直接引用元素在序列中的index值即...

Pylance 性能更新,微软新的VS Code Python 插件已趋于稳定_Python中文社区的博客-程序员宝宝

微软宣布,Pylance —— 其在Visual Studio Code中对Python的快速且功能丰富的语言支持,现已正式完成测试,并达到其第一个稳定版本。本周早些时候,Pylance ...

《算法图解》——第六章 广度有限搜索_weixin_30569001的博客-程序员宝宝

       第六章 广度有限搜索1  图简介假设你居住在旧金山,要从双子峰前往金门大桥。你想乘公交车前往,并希望换乘最少。可乘坐的公交车如下。从双子峰出发,可沿下面的路线三步到达金门大桥。其他的都需要四步。这种问题被称为最短路径问题(shortest-path problem),解决最短路径问题的算法被称为广度优先搜索。如何解决路径问题,需要两个步骤:①使用...

4. Tachyon安装-Tachyon集群模式搭建_艾文编程的博客-程序员宝宝

tachyon默认支持hadoop-1.0.4版本,如果需要使用更高版本需要重新编译打包。如果使用maven打包,命令如下:mvnclean package -Djava.version=1.7 -Dhadoop.version=2.6.0  -DskipTests 本文采用默认版本进行安装,步骤如下: 1.1.1      Hadoop-1.0.4安装注意:需要实现做好免

STM32F103学习笔记(一)_智定义物联网的博客-程序员宝宝_stm32f103

最近某创和某配互撕,10×10双层板打样低至5RMB,这波薅羊毛的机会当然不能轻易放过啦,这不赶紧搞出一块STM32F103C8T6最小系统板出来玩玩,顺便学习一下STM32,当做入门吧(以前一直用国产的某51单片机),没有被占用的IO口全引出,焊接技术不够,酒精、高压水枪来凑,用高难度酒精洗去助焊剂,用高压水枪冲掉卡在缝隙里的锡渣,可当我可是检测IO功能时却发现好几个IO口不听从召唤,难到是凑技...

随便推点

分享teamviewer14绿色版_banggou6994的博客-程序员宝宝

这几天用teamviewer挺好用的,但是今天提示我试用到期,5分钟限制,哎,在网上找了找总算找了个绿色版,还挺好用的,到期后更改ID就可以再用7天。感谢。百度网盘:https://pan.baidu.com/s/1lJ81OuJ9uWq8hW3SYoHC2Q 提取码:1x74转载于:https://www.cnblogs.com/fwq345/p/11259565....

Android Studio 3.6 稳定版发布_切切歆语的博客-程序员宝宝

Android Studio 3.6稳定版已发布,此版本也是“Project Marble”结束后发布的首个版本,“Project Marble”是 Android Studio 团队去年为提升产品质量而进行的一项计划,在此期间,团队暂缓了新特性的开发工作,专心提升产品质量。该计划着力改进 Android Studio 的三个主要方面:系统运行状况、功能完善以及错误修复,力图在 Android ...

JavaWeb之EL表达式_weixin_34270606的博客-程序员宝宝

时间:2016-11-25 23:06——JavaBean规范 JavaBean出现的目的是在一些可视化工具中完成一些组件的显示。一、规范1、必须为成员提供set/get方法(两者只提供一个也可以) 如果只有get方法,那么这个属性是只读属性。2、必须有默认构造器(无参构造器)3、一般对具有set/get方法的成员变量称之为属性。...

Linux搭建FFMPEG环境实现MP4格式转m3u8格式_zhongyanpingzzz的博客-程序员宝宝

公司要实现mp4文件的切片操作,需要使用到ffmpeg,在网上找了很多搭建环境的文章,发现要么ffmpeg版本太久,要么就是不全,折腾了半天各种问题都没有成功安装。最后在ffmpeg的官网上发现了一篇ffmpeg在linux编译安装的文章,最终终于成功安装,这里记录下安装ffmpeg的全过程,并附上官网的文章url:https://trac.ffmpeg.org/wiki/CompilationGu

GML对象的层次结构_iteye_15968的博客-程序员宝宝

GML是一个复杂的标准。本文的内容以OGC GML 3.1.0为参考标准。它包含的内容非常多,除常规的二维矢量GIS信息以外,还包括复杂目标、拓扑信息、三维目标、时态信息、地理覆盖、注记符号、空间参考、元数据、栅格数据等等信息。和GML2版本不同,GML3.1.0中的Feature并不总是几何对象,而是真正成为一个有实际意义的地理对象(实体或现象)的抽象。这样的Feature既可以描述具...

推荐文章

热门文章

相关标签