Python nlp 简单的数据处理

简单字符串处理

去除与替换

strip()

strip()用于去除lstrip()rstrip()的字符,若括号内为空则默认去除空格。

  • 若是单个字符,则是从首/尾字母开始匹配要去除的内容,到第一个匹配失败停止。

  • 若是多个字符,去除字符时与括号内的字符顺序无关。

replace()

replace()需要两个参数,一个是要被替换的字符,另一个是用于替换的字符。(即替换前和替换后)

查找与判断

find()

find()会返回要目标字符的索引(从0开始)。

isXXX()

python官方定义的字母是英文字母+汉字;官方定义的数字是阿拉伯数字+带圈的数字。

分割与合并

split()

split()根据传入的分割字符进行分割,返回一个list。

join()

join()以指定的字符进行字符串合并,在分割符相同的情况下和split()为互逆操作。

正则表达式

匹配方法

  • match():从开始位置进行匹配,开头没有返回NoneType不会继续往后搜索,返回MatchObject;
  • search():开头不匹配则会跳过开头继续查找,返回MatchObject;
  • findall():搜索整个字符串,返回一个list。
  • 字符匹配

    正则表达式是一个字符一个字符匹配的,用pattern存储“规则”(或者说是模板)。
说明 示例 匹配结果
一般字符 匹配字符本身 abc abc
. 匹配除了换行符外的任意一个字符 a.c abc, adc, a/c
\\ 匹配有特殊作用的字符,如 . 或 * a\.c a.c
[...] 匹配中括号内的任意一个字符 a[bcd]e abe, ace, ade

.

\

[...]

  • [abc]:匹配字符集里的字符;
  • [a-zA-Z]:匹配所有英文字母不区分大小写;
  • [^a-zA-Z]^表示对当前正则表达式取否,即匹配不是英文字母的字符;
  • |:可以连接两个规则,如[a-zA-Z]|[0-9]=[a-zA-Z0-9]

预定义字符集

\大写字母\小写字母的否定。

  • \d, \D:数字与非数字;
  • \s, \S:空白字符(间隔符)[<空格>\t\r\n\f\v]与非空白字符;
  • \w, \W:单词字符[A-Za-z0-9_]与非单词字符;
  • \b\w能匹配的到的字符的边界,具体可参考这篇博客,部分例子如下。

数量词

说明 示例 匹配结果
* 匹配前一个字符[0, ∞)次 abc* ab, abccc
+ 匹配前一个字符[1, ∞)次 abc+ abc, abccc
? 匹配前一个字符[0, 1)次 abc? ab, abc
{m} 匹配前一个字符m次 abc{3} abccc
{m,n} 匹配前一个字符[m, n]次 ab{1,2}c anc, abbc

字符串的替换和修改

  • sub(rule, replace, target[,count]):第一个参数是正则表达式,第二个参数指定用于替换的字符串,第三个参数是要被替换处理的字符串,第四个参数是最多替换次数。
  • subn(rule, replace, target[,count]):参数说明同上,不同的是,sub()返回一个被替换后的字符串,subn()返回的是一个元组,第一个元素是替换后的字符串,第二个元素是产生替换的次数。

re+split()

使用指定的正则规则在目标字符串中查找匹配的字符串,并以此为界进行分割。

(?P<...>)

(?P<name>)允许给不同的规则取名,通过名字来决定使用哪个规则。

需要注意的是,这里使用search匹配到的第一个结果是“机器学习”而非“自然语言处理”。这是因为使用命名组时,search先匹配的是符合两个规则的子串,然后在这个子串中进行匹配。在这个例子中,第一个被找到的匹配整个正则表达式的子串是“234机器学习”,所以,没有“自然语言处理”。如果要匹配数字之前的文本,要调换两个组的顺序。

NLTK

适用于英文文本的处理。pip install nltk

分词

英文分词的时候token是不区分大小写的。

1
2
3
4
5
from nltk.tokenize import word_tokenize

input_str = "Today's weather is good, very windy and sunny, we have no classes in the afternoon,We have to play basketball tomorrow."
tokens = word_tokenize(input_str)
tokens = [word.lower() for word in tokens] # 不区分大小写

Text对象

Text类里封装了很多方法。

1
2
3
4
5
6
7
8
from nltk.text import Text

input_str = "Today's weather is good, very windy and sunny, we have no classes in the afternoon,We have to play basketball tomorrow."
tokens = word_tokenize(input_str)
t = Text(tokens)
t.count('good') # 统计 good 的出现次数
t.index('good') # 获取 good 的索引
t.plot(8) # 将出现频率前八的单词可视化

停用词过滤

停用词即在句子中权重低的词(非关键词),如is/the/we/their等,这些出现频率太高、不包含重要语义的词。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from nltk.corpus import stopwords

input_str = "Today's weather is good, very windy and sunny, we have no classes in the afternoon,We have to play basketball tomorrow."
tokens = word_tokenize(input_str)
test_words = [word.lower() for word in tokens]

# 将分词后的结果变为无重复元素的集合
test_words_set = set(test_words)
# 查看 test_words_set 有的停用词
test_words_set.intersection(set(stopwords.words('english')))
# 过滤停用词
filtered = [w for w in test_words_set if(w not in stopwords.words('english'))]
# 输出结果
# ['today', 'good', 'windy', 'sunny', 'afternoon', 'play', 'basketball', 'tomorrow', 'weather', 'classes', ',', '.', "'s"]

词性标注

标注后的词性可以参考这里给出的解释。

1
2
3
from nltk import pos_tag

tags = pos_tag(tokens)

POS Tag 指代
CC 并列连词
CD 基数词
DT 限定符
EX 存在词
FW 外来词
IN 介词或从属连词
JJ 形容词
JJR 比较级的形容词
JJS 最高级的形容词
LS 列表项标记
MD 情态动词
NN 名词单数
NNS 名词复数
NNP 专有名词
PDT 前置限定词
POS 所有格结尾
PRP 人称代词
PRP$ 所有格代词
RB 副词
RBR 副词比较级
RBS 副词最高级
RP 小品词
UH 感叹词
VB 动词原型
VBD 动词过去式
VBG 动名词或现在分词
VBN 动词过去分词
VBP 非第三人称单数的现在时
VBZ 第三人称单数的现在时
WDT 以wh开头的限定词

分块

1
2
3
4
5
6
7
8
9
from nltk.chunk import RegexpParser

sentence = [('the','DT'),('little','JJ'),('yellow','JJ'),('dog','NN'),('died','VBD')]
grammer = "MY_NP: {<DT>?<JJ>*<NN>}"
cp = nltk.RegexpParser(grammer) #生成规则
result = cp.parse(sentence) #进行分块
print(result)

result.draw() #调用matplotlib库画出来,树状结构

命名实体识别

1
2
3
4
from nltk import ne_chunk

sentence = "Edison went to Tsinghua University today."
print(ne_chunk(pos_tag(word_tokenize(sentence))))

数据清洗实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import re
from nltk.corpus import stopwords
# 输入数据
s = ' RT @Amila #Test\nTom\'s newly listed Co &amp; Mary\'s unlisted Group to supply tech for nlTK.\nh $TSLA $AAPL https:// t.co/x34afsfQsh'

#指定停用词
cache_english_stopwords = stopwords.words('english')

def text_clean(text):
# 去掉HTML标签(&amp, @Amila等)
text_no_special_entities = re.sub(r'\&\w*;|#\w*|@\w*', '', text)

# 去掉 $ 符号
text_no_tickers = re.sub(r'\$\w*', '', text_no_special_entities)

# 去掉超链接
text_no_hyperlinks = re.sub(r'https?:\/\/.*\/\w*', '', text_no_tickers)

# 去掉一些专门名词缩写,简单来说就是字母比较少的词
text_no_small_words = re.sub(r'\b\w{1,2}\b', '', text_no_hyperlinks)

# 多余的空格变为一个空格,去掉句首的空格
text_no_whitespace = re.sub(r'\s\s+', ' ', text_no_small_words)
text_no_whitespace = text_no_whitespace.lstrip(' ')

# 分词
tokens = word_tokenize(text_no_whitespace)

# 去停用词
list_no_stopwords = [i for i in tokens if i not in cache_english_stopwords]

# 过滤后结果
text_filtered =' '.join(list_no_stopwords)

Spacy

pip install spacy & python -m spacy download en

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import spacy

nlp = spacy.load('en')
doc = nlp('Weather is good, very windy and sunny. We have no classes in the afternoon.')

# 分词
for token in doc:
print (token)

# 分句
for sent in doc.sents:
print (sent)

# 查看词性
for token in doc:
print ('{}-{}'.format(token,token.pos_))

# 命名实体识别
doc_2 = nlp("I went to Paris where I met my old friend Jack from uni.")
for ent in doc_2.ents:
print ('{}-{}'.format(ent,ent.label_))

spacy提供实体标注可视化包displacy

jieba

jieba分词综合了基于字符串匹配的算法和基于统计的算法。

  • 基于前缀词典实现高效的词图扫描,生成句子中汉字所有可能成词情况所构成的有向无环图 (DAG);
  • 采用了动态规划查找最大概率路径,找出基于词频的最大切分组合;
  • 对于未登录词,采用了基于汉字成词能力的 HMM 模型,使用了 Viterbi 算法。

分词

jieba分词时可选择4种模式:精确模式、全模式、搜索引擎模式、paddle模式,最常用的还是前三种。

jieba.cut 以及 jieba.cut_for_search 返回的结构都是一个可迭代的 generator,可以使用 for 循环来获得分词后得到的每一个词语(unicode),jieba.lcut 以及 jieba.lcut_for_search 直接返回 list。

  • jieba.cut 方法接受四个输入参数:
    1. 需要分词的字符串;
    2. cut_all参数用来控制采用全模式/精确模式,默认是精确模式;
    3. HMM 参数用来控制是否使用 HMM 模型;
    4. use_paddle 参数用来控制是否使用paddle模式下的分词模式,paddle模式采用延迟加载方式,通过enable_paddle接口安装paddlepaddle-tiny,并且import相关代码;
  • jieba.cut_for_search 方法接受两个参数:
    1. 需要分词的字符串;
    2. 是否使用 HMM 模型。该方法适合用于搜索引擎构建倒排索引的分词,粒度比较细。
1
2
3
4
5
6
import jieba

seg_list = jieba.cut("我来到北京清华大学", cut_all=True) # 全模式
seg_list = jieba.cut("我来到北京清华大学", cut_all=False) # 精确模式
seg_list = jieba.cut("他来到了网易杭研大厦") # 默认是精确模式
seg_list = jieba.cut_for_search("小明硕士毕业于中国科学院计算所,后在日本京都大学深造") # 搜索引擎模式

全模式:我/ 来到/ 北京/ 清华/ 清华大学/ 华大/ 大学

精确模式:我/ 来到/ 北京/ 清华大学

新词识别:他, 来到, 了, 网易, 杭研, 大厦 (此处,“杭研”并没有在词典中,但是也被Viterbi算法识别出来了)

搜索引擎模式: 小明, 硕士, 毕业, 于, 中国, 科学, 学院, 科学院, 中国科学院, 计算, 计算所, 后, 在, 日本, 京都, 大学, 日本京都大学, 深造

添加自定义词典

对于一些专有名词,可以用jieba加载自定义词典(词典应保存为utf-8编码)。词典格式是一个词一行,每一行包括词语、词频(可省略)、词性(可省略)三部分,用空格隔开,顺序不可颠倒。

1
jieba.load_userdict("./data/mydict.txt") 

也可以直接添加词,但这个词只是临时保存了,再创建新的文本分词时词表里不会有这个词。

1
jieba.add_word(word, freq=None, tag=None)

关键词抽取

analyse.extract_tags可以抽取文本里的关键词。

1
2
3
4
5
import jieba.analyse

text = "故宫的著名景点包括乾清宫、太和殿和黄琉璃瓦等"
seg_list = jieba.cut(text, cut_all=False)
tags = jieba.analyse.extract_tags(text, topK=5)

withWeight可以查看每个词的权重,topK限定查看的范围。

1
2
3
tags = jieba.analyse.extract_tags(text, topK=5, withWeight=True)
for word, weight in tags:
print(word, weight)

词性标注

1
2
3
4
5
import jieba.posseg as pseg

words = pseg.cut("我爱北京天安门")
for word, flag in words:
print("%s %s" % (word, flag))

Reference:python-nlp(P2-P13)正则表达式-边界jieba分词用法及原理


Python nlp 简单的数据处理
https://jiangcara.github.io/posts/24988785/
作者
Jiang Cara
发布于
2024年7月31日
许可协议