幾百個作者有相同的名字?| 智源-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]

點「在看」的人都變好看了哦!