简单的社交网络分析(基于R)
原文鏈接:http://cos.name/2011/04/exploring-renren-social-network/#comment-2281
最近四五年間,互聯網行業似乎總是繞不開社交網絡這個概念。無論是旗艦級別的傳說中的facebook、LinkedIn,還是如雨后春筍般冒出來的各種團購和微博網站,全都或多或少地體現著SNS(社會網絡服務)的特色。這些五花八門的產品,在豐富我們業余生活的同時,也為研究者提供了大量珍貴的數據。以往只能依靠有限的調研或模擬才能進行的社會網絡分析(SNA),現在具備了大規模開展和實施的條件。國內著名而典型的SNS網站“人人網”,最近依靠上市新聞重新贏得了大家的關注。本文基于人人網的好友關系數據,應用統計分析軟件R做了社會網絡分析的一些嘗試。
注:網絡邊界的確定,是社會網絡分析的關鍵而困難的步驟。由于數據獲取的限制,本文分析的對象限制于我的好友。也就是說,本文分析的網絡是我自己的好友圈子,讀者看了這些分析結果或許會覺得索然無味,感興趣的同學可以分析一下自己的社交網絡,看看是否會有類似的結果。
2011-06-20 增加了新的代碼在附件中,可以直接獲取“共同好友”。如果只需要分析好友的群組關系(而忽略并無技術含量的好友推薦功能),可以直接運行這段代碼,大幅度提高效率,幾分鐘就能搞定,同時繞過好友同名的問題。歡迎試用,如需修改參數麻煩自行操作。=”=
2011-12-15 修改了正文的腳本,修正了數據讀取的代碼中的一處錯誤。
一、讀取數據
之所以選擇人人網作為分析的對象,很重要的一點原因在于其數據獲取較為便利。本文讀取數據的過程借助了一款命令行瀏覽器cURL,這個瀏覽器在R中可以用RCurl包實現,簡要的中文介紹建議參考medo的《R不務正業之RCurl》。通過RCurl的簡單編程,我們可以在R中實現登錄人人網、發布狀態以及讀取頁面數據等功能。
人人網好友列表頁面的url為http://friend.renren.com/GetFriendList.do?curpage=0&id=****,其中curpage為頁碼參數,id為相應的用戶。通過對id與curpage做簡單的循環,我讀取了自己(陳逸波)的所有好友以及好友的好友。(讀取數據的R代碼見文末附件。)
用上述代碼讀取到的數據集記為friend_all,該數據有如下的格式:
| 1 2 | set.seed(13) friend_all[sample(1:nrow(friend_all), 10), ] |
其中,第一行數據表示“沈葉”與“邢鳳婷”是好友關系,id0與id1為相應的用戶id。需要注意的是人人網中不可避免地會出現同名用戶的情況,因此id才是用戶的唯一標識。
二、繪制簡單的好友關系網絡圖
本文分析的焦點集中于我的好友之間形成的網絡,因此考慮做網絡圖來直觀地展示網絡的結構。
首先,從上述讀取到的數據集中篩選出希望分析的子集。這個子集包含了兩個條件:
(1)網絡中沒有我自己(否則會呈現以我為中心的分布,失去了分析的意義);
(2)網絡中的用戶都是我自己的好友。
| 1 2 3 4 5 | tmp1 = friend_all[friend_all[, 2] == "41021031", ] ## "41021031"是用戶的uid,在讀取數據的代碼中可以自動獲取 tmp2 = friend_all[(friend_all[, 2] != "41021031") & ??????????????????(friend_all[, 4] %in% tmp1[, 4]), c(2, 4)] tmp1 = tmp1[tmp1[, 4] %in% tmp2[, 1] & tmp1[, 4] %in% tmp2[, 2], ] |
然后就是直接利用igraph包的做圖功能繪制相應的網絡圖。考慮前面提到的用戶同名情況,直接用id來做后續的分析。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | library(igraph) people = data.frame(id = tmp1[, 4], name = tmp1[, 3]) gg = graph.data.frame(d = tmp2, directed = F, vertices = people) is.simple(gg) gg = simplify(gg) ## 去掉重復的連接 is.simple(gg) ## png("net_simple.png", width = 500, height = 500) par(mar = c(0, 0, 0, 0)) set.seed(14) plot(gg, layout = layout.fruchterman.reingold, vertex.size = 5, vertex.label = NA, ????edge.color = grey(0.5), edge.arrow.mode = "-") ## dev.off() |
從圖中可以直觀地看出,我的好友網絡存在一定的人群分割,可以嘗試對這個網絡進行一些分析以提取出其中相對獨立的子群(或者稱為社群)。
三、子群分割
信息的分類和過濾是社會網絡服務的一項特征,例如人人網對好友關系有一套自己的分類方式,用戶可以自行對好友進行分組,從而對信息的收發做分組的管理。但是作為用戶卻未必能夠養成并保持這種分組的習慣(例如我自己就從來沒有對好友做過分組)。與此同時我們揣測,作為真實關系的線上反映,人人網的好友網絡是能夠自動呈現出一定的人群分割的,而在社會網絡分析中,對網絡成分的分析也確實是一項重點。通過分析網絡的結構,提取出其中的子群,能夠讓我們更好地理解這個網絡的組成方式,從而更好地管理和利用信息流。
尋找子群的算法有很多,igraph包提供了若干函數以實現對網絡子群的搜索,本文采用了其中的walktrap.community()函數,更多細節及其他算法可以查看幫助文檔。
為了在網絡圖中展示這些子群,我們采用不同的顏色來標記他們。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | com = walktrap.community(gg, steps = 6) sg = data.frame(name = com$labels, sg = com$mem + 1) subgroup = vector("list", length(unique(com$mem))) for(i in 1:length(unique(com$mem))){ subgroup[[i]] = as.character(sg[sg[, 2]== i, 1])} rm(i) ## subgroup V(gg)$sg = com$mem + 1 V(gg)$color = rainbow(max(V(gg)$sg))[V(gg)$sg] ## png("net_walktrap.png", width = 500, height = 500) par(mar = c(0, 0, 0, 0)) set.seed(14) plot(gg, layout = layout.fruchterman.reingold, vertex.size = 5, ????vertex.color = V(gg)$color, vertex.label = NA, edge.color = grey(0.5), ????edge.arrow.mode = "-") ## dev.off() |
從圖中可以直觀地看出好友網絡已經被劃分為若干相對獨立的子群。這也與我們對人人網(尤其是其前身校內網)的直觀理解相符合——人人網的好友關系基本都是真實線下關系的反映,很自然地可以劃分為初中同學、高中同學、大學同學,等等(例如網絡的上半部分為小學及中學的同學,下半部分為大學同學,而左側的五個節點,那是統計之都的同學們。)。
具體地看一下劃分得到的子群,就能夠更好地理解子群的含義。我挑出了比較典型的幾個子群,其中包括:
“實驗室同學”(子群9)
| 1 | subgroup[[9]] |
“校內論壇上某版版友”(子群7)
| 1 | subgroup[[7]] |
“高中學弟學妹”(子群11)
| 1 | subgroup[[11]] |
“統計之都”(子群8)
| 1 | subgroup[[8]] |
其他子群還包括“大學同學(數學系)”、“大學同學(非數學系)”等等,不一而足(甚至能夠區分高中的不同班級的同學)。因此可以認為上述算法得到的子群劃分是合理且有意義的。
更進一步地,可以對照網絡圖來考察各個子群成員的分布情況。例如大學數學系同學(下方藍色點)的鏈接較為緊密,而非數學系的大學同學(主要是校內論壇上的朋友,下方紅色點)的分布則相對分散。通過網絡密度可以定量地印證這一點:
| 1 2 3 4 5 6 7 8 9 10 | ## 數學系 sg10=subgraph(gg,V(gg)[sg==10]) ## 非數學系 sg1=subgraph(gg,V(gg)[sg==1]) graph.density(gg) ## [1] 0.06376068 graph.density(sg10) ## [1] 0.5883441 graph.density(sg1) ## [1] 0.1223607 |
四、起到中介作用的那些好友
在社會網絡分析中,對節點的中介作用有一個經典的刻畫叫做“中間度”。中間度衡量了節點作為中介的程度,當網絡中某個個體的中間度較大時,我們認為它在很大程度上起到了中介和溝通的作用。常用的中間度的定義是,其中表示聯通i與j兩個節點的捷徑的條數,則表示聯通i與j兩個節點且經過v的捷徑的條數(所謂捷徑,就是兩個節點之間的最短路徑)。在igraph包中,betweenness()函數能夠簡單地計算網絡中各個節點的中間度。
| 1 2 3 4 5 | V(gg)$bte = betweenness(gg, directed = F) ## png("net_betweenness.png", width = 500, height = 500) par(mar = c(0, 2, 0, 0)) plot(V(gg)$bte) ## dev.off() |
根據得到的中間度散點圖,我們人為地選擇了3000作為分界點,選取中間度高于3000的節點并在圖形中利用節點的大小展示出來。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | V(gg)$size = 5 V(gg)[bte>=3000]$size = 15 ## 這里的3000可以換成分位數之類 V(gg)$label=NA V(gg)[bte>=3000]$label=V(gg)[bte>=3000]$name V(gg)$cex=1 V(gg)[bte>=3000]$cex=2 ## png("net_walktrap_betweenness.png", width = 500, height = 500) par(mar = c(0, 0, 0, 0)) set.seed(14) plot(gg, layout = layout.fruchterman.reingold, vertex.size = V(gg)$size, ????vertex.color = V(gg)$color, vertex.label = V(gg)$label, ????vertex.label.cex=V(gg)$cex, edge.color = grey(0.5), ????edge.arrow.mode = "-") ## dev.off() |
從圖中也可以直觀地看出,中間度最高的5個節點,確實位于中介的地位。
具體看這5個節點:
| 1 | V(gg)[bte>=3000] |
對這5個節點,基本上都有比較合理的解釋,其中有三個人是“高中校友”兼“大學校友”,而另外兩個則溝通了“網絡好友”與“大學好友”。
五、基于好友關系的一種簡單的推薦
最后,我們也做了基于好友關系的好友推薦,推薦的邏輯與人人網自身的推薦邏輯相同:根據共同好友的數量來進行推薦。在具體實現的時候,仍然需要考慮用戶同名的情況。
| 1 2 3 4 5 6 7 | tmp3 = friend_all[!(friend_all[, 4] %in% ????????friend_all[friend_all[, 2] == "41021031", 4]), ] listall = sort(table(tmp3[, 4]), dec = T) top = names(listall[1:20]) tmp4 = tmp3[tmp3[, 4] %in% top, 3] top20 = sort(table(tmp4), dec = T) top20 |
這個推薦的結果與人人網的推薦基本一致(因為邏輯相同嘛),以下是人人網的一些推薦截圖:
上述推薦的機制較為簡單,但是在擁有大量真實關系的網絡中,推薦的效率還是比較高的。當然,我們也可以開展對文本與行為的挖掘,以得到超越真實線下關系的推薦,但本文尚未做這方面的嘗試。
2011-06-20 增加了新的代碼在附件中,可以直接獲取“共同好友”。如果只需要分析好友的群組關系(而忽略并無技術含量的好友推薦功能),可以直接運行這段代碼,大幅度提高效率,幾分鐘就能搞定,同時繞過好友同名的問題。歡迎試用,如需修改參數麻煩自行操作。=”=
2011-12-15 修改了正文的腳本,修正了數據讀取的代碼中的一處錯誤。
總結
以上是生活随笔為你收集整理的简单的社交网络分析(基于R)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 保监会:《保险公司信息系统安全管理指引(
- 下一篇: Windows 7下Eclipse搭建A