DBLP( Digital Bibliography and Library Project )是一個計算機類英文文獻的集成數據庫系統。DBLP所收錄的論文質量較高, 文獻更新速度很快, 很好地反應了國際學術研究的前沿方向。DBLP數據可以為人們提供大量有用的知識, 通過對DBLP數據的分析, 可以找到權威作者。對權威作家的分析, 可以挖掘出計算機研究的新領域。
作者合著關系屬於社會網絡范疇, 目的是研究合著論文的作者間的關系。通過對這種關系的研究,可以使人們了解科學協作的結構, 即協作以何種方式組織的; 了解研究者在科學研究中所處的位置; 還可以應用到多種會議上, 使人們了解在某一特定會議上發表論文的作者間的關系。
通過對DBLP數據的處理,找到DBLP上作者間協作的關系,輸出合作次數較多的作者合著關聯規則。具體按以下三個方面展開:
1.DBLP數據預處理
從DBLP網站:http://dblp.uni-trier.de/xml/得到DBLP XML記錄。研究分析XML文件的內容和特點,選擇適合的解析方法得到作者數據集。
同時,可根據實驗要求與數據特點對數據集進行適當的篩選,以達到進一步壓縮數據的目的。
2.實現格式轉化
將解析得到的數據集(一般為csv格式文件)通過weka或者其他編輯器加入頭部定義,轉化為weka專用的文件格式arff。
3.挖掘關聯規則
將arff文件導入到weka中,選用關聯規則並設定好各參數的值挖掘頻繁項並按作者合著關系的次數由大到小輸出關聯規則。
原理:
1.關聯規則
關聯規則概念首先由R. AgrawaI 等於1993 年提出。所謂關聯規則,是指客體之間的相互關系。關聯規則形如:A1∩A2∩Ai->B1∩B2∩⋯∩Bj,(4%,70%)意味着目標數據中客體B1, B2, ⋯, Bj 傾向於同客體A1,A2,···,Ai
一起出現,其中4%為關聯規則的支持度,70%為關聯規則的信任度。
2.Apriori算法
Apriori 算法采用的是迭代方法,需要多遍掃描事務數據庫, 為了提高頻繁項目集的產生效率,可利用一個重要的性質來減少項目搜索空間。Apriori 性質就是規定一個頻繁項目集的所有非空子集必需也是頻繁項目集。根據這一性質,進行第 遍掃描之前,可先產生候選集C , C 可以分兩步來產生,設前一步(第 k-1)步已生成(k-1)-頻繁集Lk-1,則首先可以通過對Lk -1中的成員進行聯接來產生候選,Lk-1 中的兩個成員必需滿足在兩個成員項目中有k-2個項目是相同的這個條件方可聯接,即:C = Lk-1ΘLk-1 = { AΘB|A, BcLk-1, |A∩B|=k-2 }
接着,再從C 中刪除所有包含不是頻繁的( k-1)-子集的成員項目集即可。
3.矩陣交集算法
關聯規則挖掘的難點主要在挖掘頻繁項目集,由於其面對的是海量數據,其理論上的搜索空間是2i,該算法存在“項集生成瓶頸”問題,目前,Apriori關聯規則優化算法也是針對這個問題提出的.
由於關聯規則算法存在上述問題,因此,我們在實驗過程中參考一篇學術論文采用了新的關聯規則挖掘算法—矩陣交集算法.算法步驟如下:
(1) 產生數據庫D':遍歷數據庫D,篩選出所有大於min_sup的項目,並產生數據庫D'(在本實驗中表現為在原數據集中將出現次數小於min_up的作者刪掉),同時列出在數據庫D'中候選項的集合記做ak (2<k<m),所有的頻繁1-項集都包含在ak中.
(2) 轉換數據形式生成矩陣:由ak(D'中候選項的集合)產生k個列,按TID(人物標識)包含的項目由多到少的規律排列,由行計數器sr 統計每個交易行中項目集合數,由列計數器cr 為列中相同的項目計數,為每個ak 集合中的項
目賦值(0,1),有則賦1,無為0.掃描數據庫為每個ak 計數,生成新數據庫包含T(t1 ~tn ),並按照交易項數ak 的計數從大到小排列.
(3) 產生交集:由sr 和cr 產生最大項目集和次項目集n個,求其交集t1∩t3,t1∩t4,⋯,t1∩tn 找出最大頻繁項集.其可信度由sr 最大項集中的項同時滿足cr 較大值來驗證.算法應用過程舉例如下:
① 取min_up=50%=2,
數據庫D
TID |
Items |
100 |
a,c,d,f,n |
200 |
b,c,d,e,f,i,k |
300 |
d,e,f,g,m |
400 |
b,f,p,s |
500 |
c,d,f,s |
600 |
a,b,c,e,h,o |
數據庫D’
TID |
Items |
100 |
a,c,d,f |
200 |
b,c,d,e,f |
300 |
d,e,f,g,m |
400 |
b,f,p,s |
500 |
c,d,f,s |
600 |
a,b,c,e,h,o |
② 生成矩陣
TID |
a |
b |
c |
d |
e |
f |
sr |
100 |
1 |
|
1 |
1 |
|
1 |
|
200 |
|
1 |
1 |
1 |
1 |
1 |
|
300 |
|
|
|
1 |
1 |
1 |
|
400 |
|
1 |
|
|
|
1 |
|
500 |
|
|
1 |
1 |
|
1 |
|
600 |
1 |
1 |
1 |
|
1 |
|
|
cr |
|
|
|
|
|
|
|
③計數篩選
TID |
a |
b |
c |
d |
e |
f |
Sr |
200 |
1 |
|
1 |
1 |
|
1 |
5 |
100 |
|
1 |
1 |
1 |
1 |
1 |
4 |
600 |
|
|
|
1 |
1 |
1 |
4 |
300 |
|
1 |
|
|
|
1 |
3 |
500 |
|
|
1 |
1 |
|
1 |
3 |
400 |
1 |
1 |
1 |
|
1 |
|
2 |
cr |
2 |
3 |
4 |
4 |
3 |
5 |
|
產生項集的最大集合和次集合T1、T2 、T3,求其互相的交集:
T1∩T2={b,c,d,e,f}∩{a,c,d,f} ={c,d,f},
T1∩T3={b,c,d,e,f}∩{a,b,c,e} ={b,c,e},
根據cr值和關聯規則的性質刪除{b,c,e}從而產生最大頻繁項集{f,c,d}.
實現:
4.1 過程詳解
1. 從DBLP官網(http://dblp.uni-trier.de/xml/)下載得到原始數據文件dblp.xml。使用vi打開:
2. 分析xml文件的標簽,得知作者名在<author>和</author>之間,我們現在只提取article的作者名,主要C/C++代碼如下:

1 int dblp2csv() 2 { 3 ofstream outfile("dblp.csv") ; 4 ifstream infile("dblp.xml") ; 5 6 string line ; 7 8 for(; getline(infile,line) ;) 9 { 10 if(line.substr(0,8) == "<article") 11 { 12 for(int count = 0 ; getline(infile,line);) 13 { 14 if(line.substr(0,10) == "</article>") 15 { 16 outfile << '\n' ; 17 break ; 18 } 19 if(line.substr(0,8) == "<author>") 20 { 21 if(count != 0) 22 outfile << ',' ; 23 for(string::size_type pos = 8 ; pos != line.size() ; ++pos ) 24 { 25 if(line[pos] == '<') 26 { 27 if(line.substr(pos,9) == "</author>") 28 { 29 count += 1 ; 30 break ; 31 } 32 } 33 else 34 outfile << line[pos] ; 35 } 36 } 37 } 38 } 39 } 40 41 outfile.close(); 42 infile.close(); 43 return 0 ; 44 }
3. 提取作者名的文件dblp.csv:
4. 試圖將dblp.csv文件導入到weka時,發現格式不對。
分析:少了第一行屬性值,以及每一行屬性對應的值如果缺失則需要用缺失值(在arff格式中用‘?’表示)表示,所以在csv文件中每一行沒有達到最大屬性值個數的需要用逗號隔開,以表示這是缺失值,並非不存在屬性值。
因此將dblp.csv文件稍作修改,主要C/C++代碼如下:

1 int dblp_mod() 2 { 3 ofstream outfile("dblp_new.csv") ; 4 ifstream infile("dblp.csv") ; 5 6 int max_au = 0 ; 7 string line ; 8 9 for(;getline(infile , line);) 10 { 11 if(line == "") 12 continue ; 13 int count = 1 ; 14 for(string::size_type i = 0 ; i != line.size() ; ++i) 15 { 16 if(line[i] == ',') 17 count += 1 ; 18 } 19 if(max_au < count) 20 max_au = count ; 21 } 22 int i = 0 ; 23 for( ; i != max_au ; ++i) 24 { 25 outfile << "auth" << i << ',' ; 26 } 27 outfile << "auth" << i << '\n' ; 28 29 infile.clear(); 30 infile.seekg(0); 31 for( ; getline(infile , line) ; ) 32 { 33 if(line == "") 34 continue ; 35 for(string::size_type n = 0 ; n != (line.size()-1) ; ++n) 36 { 37 outfile << line[n] ; 38 } 39 int count = 0 ; 40 for(string::size_type j = 0 ; j != line.size() ; ++j) 41 { 42 if(line[j] == ',') 43 count += 1 ; 44 } 45 for(int duf = 0 ; duf != (max_au - count - 1) ; ++duf) 46 { 47 outfile << ',' ; 48 } 49 outfile << '\n' ; 50 } 51 infile.close(); 52 outfile.close(); 53 return 0 ; 54 }
5. 修改后的文件dblp_new.csv:
分析:weka中對某些特殊字符不支持,比如說單引號,雙引號等,需要把前一步得到的文件中的特殊符號替換成不會出錯的符號,比如*。
6. 目前產生的文件有160M左右,weka讀這么大小的文件需要2G以上的內存,硬件成了主要瓶頸。
分析:硬件沒辦法改變,需要找到其他的解決辦法,辦法之一是將數據壓縮。由於本實驗的目的是找出作者之間的強關聯規則,對具體作者的名字的值沒有要求,而目前文件中作者名字基本都是比較長的字符串,所以,字典壓縮是我們的首選,並且為了盡可能的減少字符的字數,我們采用62進制(0,1,...9,a,b,...,z,A,B,...,Z),主要C/C++代碼如下:

1 int generate_index() 2 { 3 ifstream infile("dblp_new_1019.csv"); 4 ofstream outfile1("dblp_index.csv"); 5 ofstream outfile2("dblp_new_index.csv"); 6 7 string line , temp ; 8 string *index = new string[10000000]; 9 int count = 0 , 10 i = 0 , 11 n = 0 ; 12 13 getline(infile,line); 14 outfile2 << line << '\n'; 15 for(; getline(infile,line) ;) 16 { 17 if(line == "") 18 continue ; 19 for(string::size_type j = 0 ; j != line.size() ; ++j) 20 { 21 if(line[j] != ',') 22 { 23 temp += line[j] ; 24 if(j != (line.size()-1)) 25 continue ; 26 else 27 { 28 for(i = count-1 ; i >= 0 ; --i) 29 { 30 if(temp == index[i]) 31 { 32 outfile2 << ten_to_thrtw(i) << '\n' ; 33 break ; 34 } 35 } 36 if(i < 0) 37 { 38 index[count] = temp ; 39 outfile1 << ten_to_thrtw(count) << ',' << index[count] << '\n'; 40 outfile2 << ten_to_thrtw(count) << '\n' ; 41 ++count; 42 } 43 n = 0 ; 44 temp = ""; 45 } 46 } 47 else if(line[j] == ',') 48 { 49 if(temp == "") 50 { 51 outfile2 << line.substr(j,line.size()-j) << '\n' ; 52 break ; 53 } 54 else 55 { 56 for(i = count-1 ; i >= 0 ; --i) 57 { 58 if(temp == index[i]) 59 { 60 if(j == (line.size()-1)) 61 { 62 outfile2 << ten_to_thrtw(i) << line[j] << '\n' ; 63 } 64 else 65 { 66 outfile2 << ten_to_thrtw(i) << line[j] ; 67 } 68 break ; 69 } 70 } 71 if(i < 0) 72 { 73 index[count] = temp ; 74 outfile1 << ten_to_thrtw(count) << ',' << index[count] << '\n'; 75 if(j == (line.size()-1)) 76 { 77 outfile2 << ten_to_thrtw(count) << line[j] << '\n' ; 78 } 79 else 80 { 81 outfile2 << ten_to_thrtw(count) << line[j] ; 82 } 83 ++count ; 84 } 85 n = 0 ; 86 temp = ""; 87 } 88 } 89 } 90 } 91 92 delete[] index; 93 infile.close(); 94 outfile1.close(); 95 outfile2.close(); 96 return 0 ; 97 } 98 99 100 string ten_to_thrtw(int x) 101 { 102 int m , n ; 103 string obj ; 104 105 for(n = x+1 ; n ; n /= 62) 106 { 107 m = n%62 ; 108 if(m >= 10) 109 { 110 if(m >= 36) 111 obj.push_back('A' + (m-36)); 112 else 113 obj.push_back('a'+(m-10)); 114 } 115 else 116 obj.push_back('0' + m) ; 117 } 118 reverse(obj.begin(),obj.end()); 119 return obj ; 120 }
6. 壓縮后的文件dblp_new_index.csv:
8.下圖是字典文件dblp_index.csv:
9. 從結果來看,壓縮比的方案不可行,實際的壓縮比令我們非常失望。
①分析:dblp_new.csv文件中逗號占了絕大多數,並且由於作者人數過大,大多數作者名也需要用三位乃至四位字符表示,而主要原因還是缺失值太多,而這些由於缺失值產生的逗號無法壓縮,最終導致了壓縮比不令人滿意的結果。
②稀疏格式:經過查閱資料,我們發現了arff格式有一種叫做“稀疏格式”的表示方法。有的時候數據集中含有大量的0值(比如購物籃分析),這個時候用稀疏格式的數據存貯更加省空間。
假設有數據:
@data
0, X, 0, Y, "class A"
0, 0, W, 0, "class B"
用稀疏格式表達的話就是
@data
{1 X, 3 Y, 4 "class A"}
{2 W, 4 "class B"}
4.2 問題的提出
①問題1:稀疏數據只是針對有大量0的情況下,我們現在的缺失值,也就是空值,如何將問題轉換?
②問題2:weka所采用的apriori算法與教材上的算法略有不同,簡單的說,weka的apriori算法所得出的強關聯規則是屬性之間的關聯,而不是具體屬性值的關聯。為了說明這個問題,我們做一下測試:
a.假設有以下作者(6人),每條記錄表示參與一篇文章寫作的作者名;
b.我們使用weka的apriori算法對這些坐着進行關聯規則的挖掘。將支持度設置為50%,也就是在以上數據集中存在3條支持項即可滿足關聯;
c.結果標明L(2)共有2個關聯,即Jack、Tom之間存在合作關系,Judy、Jack之間存在合作關系,但實際上Tom、Jack、Lucy之間也符合支持度3的條件。所以weka的apriori算法其實是挖掘屬性之間的關聯,而不是具體屬性值的關聯,從上述例子可以很好的看到這一點,即實際是name1、name2、name3、name4之間的關聯。
4.3 解決方案
由於存在以上兩個問題,原始的數據格式已經無法達成實驗預期的目標,因此,我們引入矩陣交集算法思想和垂直數據格式的表示方法。其原理見“實驗原理”。其中矩陣交集算法我們只借鑒他的思想,算法實現仍然使用apriori算法。我們的做法是,在不考慮內存問題的情況下,我們將屬性設置為所有可能出現的作者名(實際是經過62進制壓縮后的標識),故屬性個數會達到一百多萬個,一條記錄為一篇文章,在參與本篇文章寫作的對應作者屬性那欄置‘1’,其余置為‘0’。使用weka的apriori算法求強關聯規則,我們只需關注均為‘1’的關聯,忽略0 - 0 ,1 - 0 ,0 - 1 這樣的可能。
1. 將數據轉換成稀疏表示的垂直數據格式的C/C++主要代碼如下:

1 int dblp_end() 2 { 3 ifstream infile1("case_auth.csv" ); 4 ifstream infile2("case9.txt" ); 5 ofstream outfile("dblp_end.csv" ); 6 string *index = new string[NUMOFAUT], 7 *author = new string[120]; 8 string line , temp = ""; 9 int count , n; 10 for(int i = 0 ; i != NUMOFAUT ; ++i) 11 { 12 getline(infile1 , line); 13 index[i] = line ; 14 } 15 outfile << "@relation dblp" << '\n'; 16 for(int i = 0 ; i != NUMOFAUT ; ++i) 17 { 18 outfile << "@attribute " << index[i] << " " << "real" << '\n' ; 19 } 20 infile2.clear(); 21 infile2.seekg(0); 22 outfile << "@data" << '\n'; 23 getline(infile2 , line); 24 for(;getline(infile2,line);) 25 { 26 if(line == "") 27 continue ; 28 n = 0 ; 29 author[0] = ""; 30 for(string::size_type pos = 0 ; pos != line.size() ; ++pos) 31 { 32 if(line[pos] != ',') 33 { 34 author[n] += line[pos]; 35 } 36 else 37 { 38 if(author[n] == "") 39 break ; 40 author[++n] = "" ; 41 } 42 } 43 outfile << '\173' ; 44 count = 0 ; 45 for(int i = 0 ; i != NUMOFAUT ; ++i) 46 { 47 for(n = 0 ; author[n] != "" ; ++n) 48 { 49 if(index[i] == author[n]) 50 { 51 if((count++) != 0) 52 { 53 outfile << ',' ; 54 } 55 outfile << i << " " << 1; 56 break; 57 } 58 } 59 } 60 outfile << '\175' << '\n'; 61 } 62 63 infile1.close(); 64 infile2.close(); 65 outfile.close(); 66 return 0 ; 67 }
2. 轉換后的數據:
(屬性部分)
(數據部分)
3. 將數據導入到weka。由於垂直數據格式本身的缺點(對內存和CPU的要求高),再者實際數據屬性(即出現的作者數)達到一百多萬個,因此單台PC難以承擔起這個代價,無法通過weka使用apriori算法對這樣一個數據集進行處理。
稀疏格式分析:用稀疏格式保存在磁盤上的文件能夠有效減少磁盤空間的占有量,但是通過weka處理這些數據時需要先“解壓”這些數據,因此對於內存來說,“稀疏”的數據與“不稀疏”的數據沒什么差別。
結果分析
由於數據量過於龐大,尤其是稀疏數據集的屬性由於為所有出現的作者,因此屬性多達一百多萬個,用weka導入稀疏數據集一直報錯內存不足。由於時間過於緊迫,因此我們放棄了通過weka來挖掘作者間的兩兩合作關系,而通過直接通過數據庫操作對感興趣的作者合著關系進行挖掘。
初步處理的文件大小為500M,weka無法處理,因而考慮到合作者信息故將所有的單獨出現的作者全部刪除,這部分的數據不影響最終的結果。處理完成后,數據庫中的作者信息並未出現較大的變動,此時考慮對數據進一步的提取。
根據對較大數據集的挖掘規則,可將本數據集中出現較少次數的作者不納入下一步的考慮范圍,此時對數據庫的數據進一步提取,將小於110的作者全部刪除,這個值是在綜合文件大小和數據庫內數據出現次數得到的。通過以下程序,實現了對作者數據集屬性間關聯規則的挖掘以及排序統計過程。
圖5.1 挖掘作者數據集的屬性間關聯規則
圖5.2 對挖掘結果(合著者與次數)進行排序統計
由以上程序可以得到一個完整的合作次數排序文件,下圖給出最常合作的幾個作者信息(詳細結果見附件里csv文件):