【python】结巴分词案例(英文词组识别)

您所在的位置:网站首页 在字典里查找的英文短语 【python】结巴分词案例(英文词组识别)

【python】结巴分词案例(英文词组识别)

2024-07-13 07:35| 来源: 网络整理| 查看: 265

本人菜鸡一只,今天来写写结巴分词!

哇,距离上一次写文章已经20天过去了,最近这些天还真是挺忙的,主要是上上周到了跑月数据的节点,然后上周原始数据出了问题,我调了一周多才把这个错误解决了,还修复了一个隐藏的小bug

在这里提醒下自己,用任何表在做关联的时候一定要好好检查,关联键是不是唯一的,否则会数据倍增!!

其实在这一段时间里,还是有一点点自己学习的。

首先整理了ES的一些API,还没整理完,后面我会出一篇文章来写这个的!

本文,是最近使用结巴分词做的一些事情的总结! 业务场景:

先说说业务场景,数据库中有一些文本,我想从文本里面统计某些词的count,这些词是我自定义的词(就比如说是洗发水的品牌名称吧),我想看看每一条文本中,是否有提到相关品牌,并且提到的次数!

 

实现工具:

python+结巴分词+数据库,应该是开发起来最快的了吧,虽然python可能性能不是那么好,但是用起来方便!

结巴的介绍1:https://gitee.com/fxsjy/jieba

结巴的介绍2:https://github.com/fxsjy/jieba

  实际遇到的问题:

1、英文词组如何处理

有一些品牌是英文,有大小写的,有空格,比如(SUPER MILD),可能结巴分词直接把这两个英文拆开了,那就匹配不上了!

因此我搜索到了解决方案:https://segmentfault.com/q/1010000016011808

1、在结巴根目录下,打开__init__.py只需要往相应的正则表达式添加空格即可,如

-re_han_default = re.compile("([\u4E00-\u9FD5a-zA-Z0-9+#&\._%]+)", re.U) +re_han_default = re.compile("([\u4E00-\u9FD5a-zA-Z0-9+#&\._% ]+)", re.U)

 2、或者在调用jieba.cut(text, cut_all=False)之前,先执行:

jieba.re_han_default = re.compile('(.+)', re.U)

 

 这样就可以识别词组了,当然也可以考虑换一个分词包来实现,比如:MWETokenizer

2、添加自定义词(其实就是洗发水品牌名称)

https://github.com/fxsjy/jieba/issues/14

上面这个网址,大家有兴趣可以往后翻翻,有一些开发者提出的一些使用上的问题,也有人在帮忙回答,说不定就能解决你的问题!

 

 

贴上代码: # coding=gbk import psycopg2 import jieba.analyse ##读取品牌名称列表,通过这个list来过滤掉不属于洗发水品牌的词汇 def readbrandTXT(rootdir): brandList = [] with open(rootdir, 'r', encoding='UTF-8') as file_to_read: while True: line = file_to_read.readline() if not line: break line = line.strip('\n') brandList.append(line) return brandList # 获取该文本的词和词的出现次数 def getNum(text, list): word = [] counter = {} jieba.re_han_default = re.compile('(.+)', re.U) seg_list = jieba.cut(text) listStr = "#".join(seg_list) list = listStr.split('#') for w in list: if w in list: if not w in word: word.append(w) if not w in counter: counter[w] = 1 else: counter[w] += 1 counter_list = sorted(counter.items(), key=lambda x: x[1], reverse=True) return counter_list # 插入数据库的方法 def insertManyRow(strings): try: conn = psycopg2.connect(database="数据库名", user="用户名", password="密码", host="ip地址",port="端口号") cur2 = conn.cursor() sql2 = "INSERT INTO schema名称.表名(字段1,字段2,字段3,字段4...很多字段) " \ "VALUES(%(字段1)s,%(字段2)s,%(字段3)s,%(字段4)s...很多字段)" cur2.executemany(sql2, strings) conn.commit() cur2.close() conn.close() print("成功插入数据,关闭连接") except Exception as e: print("执行sql时出错:%s" % (e)) cur2.rollback() conn.close() ##获取还未处理的数据 def getUnprocessedData(): conn = psycopg2.connect(database="数据库名", user="用户名", password="密码", host="ip地址",port="端口号") cur3 = conn.cursor() #这里是一段leftjoin,查出有哪些数据还未处理,一次性查出2000条 cur3.execute("""SELECT a.* FROM 全量数据表 a LEFT JOIN 已处理的数据表 b \ on a.主键=b.主键 \ WHERE b.主键 is null limit 2000""") rows = cur3.fetchall() # all rows in table #print(rows) #print("============") return rows if __name__ == "__main__": brandList = readbrandTXT('D:\\洗发水品牌列表.txt') for i in range(100): print('开始循环:',i+1) strings = [] rows = getUnprocessedData() #通过i来判断批量插入的时间点 i = 0 try: for index in range(len(rows)): #将文本传入getNum,和想要的品牌列表 counter_list = getNum(rows[index][4] + rows[index][5], brandList ) if (counter_list.__len__()!=0): for j in counter_list: text = {} text = {'字段1': rows[index][0], '字段2': rows[index][1], '字段3': rows[index][2], '字段4': rows[index][3], "字段5": rows[index][4]....把字段都放进来} strings.append(text) i = i + 1 # print(text) else: #如果返回的结果为空,证明该文本中没有相关词汇,就插入null text = {'字段1': rows[index][0], '字段2': rows[index][1], '字段3': rows[index][2], '字段4': rows[index][3], "字段5": None....把字段都放进来,} strings.append(text) i = i + 1 #约500条数据插入一次 if (i >= 500): print("i:",i) insertManyRow(strings) strings.clear() i = 0 #如果到了最后,数据不到500条也需要强行执行插入 if (strings.__len__() != 0): print("strings.__len__()",strings.__len__()) insertManyRow(strings) strings.clear() except Exception as e: print('Error',e) #就算当前循环插入失败,也继续下一步循环(因为是增量处理,所以插入失败的数据会被重新查出来) continue

 

好的,本人比较不是专业的python工程师,所以代码可能写的稀烂,不好意思,请谅解!

 

我遇到的问题,与需要注意的点:

1、要使用英文词汇,需要添加正则匹配规则的修改

2、添加自定义词的时候

-1.加载文档

jieba.load_userdict("D:\\load_taobrand.txt")

但是在使用加载文档的时候,会遇到文档里面用空格来做不同列的分割符,但是我的词汇中自带空格,导致词汇无法添加,解决方案是要么用单独添加词组的方式,要么修改load_userdict方法默认的分隔符,详情见如下:

相关issue:https://github.com/fxsjy/jieba/issues/423

 -2.单独添加词语

jieba.add_word("自定义词语")

3、判别是否需要添加该自定义的词

-1.词组纯英文单词

如果有的品牌是纯英文单词,例如:AB,如果修改了正则匹配规则,并添加了该词到自定义词汇中,会导致“ABCDEFG HIJKLMN”这样的一串英文,原本分为ABCDEFG,HIJKLMN两个词,变成分为AB,CDEFG,HIJKLMN三个词,这样其实违背了我们的意愿,我们想要的是,单独提到AB品牌的文章,因此纯英文单词,没有任何符号的词不需要加入到自定义词汇中!

-2.纯中文品牌

纯中文品牌也需要注意,有些品牌名字比较长,比如:“悦诗风吟”,如果不添加该词的话,结巴分词默认会分为“悦诗”,“风吟”两个词,这样也就匹配不上该品牌,所以名字较长,或者不是常规词汇的中文品牌,需要添加到自定义词汇中!

-3.品牌名称夹杂中英文或者特殊符号

这部分品牌建议还是要添加到词汇中的,例如:DE&E,如果不添加,默认是“DE”,“&”,“E”,因此如果要识别,也需要添加

4、处理数据当中,我遇到了一些识别字符串中是否包含英文,是否包含中文,是否纯英文等等需求,我稍微记录下(不同数据库用法不同,我是greenplum/postgresql)

--当包含中文的时候,如下两个函数返回长度不一样 select octet_length(字符串) char_length(字符串) --是否纯英文 select 字符串 ~ '^([a-zA-Z]+\s?[a-zA-Z]*\s?[a-zA-Z]*)$';

 

 

 

总结:

总结下有哪些需要改进的地方:

1、品牌名字过短,是一些常用词汇或者有歧义,比如“一点点”,“时候”,“美的”等品牌,可能文章中是“天冷的时候”,“美的一天”,但是却被识别成某个品牌,就是有些品牌名字会跟大众使用的词汇混合起来,就不好识别,暂时没有想到好的方法来解决

2、性能比较差,我的每个文本其实很短,也就40个字左右吧(可能还没有),有21W条数据,运行我的代码,批量插入数据库,最终运行了5个小时左右,也就是每秒能够往数据库插入十几条数据,相对来说还是比较慢的

 

当然这个需求只是个先行版,后面肯定会有更多更复杂的东西在里面,我也没想好,后面再说吧!有兴趣大家可以好好看看结巴分词的GitHub的README,里面还是写的很清晰的,文本分词还是很常见的需求~

好了本文就到这里,菜鸡一只,如果有任何疑问,或者我说的不对的地方,欢迎大家留言!

 

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3