物流地址类数据分类算法
项目情况:在工作的过程中拿到一部分物流数据,格式比较杂乱,无法区分这些地址的归属省市区信息,客户想让我把数据进行处理,最终效果为能从数据中提取出省市区信息。
现有数据有7000多条,样例数据如下。
姓名 | 地址 |
---|---|
张三 | 株洲市XX区XX街道XX路XX小区X栋X单元XX |
李四 | 吴兴区XX镇XX南路XX花园X撞X单元XXX |
张三 | 山东省青岛市即墨市XX办事处北XX村 |
李四 | 河南省郑州市新郑市XX路XXXX小区 |
张三 | 江苏省扬州市邗江区XX小区北苑X栋X号 |
李四 | 广东省广州市XX区XXX |
张三 | 广东省深圳市龙岗区XXX园 |
想达到效果:
姓名 | 地址 | 省份 | 市 | 区县 |
---|---|---|---|---|
张三 | 株洲市芦淞区XX街道XX路XX小区X栋X单元XX | 湖南 | 株洲 | 芦淞 |
李四 | 吴兴区XX镇XX南路XX花园X撞X单元XXX | 浙江 | 湖州 | 吴兴 |
张三 | 山东省青岛市即墨市XX办事处北XX村 | 山东 | 青岛 | 即墨 |
李四 | 河南省郑州市新郑市XX路XXXX小区 | 河南 | 郑州 | 新郑 |
张三 | 江苏省扬州市邗江区XX小区北苑X栋X号 | 江苏 | 扬州 | 邗江 |
李四 | 广东省广州市天河区XXX | 广东 | 广州 | 天河 |
张三 | 广东省深圳市龙岗区XXX园 | 广东 | 深圳 | 龙岗 |
给的这部分数据中一部分都是有省市区的,有5000条数据,实际上客户那里80%的数据都是没有省市区的,需要从原数据中提取。
常规机器学习算法效果不佳
第一天拿到数据以后,清洗完,高高兴兴用jieba分词,将数据词组切分,提取关键词然后使用k近邻,随机森林,贝叶斯等进行机器学习算法进行分类,效果不佳。可能是数据量太小或者是类别过多,分类效果最好的是贝叶斯,但是准确率也就55%,这个准确率实在太低了,第一天就这么没了。
换个思路,为什么一定要走别人的路
第二天的时候我看着那些数据,肉眼看是能够区分这些地址归属地的,而且比较有规律,比如数据中出现了某某县或者区,那我就可以根据这个县/区的名称去反推所属省份,这貌似也是个路子。依照这个思路,我就需要做出中国所有省市区的三级对应关系表,然后将原数据中的数据进行分词,和省市区的关系表进行比对,比对成功的自然就是我们想要的了。而且这个方法不用对数据进行学习,貌似也是一个非监督学习算法,编写出第一个非监督学习算法,还是很高兴的。
实现过程
想要完成这项工作,必不可少的就是需要一份中国行政区划表(全国有3000多个县级区域,也就是分类最后要有3000多类,并且区域名称和级别会随时间改变,注意更新对照表)。像这样的:
省份 | 市 | 区县 |
---|---|---|
北京 | 北京市 | 东城区 |
北京 | 北京市 | 怀柔区 |
北京 | 北京市 | 平谷区 |
北京 | 北京市 | 密云县 |
北京 | 北京市 | 延庆县 |
这个表可以在中国统计局官网找到,github也有相关的爬虫项目。
有了这个表以后最终分类的结果就是“省--市--区”的结构,比如:山东省青岛市即墨市XX办事处北XX村,最后给的标签就是“山东--青岛--即墨”。
下面说实现过程:
1、分词
使用jieba分词将地址数据切分成一个个关键词,然后去重。
举个例子来说:
”上海市浦东区南京西路XX号“分词以后的结果就是('号', '区', 'XX', '浦东', '西路', '上海市', '南京')
2、创建关键词集合
创建识别每一个区域所依据的关键词组,例如“ 南京市秦淮区 ”对应的关键词组为(江苏、江苏省、南京、南京市、秦淮、秦淮区),之所以这样是因为有的人填写地址时会加省市区,而有的人不会,jieba分词的时候如果有江苏省这样的字符,分出来的是“ 江苏省 ”而不是“江苏、省”。
3、计算重合度
重合度=(待分类地址关键词与地名关键词重合数)/地名关键词个数
举个例子:
上海市浦东区这个地名的关键词就是(上海、浦东、上海市、浦东区)
南京市秦淮区的关键词就是(江苏、江苏省、南京、南京市、秦淮、秦淮区)
待分类地址 “上海市浦东区南京西路XX号” 分词以后提取的关键词为(上海市、浦东区、南京、西路、XX号)
与上海浦东重合的关键词是(上海市、浦东区),重合度就是 2/4 =0.5,
与南京重合的关键词是(南京),重合度就是1/4=0.25,
结果我们取重合度最高的,也就是“上海市浦东区”
4、代码运行流程:
待分类地址数据 ---> jieba分词 ---> 与所有区域的关键词进行比对 ---> 计算出重合度最高的一个结果返回
5、上代码
因为前面原理说的已经很清楚了,所以代码方面就不做过多解释。
import jieba
import pandas
import numpy
#文件位置
file_path=r'.\重合度计算数据.xlsx'
file_path1=r'.\地址训练用数据.xlsx'
def cut_str(string):
#分词
a=jieba.cut(string,cut_all=False)
return set(a)
#设置预设关键词字典
def chd(a,b):
dict_1={}
count=0
for i in a['full_name_1']:
dict_1[count]=set(i.split('-'))
count+=1
return dict_1
#计算重合度最高的词组
def distance(dict_1,set_i):
b=[]
count=0
for i in range(len(dict_1)):
c=dict_1[i]&set_i
b.append(len(c)/len(dict_1[i]))
max_b=max(b)
return b.index(max_b)
#读取数据
a=pandas.read_excel(file_path)
b=pandas.read_excel(file_path1)
b=b[['地址','labels']]
dict_1=chd(a,b)
predict=[]
for addr in b['地址']:
index_max=distance(dict_1,cut_str(addr))
predict.append(a['labels'][index_max])
'''
预测结果输出
predict_dict={'地址':list(b['地址']),'predict':predict}
out_put=pandas.DataFrame(predict_dict)
out_put.to_excel(r'.\预测结果.xlsx',index=None)
'''
#计算准确率
num=0
for k in range(len(predict)):
if predict[k]!=b['labels'][k] :
num+=1
#if list(predict[k].split('-'))[:2]!=list(b['labels'][k].split('-'))[:2] :
print(predict[k],b['labels'][k]) #输出错误预测结果
print('验证准确率:','{:%}'.format(1-num/len(predict)))
运算结果:
甘肃省-陇南市-武都区 甘肃省-陇南市-成县
甘肃省-陇南市-武都区 甘肃省-陇南市-文县
甘肃省-陇南市-武都区 甘肃省-陇南市-康县
甘肃省-陇南市-武都区 甘肃省-陇南市-礼县
新疆维吾尔自治区-和田地区-和田市 新疆维吾尔自治区-和田地区-和田县
山西省-阳泉市-城区 山西省-阳泉市-郊区
湖南省-长沙市-长沙县 湖南省-长沙市-望城区
江西省-赣州市-赣县 江西省-赣州市-龙南县
台湾-宜兰县-宜兰市 台湾-台中市-东区
台湾-台东县-关山镇 台湾-台东县-台东市
甘肃省-陇南市-武都区 甘肃省-陇南市-徽县
台湾-台东县-关山镇 台湾-台东县-台东市
验证准确率: 98.962443%
截取了最后几条结果作为展示。可以看到准确率还是很高的,将近99%,如果数据只分类到市一级的话准确率几乎达到了100%,只有极小的误差,不过现在的结果已经给客户的工作带来很大的帮助了。
其实代码还有需要优化的地方,比如说最大值选择的时候,没处理重合度相同的情况,因为之后也没再处理这方面的数据,这部分也就没再处理。
如果有人对这个感兴趣,也想拿这份数据做练习的话,可以私聊我,留下邮箱,我看到消息会回复的。