几百个作者有相同的名字?| 智源-AMiner大赛,从EDA到冠军baseline

  • 2019 年 11 月 14 日
  • 笔记

大数据文摘出品

2019年10月,智源-AMiner 北京智源人工智能研究院和AMiner联合发布了一个大规模姓名排歧数据集OAG – WhoIsWho,这是目前为止发布的人工标注数据规模最大的姓名消歧数据集。

依托数据集,智源和AMiner联合发布了一项奖金为10万元的比赛。目前,比赛仍在进行中。我们邀请了一些参赛选手对数据集进行了一些有趣的探索,另外还邀请了AMiner官方和往届比赛获奖选手提供了两个baseline。EDA和baseline的代码和结果都可以到比赛页面的“Models”栏目查看。

相关链接:

https://biendata.com/competition/aminer2019/

本次比赛部分选手的EDA和baseline代码

在外文期刊数据库中,同一姓名简称代表多位作者的现象十分普遍,严重影响作者检索的精度,所以在此查看论文作者的重名、缩写名、别名等信息。发现在训练集中作者同名数量为221,平均每个同名作者们的论文数在1000左右。同样的在测试集中,同名作者数量为50,其所涉及的平均论文数量是917.96。

authors = [author for author in train_data]authors_num_person = [len(train_data[author].keys()) for author in train_data]print('训练集同名数量:', len(authors))print('消歧后实际作者数量:',  sum(authors_num_person))  # 以绘制训练集同名作者个体数量为例plt.figure(figsize=(40, 8), dpi=80)x = range(len(authors))  plt.bar(x, authors_num_person, width=0.5)plt.xticks(x, authors)plt.xticks(rotation=270)plt.xlabel('训练集同名作者')plt.ylabel('该名字同名作者数量(个)')for xl, yl in zip(x, authors_num_person):    plt.text(xl, yl+0.3, str(yl), ha='center', va='bottom', fontsize=10.5)  mean_person = int(np.mean(authors_num_person))plt.gca().hlines(mean_person,-1,225,linestyles='--',colors='red',label='平均值')plt.annotate(u"平均值:" + str(mean_person), xy = (225, mean_person), xytext = (225, mean_person+40),arrowprops=dict(facecolor='red',shrink=0.1,width=2))
训练集同名数量:221消歧后实际作者数量:22839涉及的论文总数(篇):205498

查看几条重名作者的信息后,我们可以发现,论文作者名字存在不一致的情况主要源于名字大小写问题、姓和名顺序不一致、名字带有下划线或横线、名字是否简写、以及名字是否分开写,例如:

paper id: zszavvJhpaper author name:  feifei chengpaper author name:  heng lipaper author name:  y w wangpaper author name:  martin skitmorepaper author name:  p j forsythebr

来源:赛道一,朱丽

同理,机构的表达也可能存在不一致的情况,因此需要对数据做相应的预处理统一表达之后,再具体查看某一作者的论文作者名中是否包含消歧作者名。实际情况中,一个作者可能有多个机构,一个机构有很多种表述方式,一些特殊姓氏可能都集中在一个国家(比如日本),同一个期刊可能同时存在简称和全称等等消歧情况,所以在此查看机构、协作作者、协作机构、常用关键词、发表的会议期刊是否有交集。发现有交集,所以在用基于规则的方式处理时需要注意。

# 查看机构、协作作者、协作机构、常用关键词、发表的会议期刊是否有交集for aid1 in author_data:    for aid2 in author_data:        if aid1 != aid2:            if set(org[aid1]).intersection(set(org[aid2])):                print('%s与%s机构重叠:' % (aid1, aid2), set(org[aid1]).intersection(set(org[aid2])))            if set(co_author[aid1]).intersection(set(co_author[aid2])):                print('%s与%s协作者重叠:' % (aid1, aid2), set(co_author[aid1]).intersection(set(co_author[aid2])))            if set(co_org[aid1]).intersection(set(co_org[aid2])):                print('%s与%s协作机构重叠:' % (aid1, aid2), set(co_org[aid1]).intersection(set(co_org[aid2])))            if set(keywords[aid1]).intersection(set(keywords[aid2])):                print('%s与%s关键词重叠:' % (aid1, aid2), set(keywords[aid1]).intersection(set(keywords[aid2])))            if set(venue[aid1]).intersection(set(venue[aid2])):                print('%s与%s会议期刊重叠:' % (aid1, aid2), set(venue[aid1]).intersection(set(venue[aid2])))br
bXCEdRdj与WSFIcbxu关键词重叠: {'chemical composition'}bXCEdRdj与WSFIcbxu会议期刊重叠: {'Journal of Agricultural and Food Chemistry'}bXCEdRdj与gUSOTB2u会议期刊重叠: {'Journal of home economics'}OaaWMLWs与5Bxjg2tr协作者重叠: {'Shoei Sato'}OaaWMLWs与5Bxjg2tr会议期刊重叠: {'APSIPA'}WSFIcbxu与bXCEdRdj关键词重叠: {'chemical composition'}WSFIcbxu与bXCEdRdj会议期刊重叠: {'Journal of Agricultural and Food Chemistry'}CsE5vsJA与JvJ9opoq协作者重叠: {'Hiroki Sakaji'}gUSOTB2u与bXCEdRdj会议期刊重叠: {'Journal of home economics'}5Bxjg2tr与OaaWMLWs协作者重叠: {'Shoei Sato'}5Bxjg2tr与OaaWMLWs会议期刊重叠: {'APSIPA'}JvJ9opoq与CsE5vsJA协作者重叠: {'Hiroki Sakaji'}br

一个作者的协作者、所发的会议期刊、关键词都有可能重叠,在使用相关规则需要谨慎。

来源:赛道一,桑运鑫

那么我们在使用规则处理时,就可以采用预处理机构的简写替换,以及使用正则表达式去除特殊的无意义标点符号或连接符号。例如:

#正则去标点def etl(content):    content = re.sub("[s+.!/,;$%^*(+"')]+|[+——()?【】“”!,。?、~@#¥%……&*()]+", " ", content)    content = re.sub(r" {2,}", " ", content)    return content  def get_org(co_authors, author_name):    for au in co_authors:        name = precessname(au['name'])        name = name.split('_')        if ('_'.join(name) == author_name or '_'.join(name[::-1]) == author_name) and 'org' in au:            return au['org']    return ''

来源:赛道一,朱丽

此外,一个作者,一段时间内应该是在一个单位工作的,我们可以根据作者的工作单位变动信息来为作者构建一个时间段映射到工作单位的表,在给出新论文时,用论文年份和作者工作单位进行辅助筛选。为此引入年份和工作单位,我们统计一下作者工作单位变化情况。发现共计262388份论文,其中无年份或者年份错误的占比很少,只有698份论文没有年份信息,所以绝大部分数据是有效的,可以利用这个特征。

# 统计论文的年份范围min_year = 3000max_year = 0pubs_no_year = 0for each in tqdm(author_pub.items()):    try:        year = int(each[1]['year'])    except:        pubs_no_year += 1        print("Paper {} has no year info".format(each[0]))        continue    if year<1500 or year>2100:        pubs_no_year +=1        print("Paper {} has wrong year info: {}".format(each[0], year))        continue    if year<min_year:        min_year = year    if year>max_year:        max_year = yearprint(min_year, max_year)print("共计{}份论文没有年份信息".format(pubs_no_year))

来源:赛道二,尹恒

关于同名作者数量分布,经探索发现数量大都在 [2,30] 之间, 也有部分名字重名极多在 [200,400] 之间。

import seaborn as snsimport matplotlib.pyplot as pltsns.distplot(same_author_num,30,hist_kws={"rwidth":0.0001,'edgecolor':'black', 'alpha':1.0})br
sns.distplot(same_author_num,300,             hist_kws=dict(cumulative=True),             kde_kws=dict(cumulative=True))br
sns.distplot(same_author_num,3000,             hist_kws=dict(cumulative=True),             kde_kws=dict(cumulative=True))plt.xlim(0,100)br
sns.distplot(thesis_percent,30,hist_kws={"rwidth":0.001,'edgecolor':'black', 'alpha':1.0})br
sns.distplot(thesis_percent,300,             hist_kws=dict(cumulative=True),             kde_kws=dict(cumulative=True))br
for name in train_author.keys()[15:20]:    f, ax = plt.subplots(figsize=(8, 6))    plt.plot([len(train_author[name][author])for author in train_author[name].keys()])br

同名作者的发文数量和时间段也有迹可循,大部分作者都有持续发表论文,越早发表第一篇论文的作者更有可能发表更多的论文,这可能和年龄有关。并且之后发表论文的速度越来越快。

# 同名中各个作者发布论文区间count=0for name in train_author.keys()[15:20]:    f, ax = plt.subplots(figsize=(8, 6))    authors = train_author[name].keys()    for author in authors:        years=[]        for thesis in train_author[name][author]:            if 'year' in train_pub[thesis].keys():                years.append(train_pub[thesis]['year'])        plt.plot(np.sort(years))    plt.ylim(1990,2020)    if count==3:        print(name)    count+=1br

来源:赛道一,林志豪

无监督聚类DBSCAN(根据合作者和机构TFIDF进行相似度聚类)

for author in validate_data:      # print(author)    coauther_orgs = []    papers = validate_data[author]    if len(papers) == 0:        res_dict[author] = []        continue    # print(len(papers))    paper_dict = {}    for paper in papers:        authors = paper['authors']        names = [precessname(paper_author['name']) for paper_author in authors]        orgs = [preprocessorg(paper_author['org']) for paper_author in authors if 'org' in paper_author]        abstract = paper["abstract"] if 'abstract' in paper else ''        coauther_orgs.append(etl(' '.join(names + orgs) + ' '+ abstract))    tfidf = TfidfVectorizer().fit_transform(coauther_orgs)        clf = DBSCAN(metric='cosine')    s = clf.fit_predict(tfidf)    # 每个样本所属的簇    for label, paper in zip(clf.labels_, papers):        if str(label) not in paper_dict:            paper_dict[str(label)] = [paper['id']]        else:            paper_dict[str(label)].append(paper['id'])    res_dict[author] = list(paper_dict.values())      tfidf = PCA(n_components=2, random_state=0).fit_transform(tfidf.toarray())

无监督聚类AffinityClustering(根据合作者和机构TFIDF进行相似度聚类)。

由于该算法运行效率问题,只对最后一名作者的聚类结果进行了可视化。

res_dict = {}t0 = time()for author in validate_data:    # print(author)    coauther_orgs = []    papers = validate_data[author]    if len(papers) == 0:        res_dict[author] = []        continue    # print(len(papers))    paper_dict = {}    for paper in papers:        authors = paper['authors']        names = [precessname(paper_author['name']) for paper_author in authors]        orgs = [preprocessorg(paper_author['org']) for paper_author in authors if 'org' in paper_author]        abstract = paper["abstract"] if 'abstract' in paper else ''        coauther_orgs.append(etl(' '.join(names + orgs) + ' '+ abstract))    tfidf = TfidfVectorizer().fit_transform(coauther_orgs)      # affinity_clustering,参数可以调整,此处进攻参考,未提交测试    clf = cluster.AffinityPropagation(damping=.9, preference=-20)    s = clf.fit_predict(tfidf)    # 每个样本所属的簇    for label, paper in zip(clf.labels_, papers):        if str(label) not in paper_dict:            paper_dict[str(label)] = [paper['id']]        else:            paper_dict[str(label)].append(paper['id'])    res_dict[author] = list(paper_dict.values())  t1 = time()print('running time: %.2fs'% (t1 - t0))  # 降维tfidf = PCA(n_components=2, random_state=0).fit_transform(tfidf.toarray())

来源:赛道一,朱丽

最后,AMiner官方和往届比赛获奖选手分别为两个赛道提供了baseline代码供大家参考:

赛道一:

申发海,重庆邮电大学计算机硕士,研究方向涉及计算机视觉,机器学习,深度学习,曾获CCIR2019基于电子病历的数据查询类问答大赛第一名,2018开放学术数据挖掘大赛第二名,搜狐图文匹配算法大赛三等奖等。

相关链接:

https://biendata.com/models/category/3000/L_notebook/

赛道二:

陈波,中国人民大学信息学院计算机科学与技术系学术型研究生,主要研究方向为数据集成,知识图谱及社交网络相关研究。目前致力于学术网络中的实体消歧与跨语言知识图谱对齐等研究。

相关链接:

https://biendata.com/models/category/2998/L_notebook/

实习/全职编辑记者招聘ing

加入我们,亲身体验一家专业科技媒体采写的每个细节,在最有前景的行业,和一群遍布全球最优秀的人一起成长。坐标北京·清华东门,在大数据文摘主页对话页回复“招聘”了解详情。简历请直接发送至[email protected]

点“在看”的人都变好看了哦!