实战分享之专业领域词汇无监督挖掘
作者丨苏剑林
单位丨广州火焰信息科技有限公司
研究方向丨NLP,神经网络
个人主页丨kexue.fm
去年 Data Fountain 曾举办了一个“电力专业领域词汇挖掘”的比赛,该比赛有意思的地方在于它是一个“无监督”的比赛,也就是说它考验的是从大量的语料中无监督挖掘专业词汇的能力。
大赛主页:
https://www.datafountain.cn/competitions/320/details
这个确实是工业界比较有价值的一个能力,又想着我之前也在无监督新词发现中做过一定的研究,加之“无监督比赛”的新颖性,所以当时毫不犹豫地参加了,然而最终排名并不靠前。
不管怎样,还是分享一下我自己的做法,这是一个真正意义上的无监督做法,也许会对部分读者有些参考价值。
基准对比
首先,新词发现部分,用到了我自己写的库 NLP Zero,基本思路是先分别对“比赛所给语料”、“自己爬的一部分百科百科语料”做新词发现,然后两者进行对比,就能找到一批“比赛所给语料”的特征词。
NLP Zero:
https://kexue.fm/archives/5597
参考的源码是:
from nlp_zero import *import reimport pandas as pdimport pymongoimport logginglogging.basicConfig(level = logging.INFO, format = '%(asctime)s - %(name)s - %(message)s')
class D: # 读取比赛方所给语料 def __iter__(self): with open('data.txt') as f: for l in f: l = l.strip().decode('utf-8') l = re.sub(u'[^\u4e00-\u9fa5]+', ' ', l) yield l
class DO: # 读取自己的语料(相当于平行语料) def __iter__(self): db = pymongo.MongoClient().baike.items for i in db.find().limit(300000): l = i['content'] l = re.sub(u'[^\u4e00-\u9fa5]+', ' ', l) yield l
# 在比赛方语料中做新词发现f = Word_Finder(min_proba=1e-6, min_pmi=0.5)f.train(D()) # 统计互信息f.find(D()) # 构建词库
# 导出词表words = pd.Series(f.words).sort_values(ascending=False)
# 在自己的语料中做新词发现fo = Word_Finder(min_proba=1e-6, min_pmi=0.5)fo.train(DO()) # 统计互信息fo.find(DO()) # 构建词库
# 导出词表other_words = pd.Series(fo.words).sort_values(ascending=False)other_words = other_words / other_words.sum() * words.sum() # 总词频归一化(这样才便于对比)
"""对比两份语料词频,得到特征词。对比指标是(比赛方语料的词频 + alpha)/(自己语料的词频 + beta);alpha和beta的计算参考自 http://www.matrix67.com/blog/archives/5044"""
WORDS = words.copy()OTHER_WORDS = other_words.copy()
total_zeros = (WORDS + OTHER_WORDS).fillna(0) * 0words = WORDS + total_zerosother_words = OTHER_WORDS + total_zerostotal = words + other_words
alpha = words.sum() / total.sum()
result = (words + total.mean() * alpha) / (total + total.mean())result = result.sort_values(ascending=False)idxs = [i for i in result.index if len(i) >= 2] # 排除掉单字词
# 导出csv格式pd.Series(idxs[:20000]).to_csv('result_1.csv', encoding='utf-8', header=None, index=None)
语义筛选
注意到,按照上述方法导出来的词表,顶多算是“语料特征词”,但是还不完全是“电力专业领域词汇”。如果着眼于电力词汇,那么需要对词表进行语义上的筛选。
我的做法是:用导出来的词表对比赛语料进行分词,然后训练一个 Word2Vec 模型,根据 Word2Vec 得到的词向量来对词进行聚类。
首先是训练 Word2Vec:
# nlp zero提供了良好的封装,可以直到导出一个分词器,词表是新词发现得到的词表。tokenizer = f.export_tokenizer()
class DW: def __iter__(self): for l in D(): yield tokenizer.tokenize(l, combine_Aa123=False)
from gensim.models import Word2Vec
word_size = 100word2vec = Word2Vec(DW(), size=word_size, min_count=2, sg=1, negative=10)
然后是聚类,不过这不是严格意义上的聚类,而是根据我们自己跳出来的若干个种子词,然后找到一批相似词来。算法是用相似的传递性(有点类似基于连通性的聚类算法),即 A 和 B 相似,B 和 C也相似,那么 A、B、C 就聚为一类(哪怕A、C从指标上看是不相似的)。
当然,这样传递下去很可能把整个词表都遍历了,所以要逐步加强对相似的限制。比如 A 是种子词,B、C 都不是种子词,A、B 的相似度为 0.6 就定义它为相似,B、C 的相似度要大于 0.7 才能认为它们相似,不然这样一级级地传递下去,后面的词就会离种子词的语义越来越远。
聚类算法如下:
import numpy as npfrom multiprocessing.dummy import Queue
def most_similar(word, center_vec=None, neg_vec=None): """根据给定词、中心向量和负向量找最相近的词 """ vec = word2vec[word] + center_vec - neg_vec return word2vec.similar_by_vector(vec, topn=200)
def find_words(start_words, center_words=None, neg_words=None, min_sim=0.6, max_sim=1., alpha=0.25): if center_words == None and neg_words == None: min_sim = max(min_sim, 0.6) center_vec, neg_vec = np.zeros([word_size]), np.zeros([word_size]) if center_words: # 中心向量是所有种子词向量的平均 _ = 0 for w in center_words: if w in word2vec.wv.vocab: center_vec += word2vec[w] _ += 1 if _ > 0: center_vec /= _ if neg_words: # 负向量是所有负种子词向量的平均(本文没有用到它) _ = 0 for w in neg_words: if w in word2vec.wv.vocab: neg_vec += word2vec[w] _ += 1 if _ > 0: neg_vec /= _ queue_count = 1 task_count = 0 cluster = [] queue = Queue() # 建立队列 for w in start_words: queue.put((0, w)) if w not in cluster: cluster.append(w) while not queue.empty(): idx, word = queue.get() queue_count -= 1 task_count += 1 sims = most_similar(word, center_vec, neg_vec) min_sim_ = min_sim + (max_sim-min_sim) * (1-np.exp(-alpha*idx)) if task_count % 10 == 0: log = '%s in cluster, %s in queue, %s tasks done, %s min_sim'%(len(cluster), queue_count, task_count, min_sim_) print log for i,j in sims: if j >= min_sim_: if i not in cluster and is_good(i): # is_good是人工写的过滤规则 queue.put((idx+1, i)) if i not in cluster and is_good(i): cluster.append(i) queue_count += 1 return cluster
规则过滤
总的来说,无监督算法始终是难以做到完美的,在工程上,常见的方法就是人工观察结果然后手写一些规则来处理。在这个任务中,由于前面是纯无监督的,哪怕进行了语义聚类,还是会出来一些非电力专业词汇(比如“麦克斯韦方程”),甚至还保留一些“非词”,所以我写了一通规则来过滤(写得有点丑):
def is_good(w): if re.findall(u'[\u4e00-\u9fa5]', w) \ and len(i) >= 2\ and not re.findall(u'[较很越增]|[多少大小长短高低好差]', w)\ and not u'的' in w\ and not u'了' in w\ and not u'这' in w\ and not u'那' in w\ and not u'到' in w\ and not w[-1] in u'为一人给内中后省市局院上所在有与及厂稿下厅部商者从奖出'\ and not w[0] in u'每各该个被其从与及当为'\ and not w[-2:] in [u'问题', u'市场', u'邮件', u'合约', u'假设', u'编号', u'预算', u'施加', u'战略', u'状况', u'工作', u'考核', u'评估', u'需求', u'沟通', u'阶段', u'账号', u'意识', u'价值', u'事故', u'竞争', u'交易', u'趋势', u'主任', u'价格', u'门户', u'治区', u'培养', u'职责', u'社会', u'主义', u'办法', u'干部', u'员会', u'商务', u'发展', u'原因', u'情况', u'国家', u'园区', u'伙伴', u'对手', u'目标', u'委员', u'人员', u'如下', u'况下', u'见图', u'全国', u'创新', u'共享', u'资讯', u'队伍', u'农村', u'贡献', u'争力', u'地区', u'客户', u'领域', u'查询', u'应用', u'可以', u'运营', u'成员', u'书记', u'附近', u'结果', u'经理', u'学位', u'经营', u'思想', u'监管', u'能力', u'责任', u'意见', u'精神', u'讲话', u'营销', u'业务', u'总裁', u'见表', u'电力', u'主编', u'作者', u'专辑', u'学报', u'创建', u'支持', u'资助', u'规划', u'计划', u'资金', u'代表', u'部门', u'版社', u'表明', u'证明', u'专家', u'教授', u'教师', u'基金', u'如图', u'位于', u'从事', u'公司', u'企业', u'专业', u'思路', u'集团', u'建设', u'管理', u'水平', u'领导', u'体系', u'政务', u'单位', u'部分', u'董事', u'院士', u'经济', u'意义', u'内部', u'项目', u'建设', u'服务', u'总部', u'管理', u'讨论', u'改进', u'文献']\ and not w[:2] in [u'考虑', u'图中', u'每个', u'出席', u'一个', u'随着', u'不会', u'本次', u'产生', u'查询', u'是否', u'作者']\ and not (u'博士' in w or u'硕士' in w or u'研究生' in w)\ and not (len(set(w)) == 1 and len(w) > 1)\ and not (w[0] in u'一二三四五六七八九十' and len(w) == 2)\ and re.findall(u'[^一七厂月二夕气产兰丫田洲户尹尸甲乙日卜几口工旧门目曰石闷匕勺]', w)\ and not u'进一步' in w: return True else: return False
至此,我们就可以完整地执行这个算法了:
# 种子词,在第一步得到的词表中的前面部分挑一挑即可,不需要特别准start_words = [u'电网', u'电压', u'直流', u'电力系统', u'变压器', u'电流', u'负荷', u'发电机', u'变电站', u'机组', u'母线', u'电容', u'放电', u'等效', u'节点', u'电机', u'故障', u'输电线路', u'波形', u'电感', u'导线', u'继电', u'输电', u'参数', u'无功', u'线路', u'仿真', u'功率', u'短路', u'控制器', u'谐波', u'励磁', u'电阻', u'模型', u'开关', u'绕组', u'电力', u'电厂', u'算法', u'供电', u'阻抗', u'调度', u'发电', u'场强', u'电源', u'负载', u'扰动', u'储能', u'电弧', u'配电', u'系数', u'雷电', u'输出', u'并联', u'回路', u'滤波器', u'电缆', u'分布式', u'故障诊断', u'充电', u'绝缘', u'接地', u'感应', u'额定', u'高压', u'相位', u'可靠性', u'数学模型', u'接线', u'稳态', u'误差', u'电场强度', u'电容器', u'电场', u'线圈', u'非线性', u'接入', u'模态', u'神经网络', u'频率', u'风速', u'小波', u'补偿', u'电路', u'曲线', u'峰值', u'容量', u'有效性', u'采样', u'信号', u'电极', u'实测', u'变电', u'间隙', u'模块', u'试验', u'滤波', u'量测', u'元件', u'最优', u'损耗', u'特性', u'谐振', u'带电', u'瞬时', u'阻尼', u'转速', u'优化', u'低压', u'系统', u'停电', u'选取', u'传感器', u'耦合', u'振荡', u'线性', u'信息系统', u'矩阵', u'可控', u'脉冲', u'控制', u'套管', u'监控', u'汽轮机', u'击穿', u'延时', u'联络线', u'矢量', u'整流', u'传输', u'检修', u'模拟', u'高频', u'测量', u'样本', u'高级工程师', u'变换', u'试样', u'试验研究', u'平均值', u'向量', u'特征值', u'导体', u'电晕', u'磁通', u'千伏', u'切换', u'响应', u'效率']
cluster_words = find_words(start_words, min_sim=0.6, alpha=0.35)
result2 = result[cluster_words].sort_values(ascending=False)idxs = [i for i in result2.index if is_good(i)]
pd.Series([i for i in idxs if len(i) > 2][:10000]).to_csv('result_1_2.csv', encoding='utf-8', header=None, index=None)
最终结果(部分):
变压器发电机变电站过电压可靠性控制器断路器分布式输电线路数学模型滤波器电容器故障诊断神经网络直流电压等离子体联络线传感器汽轮机晶闸管电动机约束条件数据库可行性持续时间整流器稳定性调节器电磁场
后记感想
本文的算法在榜上的成绩大约是 0.22 左右,封榜时排在 100 名左右,榜首已经是 0.49 了,所以从成绩来看其实没什么值得炫耀的。不过当时听说不少人拿现成的专业词典去做字标注,所以当时就没做下去了。要是真的那样子的话,我觉得就很没意思了。
总之,本文算是提供了一个无监督抽取专业词的实现模版,如果读者觉得有可取之处,大方取之即可;如果觉得一无是处,敬请无视它。
点击以下标题查看作者其他文章:
变分自编码器VAE:原来是这么一回事 | 附源码
变分自编码器VAE:这样做为什么能成?
简单修改,让GAN的判别器秒变编码器
深度学习中的互信息:无监督提取特征
全新视角:用变分推断统一理解生成模型
可逆ResNet:极致的暴力美学
深度学习中的Lipschitz约束:泛化与生成模型
#投 稿 通 道#
让你的论文被更多人看到
如何才能让更多的优质内容以更短路径到达读者群体,缩短读者寻找优质内容的成本呢? 答案就是:你不认识的人。
总有一些你不认识的人,知道你想知道的东西。PaperWeekly 或许可以成为一座桥梁,促使不同背景、不同方向的学者和学术灵感相互碰撞,迸发出更多的可能性。
PaperWeekly 鼓励高校实验室或个人,在我们的平台上分享各类优质内容,可以是最新论文解读,也可以是学习心得或技术干货。我们的目的只有一个,让知识真正流动起来。
? 来稿标准:
• 稿件确系个人原创作品,来稿需注明作者个人信息(姓名+学校/工作单位+学历/职位+研究方向)
• 如果文章并非首发,请在投稿时提醒并附上所有已发布链接
• PaperWeekly 默认每篇文章都是首发,均会添加“原创”标志
? 投稿邮箱:
• 投稿邮箱:hr@paperweekly.site
• 所有文章配图,请单独在附件中发送
• 请留下即时联系方式(微信或手机),以便我们在编辑发布时和作者沟通
?
现在,在「知乎」也能找到我们了
进入知乎首页搜索「PaperWeekly」
点击「关注」订阅我们的专栏吧
关于PaperWeekly
PaperWeekly 是一个推荐、解读、讨论、报道人工智能前沿论文成果的学术平台。如果你研究或从事 AI 领域,欢迎在公众号后台点击「交流群」,小助手将把你带入 PaperWeekly 的交流群里。
▽ 点击 | 阅读原文 | 查看作者博客
实战分享之专业领域词汇无监督挖掘相关推荐
- 目标检测YOLO实战应用案例100讲-无监督领域自适应目标检测方法研究与应用
目录 无监督领域自适应目标检测方法研究 领域自适应目标检测 目标检测相关技术介绍
- 实战分享:闲鱼无货源项目如何从0开始做到月收入过万
关于闲鱼这个平台大家肯定不陌生了,阿里巴巴旗下公司,二手物品交易平台,这是闲鱼给人最初的印象. 闲鱼在大多数人眼中只是一个二手交易平台,但是,如果换一个角度去看待的话,闲鱼还是一个很不错的卖货平台. ...
- 【CVPR智慧城市挑战赛】无监督交通异常检测,冠军团队技术分享
[新智元导读]"智能交通视频分析界的ImageNet竞赛"--英伟达城市挑战赛落下帷幕.新加坡松下研究院联合中科院自动化所,提出了一种双模态动静联合检测方案,在交通异常检测比赛中拔 ...
- ECCV18 | 无监督难分样本挖掘改进目标检测
(欢迎关注"我爱计算机视觉"公众号,一个有价值有深度的公众号~) 大量训练数据有助于目标检测系统性能的提升,对于已经训练好的系统而言,有研究发现,那些被系统误分类的少量" ...
- 【报告分享】2019移动互联网行业报告暨无监督机器学习下的2019行业价值人群聚类报告.pdf...
今天给大家分享的报告是TalkingData于2020年3月31日发布的<2019移动互联网行业报告暨无监督机器学习下的2019行业价值人群聚类报告.pdf>,报告包含如下四大部分: 1. ...
- 分享 | 无监督视觉目标跟踪
第一次在知乎写文章,想谈谈博士期间比较熟悉的视觉目标跟踪.过去每一年的这个时候都在忙碌的赶CVPR,今年突然闲下来,有点不适.工作之余,写点文章当作是怀念科研的时光.步入正题,谈谈最近在CVPR202 ...
- bert获得词向量_无监督语义相似度匹配之Bert抽取文本特征实战
今天记一次采用bert抽取句子向量的实战过程,主要是想感受一下bert抽取出来的句子特征向量是否真的具有不错的语义表达. 在此之前,我们来回顾一下,如果我们想拿到一个句子的特征向量可以采用什么样的方式 ...
- NLP热门词汇解读:预训练、Transformer、无监督机器翻译
Transformer Transformer在2017年由Google在题为<Attention Is All You Need>的论文中提出.Transformer是一个完全基于注意力 ...
- CLD: 通过挖掘实例与聚类间关系进行无监督特征学习
Unsupervised Feature Learning by Cross-Level Instance-Group Discrimination 作者:Xudong Wang (加州大学伯克利分校 ...
最新文章
- 【MATLAB】数据分析之多项式及其函数
- telegraf监控mysql数据库_influxdb+grafana+telegraf 监听性能数据 (完整详细版)
- SQLite的事务处理方式
- 面试:Handler 的工作原理是怎样的?
- 计算机软件记不住设置,想知道电脑密码记不住了怎么办
- 关于 m1 xcode12 编译报错 this target. for architecture arm64等问题解决方案
- How to find error message from OMS repository
- Mybatis插件机制原理
- 使用Axure创建iPhone应用程序原型(二)
- 【Pix4d精品教程】Pix4d模型成果导出OSGB并加载OSGB到EPS进行三维测图完美案例教程
- win10无线断开无法连接服务器,win10wifi自动断开什么原因_win10wifi自动断开且无法连接如何解决...
- Python多项逻辑回归用LogisticRegression识别英文字母数据集letter-recognition.data
- Flutter Sliver滚动组件
- 单细胞测序之scater包数据分析教程复现
- 如何用七牛云上传音乐生成外链
- 回帖送大奖 『和AI在一起』
- python在一个函数中调用另一函数中的变量
- Vmware16安装(详细)
- JavaScript利用回调函数完成次序循环打印“红黄绿”灯
- Adlik Deer版本发布,模型推理加速就靠它啦
热门文章
- 提领指向不完全类型的指针_望远镜不完全指南:望远镜原理、类型和配件
- mysql.connector写了一个简单的mysql操作类:
- WCF服务支持HTTP(get,post)方式请求例子
- ASP.NET没有魔法——ASP.NET MVC 与数据库之MySQLEF
- Static Final用法
- 在线音乐网站Pandora申请IPO融1亿美元
- 用平常心去对待不平常的事
- C#验证 中国 身份证 代码
- 鸿蒙os终于开始大升级,华为鸿蒙OS终于要迎来大规模推送升级了
- linux的write是线程安全的吗,socket的write/send还是是否是线程安全?