您的位置:首页 > 其它

今天我是如何10分钟完成30万售后单问题分类的

2020-09-21 09:25 197 查看

1. 背景

(1)需求,数据分析组要对公司的售后维修单进行分析,筛选出top10,然后对这些问题进行分析与跟踪;

(2)问题,从售后部拿到近2年的售后跟踪单,纯文本描述,30万条左右数据,5个分析人员分工了下,大概需要1-2周左右,才能把top10问题整理出来。

(3)领导来了,想想法子,通过程序或者算法,把这些问题归下类,统计下热度,弄个top出来,算法后续还会经常用,人工汇总整理太费事了。

(4)接招

需求简单汇总下:因需要从文本描述性信息中归类出同类信息,数据量比较大,大概20多万,人工效率低,需要算法来实现;

软件语言简单总结下: 需要做个文本相似性热度统计算法,统计出那些描述/话,是同一类的问题,再统计下出现的次数,排下序选择出top10;

2.选型

(1)选型过程不累赘了,查了很多资料,验证了很多算法(聚类算法、分词算法、热度统计算法等),效果都不太理想,分词算法分的还可以,但是满足不了业务需求,售后单描述内容太多,分词热度统计出来仅仅是个别词的热度,业务上需要看前后语境,效果不理想。

(2)最终使用python语言实现的,网上也有java语言实现, 也验证了下,效果不是太理想,部署还有点麻烦,python语言大的算法是用的gensim结合jieba分词算法实现的,做了一些的完善和改动,效果还不错。(Gensim是一个简单高效的自然语言处理Python库,用于抽取文档的语义主题)

3.算法说明

30万左右的文本描述数据,一般个人笔记本(4核16g)大概10分钟出结果,并打印出了明细数据,验证了效果。

文本相似性算法实现介绍

(1)输入文件是excel,数据大概20多万,首先通过pandas获取excel信息,通过jieba分词进行处理,jieba分词要首先自定义词典以及排除信息,这样效果会差异很大,然后形成一个二维数组。
(2)使用gensim 中的corpora模块,将分词形成后的二维数组生成词典
(3)将二维数组通过doc2bow稀疏向量,形成语料库
(4)刚开始使用TF模型算法,后来更改为:LsiModel模型算法,将语料库计算出Tfidf值。
(5)获取词典token2id的特征数
(6)计算稀疏矩阵相似度,建立一个索引
(7)读取excel行数据,通过jieba进行分词处理
(8)通过doc2bow计算测试数据的稀疏向量
(9)求得测试数据与样本数据的相似度

如果你觉得文章对你有些帮助,欢迎微信搜索「软件老王」第一时间阅读或交流!

算法说明:

(1)这里有个点,7-9步会循环执行,针对文档描述列中的每一行,会与在第六步中创建的索引就行比对,会统计与该行相似性超过50%的行数据,同时会将统计到的数据增加个数组中,后续不再执行比对,以免重复统计。
(2)第一步jieba算法中会用到专业术语词典及stop词典等,7-9部会循环执行,目前相似度阈值设置的为:50%,另外excel操作就不多说了(增加了汇总起来清单的超链,可以导航到清单)
(3)效率上,20多万的数据,因需要转换向量,大概需要10分钟左右。
(4)大的算法发是这样的,本次主要介绍整句的热度统计,后续会再介绍下分句分组的统计。

4. 完整代码及说明

完整代码,有需要的朋友可以直接拿走使用,无套路,代码分了1-6点说明了下。

import jieba.posseg as pseg
import jieba.analyse
import xlwt
import openpyxl
from gensim import corpora, models, similarities
import re

#停词函数
def StopWordsList(filepath):
wlst = [w.strip() for w in open(filepath, 'r', encoding='utf8').readlines()]
return wlst

def str_to_hex(s):
return ''.join([hex(ord(c)).replace('0x', '') for c in s])

# jieba分词
def seg_sentence(sentence, stop_words):
stop_flag = ['x', 'c', 'u', 'd', 'p', 't', 'uj', 'f', 'r']
sentence_seged = pseg.cut(sentence)
outstr = []
for word, flag in sentence_seged:
if word not in stop_words and flag not in stop_flag:
outstr.append(word)
return outstr

if __name__ == '__main__':
#1 这些是jieba分词的自定义词典,软件老王这里添加的格式行业术语,格式就是文档,一列一个词一行就行了,
# 这个几个词典软件老王就不上传了,可注释掉。
jieba.load_userdict("g1.txt")
jieba.load_userdict("g2.txt")
jieba.load_userdict("g3.txt")

#2 停用词,简单理解就是这次词不分割,这个软件老王找的网上通用的,会提交下。
spPath = 'stop.txt'
stop_words = StopWordsList(spPath)

#3 excel处理
wbk = xlwt.Workbook(encoding='ascii')
sheet = wbk.add_sheet("软件老王sheet")  # sheet名称
sheet.write(0, 0, '表头-软件老王1')
sheet.write(0, 1, '表头-软件老王2')
sheet.write(0, 2, '导航-链接到明细sheet表')
wb = openpyxl.load_workbook('软件老王-source.xlsx')
ws = wb.active
col = ws['B']
# 4 相似性处理
rcount = 1
texts = []
orig_txt = []
key_list = []
name_list = []
sheet_list = []

for cell in col:
if cell.value is None:
continue
if not isinstance(cell.value, str):
continue
item = cell.value.strip('\n\r').split('\t')  # 制表格切分
string = item[0]
if string is None or len(string) == 0:
continue
else:
textstr = seg_sentence(string, stop_words)
texts.append(textstr)
orig_txt.append(string)
dictionary = corpora.Dictionary(texts)
feature_cnt = len(dictionary.token2id.keys())
corpus = [dictionary.doc2bow(text) for text in texts]
tfidf = models.LsiModel(corpus)
index = similarities.SparseMatrixSimilarity(tfidf[corpus], num_features=feature_cnt)
result_lt = []
word_dict = {}
count =0
for keyword in orig_txt:
count = count+1
print('开始执行,第'+ str(count)+'行')
if keyword in result_lt or keyword is None or len(keyword) == 0:
continue
kw_vector = dictionary.doc2bow(seg_sentence(keyword, stop_words))
sim = index[tfidf[kw_vector]]
result_list = []
for i in range(len(sim)):
if sim[i] > 0.5:
if orig_txt[i] in result_lt and orig_txt[i] not in result_list:
continue
result_list.append(orig_txt[i])
result_lt.append(orig_txt[i])
if len(result_list) >0:
word_dict[keyword] = len(result_list)
if len(result_list) >= 1:
sname = re.sub(u"([^\u4e00-\u9fa5\u0030-\u0039\u0041-\u005a\u0061-\u007a])", "", keyword[0:10])+ '_'\
+ str(len(result_list)+ len(str_to_hex(keyword))) + str_to_hex(keyword)[-5:]
sheet_t = wbk.add_sheet(sname)  # Excel单元格名字
for i in range(len(result_list)):
sheet_t.write(i, 0, label=result_list[i])

#5 按照热度排序 -软件老王with open("rjlw.txt", 'w', encoding='utf-8') as wf2:
orderList = list(word_dict.values())
orderList.sort(reverse=True)
count = len(orderList)
for i in range(count):
for key in word_dict:
if word_dict[key] == orderList[i]:
key_list.append(key)
word_dict[key] = 0
wf2.truncate()
#6 写入目标excel
for i in range(len(key_list)):
sheet.write(i+rcount, 0, label=key_list[i])
sheet.write(i+rcount, 1, label=orderList[i])
if orderList[i] >= 1:
shname = re.sub(u"([^\u4e00-\u9fa5\u0030-\u0039\u0041-\u005a\u0061-\u007a])", "", key_list[i][0:10]) \
+ '_'+ str(orderList[i]+ len(str_to_hex(key_list[i])))+ str_to_hex(key_list[i])[-5:]
link = 'HYPERLINK("#%s!A1";"%s")' % (shname, shname)
sheet.write(i+rcount, 2, xlwt.Formula(link))
rcount = rcount + len(key_list)
key_list = []
orderList = []
texts = []
orig_txt = []
wbk.save('软件老王-target.xls')

代码说明:

(1) #1 是jieba分词的自定义词典,软件老王这里添加的格式行业术语,格式就是文档,就一列,一个词一行就行了, 这个几个行业词典软件老王就不上传了,可注释掉。

jieba.load_userdict("g1.txt")
jieba.load_userdict("g2.txt")
jieba.load_userdict("g3.txt")

(2) #2 停用词,简单理解就是这些词不拆分,这个文件软件老王是从网上找的通用的,也可以不用。

spPath = 'stop.txt'
stop_words = StopWordsList(spPath)

(3) #3 excel处理,这里新增了名称为“软件老王sheet”的sheet,表头有三个,分别为“表头-软件老王1”,“表头-软件老王2”,“导航-链接到明细sheet表”,其中“导航-链接到明细sheet表”带超链接,可以导航到明细数据。

wbk = xlwt.Workbook(encoding='ascii')
sheet = wbk.add_sheet("软件老王sheet")  # sheet名称
sheet.write(0, 0, '表头-软件老王1')
sheet.write(0, 1, '表头-软件老王2')
sheet.write(0, 2, '导航-链接到明细sheet表')
wb = openpyxl.load_workbook('软件老王-source.xlsx')
ws = wb.active
col = ws['B']

(4)# 4 相似性处理,算法核心就在这里。

rcount = 1
texts = []
orig_txt = []
key_list = []
name_list = []
sheet_list = []
for cell in col:
if cell.value is None:
continue
if not isinstance(cell.value, str):
continue
item = cell.value.strip('\n\r').split('\t')  # 制表格切分
string = item[0]
if string is None or len(string) == 0:
continue
else:
textstr = seg_sentence(string, stop_words)
texts.append(textstr)
orig_txt.append(string)
dictionary = corpora.Dictionary(texts)
feature_cnt = len(dictionary.token2id.keys())
corpus = [dictionary.doc2bow(text) for text in texts]
tfidf = models.LsiModel(corpus)
index = similarities.SparseMatrixSimilarity(tfidf[corpus], num_features=feature_cnt)
result_lt = []
word_dict = {}
count =0
for keyword in orig_txt:
count = count+1
print('开始执行,第'+ str(count)+'行')
if keyword in result_lt or keyword is None or len(keyword) == 0:
continue
kw_vector = dictionary.doc2bow(seg_sentence(keyword, stop_words))
sim = index[tfidf[kw_vector]]
result_list = []
for i in range(len(sim)):
if sim[i] > 0.5:
if orig_txt[i] in result_lt and orig_txt[i] not in result_list:
continue
result_list.append(orig_txt[i])
result_lt.append(orig_txt[i])
if len(result_list) >0:
word_dict[keyword] = len(result_list)
if len(result_list) >= 1:
sname = re.sub(u"([^\u4e00-\u9fa5\u0030-\u0039\u0041-\u005a\u0061-\u007a])", "", keyword[0:10])+ '_'\
+ str(len(result_list)+ len(str_to_hex(keyword))) + str_to_hex(keyword)[-5:]
sheet_t = wbk.add_sheet(sname)  # Excel单元格名字
for i in range(len(result_list)):
sheet_t.write(i, 0, label=result_list[i])

(5) #5 按照热度高低排序,主要是对excel数据进行操作。

with open("rjlw.txt", 'w', encoding='utf-8') as wf2:
orderList = list(word_dict.values())
orderList.sort(reverse=True)
count = len(orderList)
for i in range(count):
for key in word_dict:
if word_dict[key] == orderList[i]:
key_list.append(key)
word_dict[key] = 0
wf2.truncate()

(6) #6 写入目标excel

for i in range(len(key_list)):
sheet.write(i+rcount, 0, label=key_list[i])
sheet.write(i+rcount, 1, label=orderList[i])
if orderList[i] >= 1:
shname = re.sub(u"([^\u4e00-\u9fa5\u0030-\u0039\u0041-\u005a\u0061-\u007a])", "", key_list[i][0:10]) \
+ '_'+ str(orderList[i]+ len(str_to_hex(key_list[i])))+ str_to_hex(key_list[i])[-5:]
link = 'HYPERLINK("#%s!A1";"%s")' % (shname, shname)
sheet.write(i+rcount, 2, xlwt.Formula(link))
rcount = rcount + len(key_list)
key_list = []
orderList = []
texts = []
orig_txt = []
wbk.save('软件老王-target.xls')

5. 效果图

(1)软件老王-source.xlsx,待处理excel文本描述数据。

(2)软件老王-target.xls,算法处理好的结果数据。

(3)简单说明

​ 中间其实遇到不少坑,一是要调算法,二是要对excel进行处理,生成业务想要的结果,好在结果不错,业务很满意,真实数据不太方便公布(其实就是业务售后跟踪单,描述了客户反馈的什么问题,判断是什么问题,最后到底是什么问题,怎么解决的),简单造了一列演示数据,说明了下效果。

更多知识请关注公众号:「软件老王」,IT技术与相关干货分享,回复关键字获取对应干货,java,送必看的10本“武功秘籍”;图片,送100多万张可商用高清图片;面试,送刚毕业就能月薪“20k”的java面试题,后续不断更新中,比如“软考”、“工具”等,已经在整理中。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐