本部分是web挖掘课程的一个作业,大部分是基于python实现的,而且就是nlp相关的操作,所以记录在这里了。
有如下的文档集合:
d1 | 水果有西瓜水果,菠萝水果,苹果水果,其它水果。 |
---|---|
d2 | 水果还有苹果,桃子,其它水果。 |
d3 | 蔬菜好吃,水果也好吃。 |
d4 | 苹果,西瓜,苹果都是好吃的。 |
d5 | 好吃的水果有西瓜、苹果,还有菠萝水果,都是水果。 |
停用词表(stop words):的,地,得,有,也,都是,还有,其它。
针对文档文档进行分词,利用python中的jieba库可以很轻松的实现。即首先将文档提取到一个文件内,然后遍历处理即可。
# -*- coding: utf-8 -*-
# @Time : 2022/5/20 17:12
# @Author : MinChess
# @File : jiebacut.py
# @Software: PyCharm
import jieba
import re
cut= ""
all = ""
for line in open('data.txt', encoding='utf-8'):
line.strip('\n')
seg_list = jieba.cut(line,cut_all=False)
cut= (" ".join(seg_list))
print(cut)
all += cut
print(all)
水果 有 西瓜 水果 , 菠萝 水果 , 苹果 水果 , 其它 水果 。
水果 还有 苹果 , 桃子 , 其它 水果 。
蔬菜 好吃 , 水果 也 好吃 。
苹果 , 西瓜 , 苹果 都 是 好吃 的 。
好吃 的 水果 有 西瓜 、 苹果 , 还有 菠萝 水果 , 都 是 水果 。
上述处理的结果明显有一定的问题,首先是标点符号是不需要的,其次的分词结果有偏差,所以要进行进一步的处理。 自定义词表根据jieba库的方法进行实现,即我们建立一个自定义的词库,利用
jieba.load_userdict
方法提前加载词库即可。 标点符号的处理是利用正则表达式将其删除,也就是利用python自有库re
执行,核心代码就一行text = re.sub('\W*', '', line)
# -*- coding: utf-8 -*-
# @Time : 2022/5/20 17:12
# @Author : MinChess
# @File : jiebacut.py
# @Software: PyCharm
import jieba
import re
cut= ""
all = ""
file_userdict = 'dict.txt' #自定义词表
jieba.load_userdict(file_userdict)
for line in open('data.txt', encoding='utf-8'):
line.strip('\n')
text = re.sub('\W*', '', line)
seg_list = jieba.cut(text,cut_all=False)
# seg_list = jieba.cut(line,cut_all=False)
cut= (" ".join(seg_list))
print(cut)
all += cut
print(all)
all_list = all.split()
print(all_list)
水果 有 西瓜 水果 菠萝 水果 苹果 水果 其它 水果
水果 还有 苹果 桃子 其它 水果
蔬菜 好吃 水果 也 好吃
苹果 西瓜 苹果 都是 好吃 的
好吃 的 水果 有 西瓜 苹果 还有 菠萝 水果 都是 水果
['水果', '有', '西瓜', '水果', '菠萝', '水果', '苹果', '水果', '其它', '水果水果', '还有', '苹果', '桃子', '其它', '水果蔬菜', '好吃', '水果', '也', '好吃苹果', '西瓜', '苹果', '都是', '好吃', '的好吃', '的', '水果', '有', '西瓜', '苹果', '还有', '菠萝', '水果', '都是', '水果']
stop_words = ['的','地','得','有','也','都是','还有','其它'] #自定义停用词表
for word in cut_list:
if word not in stop_words:
if word != '\n' and word != " ":
outstr += word
outstr += " "
# -*- coding: utf-8 -*-
# @Time : 2022/5/20 17:12
# @Author : MinChess
# @File : jiebacut.py
# @Software: PyCharm
import jieba
import re
cut= ""
all = ""
outstr = ""
stop_words = ['的','地','得','有','也','都是','还有','其它'] #自定义停用词表
file_userdict = 'dict.txt' #自定义词表
jieba.load_userdict(file_userdict)
for line in open('data.txt', encoding='utf-8'):
line.strip('\n')
text = re.sub('\W*', '', line)
cut_list = jieba.cut(text,cut_all=False)
for word in cut_list:
if word not in stop_words:
if word != '\n' and word != " ":
outstr += word
outstr += " "
cut= ("".join(outstr))
outstr = ""
print(cut)
all += cut
print(all)
all_list = all.split()
print(all_list)
水果 西瓜 水果 菠萝 水果 苹果 水果 水果
水果 苹果 桃子 水果
蔬菜 好吃 水果 好吃
苹果 西瓜 苹果 好吃
好吃 水果 西瓜 苹果 菠萝 水果 水果
['水果', '西瓜', '水果', '菠萝', '水果', '苹果', '水果', '水果', '水果', '苹果', '桃子', '水果', '蔬菜', '好吃', '水果', '好吃', '苹果', '西瓜', '苹果', '好吃', '好吃', '水果', '西瓜', '苹果', '菠萝', '水果', '水果']
根据词项-文档矩阵的定义,可以得出基本实现思路,那就是首先获取基本的去重词组,进一步遍历词组,去文档中进行匹配查询,如果存在,即在对应的位置设置为1,不存在就为0。
# -*- coding: utf-8 -*-
# @Time : 2022/5/20 19:08
# @Author : MinChess
# @File : matrix.py
# @Software: PyCharm
from prettytable import PrettyTable
import numpy as np
docu={'d1':'水果 西瓜 水果 菠萝 水果 苹果 水果 水果',
'd2':'水果 苹果 桃子 水果',
'd3':'蔬菜 好吃 水果 好吃',
'd4':'苹果 西瓜 苹果 好吃',
'd5':'好吃 水果 西瓜 苹果 菠萝 水果 水果',}
all_words = []
file_index = [] #存储文档索引
for i in docu.values():
cut = i.split()
all_words.extend(cut)
set_all_words = set(all_words)
for i in docu.keys():
file_index.append(i)
matrix = {}
matrix['file'] = file_index
for b in set_all_words:
temp = []
for j in docu.keys():
field = docu[j]
split_fielt = field.split()
if b in split_fielt:
temp.append(1)
else:
temp.append(0)
matrix[b] = temp
for i in matrix.keys():
a = []
if(i=='file'):
a.append(i)
a.extend(matrix[i])
table = PrettyTable(a)
else:
a.append(i)
a.extend(matrix[i])
table.add_row(a)
print(table)
+------+----+----+----+----+----+
| file | d1 | d2 | d3 | d4 | d5 |
+------+----+----+----+----+----+
| 西瓜 | 1 | 0 | 0 | 1 | 1 |
| 蔬菜 | 0 | 0 | 1 | 0 | 0 |
| 苹果 | 1 | 1 | 0 | 1 | 1 |
| 桃子 | 0 | 1 | 0 | 0 | 0 |
| 好吃 | 0 | 0 | 1 | 1 | 1 |
| 水果 | 1 | 1 | 1 | 0 | 1 |
| 菠萝 | 1 | 0 | 0 | 0 | 1 |
+------+----+----+----+----+----+
倒排索引是一种检索方式,比如存入数据库的数据是存一篇文章进去,然而检索时我们经常需要通过关键词检索,所以提前做好倒排索引即可方便检索,而省略掉全表扫描的问题了,这是一种用空间换时间的方法。 对每个词项word,,记录所有包含word的文档列表,每篇文档用唯一ID标识。 根据上述内容,设计实现就比较简单了,同样先整理一份去重词表,再逐句匹配,存在就添加索引,这里的索引直接用给定文档的Key作为唯一ID。
# -*- coding: utf-8 -*-
# @Time : 2022/5/20 18:34
# @Author : MinChess
# @File : invertindex.py
# @Software: PyCharm
docu={'d1':'水果 西瓜 水果 菠萝 水果 苹果 水果 水果',
'd2':'水果 苹果 桃子 水果',
'd3':'蔬菜 好吃 水果 好吃',
'd4':'苹果 西瓜 苹果 好吃',
'd5':'好吃 水果 西瓜 苹果 菠萝 水果 水果',}
all_words = []
for i in docu.values():
cut = i.split()
all_words.extend(cut)
set_all_words = set(all_words)
print(set_all_words)
invert_index = dict()
for b in set_all_words:
temp = []
for j in docu.keys():
field = docu[j]
split_field = field.split()
if b in split_field:
temp.append(j)
invert_index[b] = temp
# print(invert_index)
for k, v in invert_index.items():
print("%s:%s" % (k, v))
苹果:['d1', 'd2', 'd4', 'd5']
水果:['d1', 'd2', 'd3', 'd5']
西瓜:['d1', 'd4', 'd5']
蔬菜:['d3']
桃子:['d2']
菠萝:['d1', 'd5']
好吃:['d3', 'd4', 'd5']
词频矩阵就是词在文档内词频的矩阵分布情况,所以实现较为简单,计算词频就行。
# -*- coding: utf-8 -*-
# @Time : 2022/5/20 21:45
# @Author : MinChess
# @File : wordfrequency2.py
# @Software: PyCharm
from prettytable import PrettyTable
import numpy as np
docu={'d1':'水果 西瓜 水果 菠萝 水果 苹果 水果 水果',
'd2':'水果 苹果 桃子 水果',
'd3':'蔬菜 好吃 水果 好吃',
'd4':'苹果 西瓜 苹果 好吃',
'd5':'好吃 水果 西瓜 苹果 菠萝 水果 水果',}
all_words = []
file_index = [] #存储文档索引
for i in docu.values():
cut = i.split()
all_words.extend(cut)
set_all_words = set(all_words)
for i in docu.keys():
file_index.append(i)
matrix = {}
matrix['word'] = set_all_words
for d in file_index:
print(d)
temp = []
for b in set_all_words:
field = docu[d]
split_fielt = field.split()
count = 0
for word in split_fielt:
if(b==word):
count =count + 1
temp.append(count)
matrix[d] = temp
print(matrix)
for i in matrix.keys():
a = []
if(i=='word'):
a.append(i)
a.extend(matrix[i])
table = PrettyTable(a)
else:
a.append(i)
a.extend(matrix[i])
table.add_row(a)
print(table)
+------+------+------+------+------+------+------+------+
| word | 桃子 | 水果 | 苹果 | 菠萝 | 蔬菜 | 西瓜 | 好吃 |
+------+------+------+------+------+------+------+------+
| d1 | 0 | 5 | 1 | 1 | 0 | 1 | 0 |
| d2 | 1 | 2 | 1 | 0 | 0 | 0 | 0 |
| d3 | 0 | 1 | 0 | 0 | 1 | 0 | 2 |
| d4 | 0 | 0 | 2 | 0 | 0 | 1 | 1 |
| d5 | 0 | 3 | 1 | 1 | 0 | 1 | 1 |
+------+------+------+------+------+------+------+------+
sklearn
包进行实现。
# -*- coding: utf-8 -*-
# @Time : 2022/5/20 22:08
# @Author : MinChess
# @File : tfidf.py
# @Software: PyCharm
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import CountVectorizer
from prettytable import PrettyTable
vectorizer = CountVectorizer()
transformer = TfidfTransformer()
corpus = ["水果 西瓜 水果 菠萝 水果 苹果 水果 水果", "水果 苹果 桃子 水果","蔬菜 好吃 水果 好吃","苹果 西瓜 苹果 好吃","好吃 水果 西瓜 苹果 菠萝 水果 水果",]
result_list2 = transformer.fit_transform(vectorizer.fit_transform(corpus)).toarray().tolist()
word = vectorizer.get_feature_names()
print('词典为:')
print(word)
print('归一化后的tf-idf值为:')
count = 1
matrix = {}
matrix['word'] = word
for weight in result_list2:
id = "d"+str(count)
matrix[id] = weight
count = count + 1
print(weight)
for i in matrix.keys():
a = []
if(i=='word'):
a.append(i)
a.extend(matrix[i])
table = PrettyTable(a)
else:
a.append(i)
a.extend(matrix[i])
table.add_row(a)
print(table)
词典为:
['好吃', '桃子', '水果', '苹果', '菠萝', '蔬菜', '西瓜']
归一化后的tf-idf值为:
[0.0, 0.0, 0.9211389809848156, 0.1842277961969631, 0.26382397573591737, 0.0, 0.21899773205574488]
[0.0, 0.6217300025236953, 0.7005436768464253, 0.35027183842321263, 0.0, 0.0, 0.0]
[0.7593397076753798, 0.0, 0.3193902502932603, 0.0, 0.0, 0.5669154049459911, 0.0]
[0.4549836381875804, 0.0, 0.0, 0.7654931599715217, 0.0, 0.0, 0.4549836381875804]
[0.30819636211301865, 0.0, 0.7777934874715958, 0.2592644958238653, 0.3712805096050312, 0.0, 0.30819636211301865]
好吃 | 桃子 | 水果 | 苹果 | 菠萝 | 蔬菜 | 西瓜 | |
---|---|---|---|---|---|---|---|
d1 | 0 | 0 | 0.921138980984815 | 0.184227796196963 | 0.263823975735917 | 0 | 0.218997732055744 |
d2 | 0 | 0.621730002523695 | 0.700543676846425 | 0.350271838423212 | 0 | 0 | 0 |
d3 | 0.759339707675379 | 0 | 0.31939025029326 | 0 | 0 | 0.566915404945991 | 0 |
d4 | 0.45498363818758 | 0 | 0 | 0.765493159971521 | 0 | 0 | 0.45498363818758 |
d5 | 0.308196362113018 | 0 | 0.777793487471595 | 0.259264495823865 | 0.371280509605031 | 0 | 0.308196362113018 |
# -*- coding: utf-8 -*-
# @Time : 2022/5/20 23:26
# @Author : MinChess
# @File : soundex.py
# @Software: PyCharm
import re
string = "tianqi"
string = string.lower()
law = {'aehiouwy' : 0,
'bfpv': 1,
'cgjkqsxz': 2,
'dt': 3,
'l': 4,
'mn': 5,
'r': 6}
temp_string = string[1:]
print(temp_string)
for key, value in law.items():
temp_string = re.sub('[{}]'.format(key), str(value), temp_string)
temp_string = re.sub('0', '', temp_string)
result = []
for char in temp_string:
if char not in result:
result.append(char)
print(result)
# result.remove(result[0])
result = string[0] + ''.join(result[:3])
while len(result) != 4:
result += '0'
print(string,'的Soundex编码为:',result)
tianqi 的Soundex编码为: t520
Document = {term1, term2, …… ,term N}
Document Vector = {weight1, weight2, …… ,weight N}
同样我们把查询语句看作一个简单的文档,也用向量来表示。
Query = {term1, term 2, …… , term N}
Query Vector = {weight1, weight2, …… , weight N}
把所有搜索出的文档向量及查询向量放到一个N维空间中,每个词(term)是一维。