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

【python】结巴分词案例(英文词组识别)本人菜鸡一只,今天来写写结巴分词!哇,距离上一次写文章已经20天过去了,最近这些天还真是挺忙的,主要是上上周到了跑月数据的节点,然后上周原始数据出了问题,我调了一周多才把这个错误解决了,还修复

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

哇,距离上一次写文章已经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,里面还是写的很清晰的,文本分词还是很常见的需求~

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

 

 

今天的文章【python】结巴分词案例(英文词组识别)分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:http://bianchenghao.cn/66002.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注