複雜網路作業五:第四題——Structural Role 結構角色:ROIX

ccutyear發表於2020-10-25


前言

扯淡建議跳過:昨天晚上本來是已經寫完了,結果第二天發現內容不對什麼原因我也不知道。在這個沒有做作業的一週之中,發生了很多的新聞。其中,最令人印象深刻的四川某校的書記的以死明志。想到當初的教科書中的“安能以身之察察,受物之汶汶者乎?寧赴湘流,葬於江魚之腹中。安能以皓皓之白,而蒙世俗之塵埃乎?”真的在現實生活中上了頭條。想想也是如果這個書記不這麼做就無法給這個社會帶來一點震撼,這才是這個時代最需要的脊樑吧!另外,正是因為那些高尚的精神在這個社會中並非隨處可見(應該說是極其罕見),所以才更值得新一帶人所崇拜。最後,說實話如果的作是我,我恐怕會變成一條泥鰍在淤泥中打滾吧。畢竟活著遠遠要比改變環境更容易。(我認為書記並非想逃避,他是想通過這種方式來改變大環境。)呵呵,這也就是為什麼大多數的人都是普通人吧。


一、題目

科學家合作網,下載地址http://www-personal.umich.edu/~mejn/netdata/netscience.zip.這個網路是加權的,把這個網路按照無向和無權網路來處理。
特徵抽取分成兩步:首先抽取節點的基本區域性特徵,然後聚集起來以獲得全域性特徵。特徵抽取構建出矩陣V,包含n個節點,每個節點都有f個特徵,包括區域性和全域性資訊。ROIX從矩陣中抽取節點的特徵。
(1)基本特徵:對於每個節點v,選擇3個基本特徵:

  1. 節點v的度,deg(v);
  2. 節點v的區域性網路egonet(v)中的邊數,其中v的區域性網路egonet(v)是包含節點v及其鄰居的匯出子圖
  3. 節點v的區域性網路和圖G的其他部分連線的邊數,也就是進入或者離開v的區域性網路的邊數。
    我們使用V~u來表示節點u的基本特徵向量。對於任意節點對u和v,使用cos相似性來度量其特徵向量x和y之間的相似性。Cos相似性的定義如下面的公式:
    在這裡插入圖片描述
    在這裡插入圖片描述
    問題:計算出節點9的基本特徵向量,並給出與節點9最相似的前5個節點(節點9本身除外)。(注:本題中V~9中的元素不大於10)
    (2)遞迴特徵
    本步中將遞迴產生更多的特徵。這裡使用mean和sum作為聚合函式。初始時,每個節點u都有一個特徵向量在這裡插入圖片描述
    。在第一輪迭代中,我們聚合u的所有鄰居的特徵向量均值(mean)到Vu中,也特徵向量求和(sum)做相同操作,也就是得到如下面公式所示的Vu(1):
    在這裡插入圖片描述
    N(u)是節點u的鄰居。如果N(u)為空的話,mean和sum也都為0.
    在k輪迭代後,會獲得所有的特徵矩陣
    在這裡插入圖片描述
    問題:這裡執行2輪迭代,即K=2。給出與節點9最相似的5個節點(節點9本身除外)。(提示:節點9以及與它最相似性的5個節點的相似性值都大於0.9)。與本題中的第一個問題中得出的前5個節點相比,本問題的解和第一個問題的解有哪些相同節點和哪些不同節點?
    (3)角色發現
    這個部分將根據節點的遞迴特徵向量和節點相似性得出更多的結論。
    問題1:建立有20個bin的直方圖,給出節點9和其他節點的cos相似度分佈(根據其遞迴特徵向量)。X軸是其他節點和節點9的cos相似度,y軸是節點的數量。是否可以直方圖得出一些組/角色?能得出幾組?(提示,查詢spikes)
    問題2:對於這些組/角色,從每組中選取節點u,檢視其特徵向量,並根據其特徵向量畫出節點的子圖。可以用手畫,也可以使用networkx或者graphviz畫。圖中,需要使用到節點u的區域性特徵,並且注意其1跳鄰居的聚集特徵。如果某些特徵難以使用的話,可以忽略掉,而且不必畫出節點u的三跳以外的節點。
    最後,簡單總結一下結構上的角色差異。

二、需要使用的函式的介紹(networkx)

1.構建一個圖

nx.Graph()

2.從gml檔案讀入一個圖

nx.read_gml(path,label=“id”) #和網上的可能會有不同

3.取出圖中的節點

G.nodes #G是networkx.Graph型別的變數

4.取出圖中的邊

G.edges #G是networkx.Graph型別的變數

5.把多個節點批量加入到圖中

G.add_nodes_from(nodes)

6.把多個邊批量加入到圖中

G.add_edges_from(edges)

7.求某一個節點的度

G.degree(node) #G是networkx型別的變數,node是一個int型別的變數

8.獲取一個區域性鄰居子圖

nx.ego_graph(G,node,radius=2)
G:圖
node:是中心點的編號
radius:步長

9.針對一個圖找出一個合理的部局

pos = nx.spring_layout(G)

10.根據部局來畫圖

nx.draw_networkx(G,pos) #沒有標籤

11.根據部局來畫標籤(編號)

nx.draw_networkx_labels(G,pos = pos)

三、需要使用的函式的介紹(matplotlib.pyplot)

1.為什麼要新增這一個

考慮到有人可能對這個模組下的東西不熟,所以就把matplotlib的相關東西也寫一下。(有關list,numpy的東西就不寫了)至於matplotlib的安裝就不過程就不寫了,大家就自己百度吧。

2.設定橫座標

plt.xlabel(name,fontproperties=“simsun”) #fontproperties是用於設定字型,這樣就可以顯示中文了。

3.設定縱座標

plt.ylabel(name,fontproperties=“simsun”)#fontproperties是用於設定字型,這樣就可以顯示中文了。

4.設定標題

plt.title(name,fontproperties=“simsun”)#fontproperties是用於設定字型,這樣就可以顯示中文了。

5.畫柱狀統計圖

plt.bar(x=x_bar,height=y_bar,width=0.1)

6.統計圖展示

plt.show()

7.設定畫布大小

plt.figure(figsize=(15,15))

8.畫布清空

plt.clf()

9.圖畫儲存

plt.savefig(save_path)


程式碼

# -*- coding: utf-8 -*-
import random
import networkx as nx
import numpy as np
import matplotlib.pyplot as plt
#讀取網路圖
path = r"netscience.gml"
science_G = nx.read_gml(path,label="id")
#把原來的無向帶權圖轉化為無向無向無權圖
nodes = science_G.nodes
edges = science_G.edges
G = nx.Graph()
G.add_nodes_from(nodes)
G.add_edges_from(edges)
#統計節點的特徵資訊
node_degree_list = []  #節點度特徵
node_egonet_list = []  #子圖特徵
node_global_list = []  #全域性特徵
local_graph_list = []  #區域性子圖(用於在後面使用)

def calGlobalFeature(G1,G2):
    edges = G2.edges
    cnt_out_edge = 0
    for edge in edges:
        u,v = edge
        if((u in G1 and v not in G1) or (v in G1 and u not in G1)):
            cnt_out_edge+=1
    return cnt_out_edge
for node in G:
    node_degree = science_G.degree(node)
    node_degree_list.append(node_degree)
  #  print(node_degree)
    ego_G = nx.ego_graph(G,node)
    node_egonet = ego_G.number_of_edges()
    node_egonet_list.append(node_egonet)
  #  print(node_egonet)
    ego2_G = nx.ego_graph(G,node,radius=2)
    node_global =  calGlobalFeature(ego_G,ego2_G)
    node_global_list.append(node_global)
  #  print(node_global)
    local_graph_list.append(ego_G)
node_id_list = list(G.nodes())   #獲得所有節點的編號,但是需要注意是亂序的

node_feature = list(zip(node_id_list,node_degree_list,node_egonet_list,node_global_list)) # [編號,度,鄰域,全域性]
node_feature.sort(key = lambda x:x[0])   #通過排序使得它是按照節點的遞增序排列
node_feature = np.array(node_feature)    #轉成ndarray型別方便後續計算

# 資訊特徵統計完成,編號是亂序
# 接下來是計算與9號結點之間的相似性
def calSim(node1,node2):
    node1_np = node1[1:]
    node2_np = node2[1:]
    if(np.sqrt(np.sum(node2_np*node2_np))) == 0:
        return (node2[0],0)
    return (node2[0],np.sum(node1_np*node2_np)/(np.sqrt(np.sum(node1_np*node1_np))*np.sqrt(np.sum(node2_np*node2_np))))
# 在本題的第一小題中只需要求出9號節點與前10個結點的相似度
# 即可,但是後面以我的理解是和所有節點的相似度。這麼做可以
# 使得其得函式的使用可調整
def calNodeFeatureSim(node_feature_list,node_id,cal_len=99999):
    '''
    :param node_feature_list: 節點的特徵序列
    :param node_id: 目標節點
    :param cal_len: 有多少個結點需要用來計算相似度
    :return: 與目標節點的相似度序列
    '''
    node_feature = node_feature_list[node_id]
    sim = []
    for node in node_feature_list:
        if(node[0] == node_id):
            continue
        if(node[0] > cal_len):
            break
        sim.append(calSim(node_feature,node))
    sim.sort(key = lambda x:x[1],reverse=True)
    return sim

sim9 = calNodeFeatureSim(node_feature,9,10)
print("在前10個節點中與9號節點最相似的5個節點如下:")
print("節點編號       相似度")
for i in range(5):
    print("  {}       {}".format(sim9[i][0],sim9[i][1]))


#計算遞迴特徵
def recursionFeature(node_feature,local_feature_list):
    '''
    :param node_feature: 結點的特徵序列
    :param local_feature_list: 每一個結點的一跳區域性子圖
    :return: 新的特徵
    '''
    new_node_feature = []
    for node in node_feature:
        node_id = int(node[0])
        local_G = local_graph_list[node_id]
        feature_len = len(node)
        new_feature1 = np.zeros(shape=(feature_len - 1),dtype = np.float32)
       # print(node_id)
        for neig_node in local_G.nodes():
            if(neig_node == node_id):
                continue
           # print(neig_node,node_feature[neig_node])
            new_feature1 += node_feature[neig_node][1:]
        if(len(local_G.nodes()) > 1):
            new_feature2 = new_feature1/(len(local_G.nodes()) - 1)
        else:
            new_feature2 = new_feature1 = np.zeros(shape=(feature_len - 1),dtype = np.float32)
        new_node_feature.append(np.append(new_feature1,new_feature2))
    new_node_feature = np.array(new_node_feature)
    node_feature = np.hstack((node_feature,new_node_feature))
    return node_feature
for i in range(2):
    node_feature = recursionFeature(node_feature,local_graph_list)
sim9 = calNodeFeatureSim(node_feature,9,10)
print(node_feature.shape)  #此時每一個節點的特徵數量應該是27個,所以此處應該是28列(第一列是編號)
print("遞迴特徵之後")
print("在前10個節點中與9號節點最相似的5個節點如下:")
print("節點編號       相似度")
for i in range(5):
    print("  {}       {}".format(sim9[i][0],sim9[i][1]))
#進行角色發現,這裡可能有錯誤。我不知道我理解的角色發現是否正確
sim9 = calNodeFeatureSim(node_feature,9) #按照我的理解應該要在全域性中進行角色發現
sim9 = np.array(sim9)   #轉成ndarray型別方便後續計算
#對數量資訊進行統計
bardata = []
base_l = 0
base_u = 0
change = 1/20
for i in range(20):
    base_u += change
    bar1 = sim9[sim9[:,1] < base_u]
    bar2 = bar1[bar1[:,1] >= base_l]
    bardata.append(bar2)
    base_l = base_u

x_bar = [1/20*x + 0.025 for x in range(20)]  #柱形圖的橫軸
y_bar = [len(x) for x in bardata ]   #柱形圖的縱軸

plt.xlabel("相似度",fontproperties="simsun")
plt.ylabel("數量",fontproperties="simsun")
plt.title("相似度統計圖",fontproperties="simsun")
plt.bar(x=x_bar,height=y_bar,width=0.1)
plt.show()
import heapq #用於尋找最大的n個值
max3_index = list(map(y_bar.index,heapq.nlargest(3,y_bar))) #用於尋找最大的3個值,並獲取對應的下標
random_node = []
for index in max3_index:
    random_node.append(int(bardata[index][random.randint(0,y_bar[index])][0]))
print("從三組中選出的任意結點是:",random_node)
plt.figure(figsize=(15,15))  #設定畫布大小
for node_id in random_node:
    plt.clf()   #一共要畫三個圖,所以每一次在畫圖之前都需要清空
    act_local_G = nx.ego_graph(G,node_id,radius=3)
    for node in act_local_G:
        act_local_G.add_node(node,local_feature = node_feature[node][1])
    pos=nx.spring_layout(act_local_G) #根據spring演算法進行部局,spring演算法我不知道是啥。
    nx.draw_networkx(act_local_G,pos)
    nx.draw_networkx_labels(act_local_G,pos = pos)
    plt.savefig(r"filename" + str(node_id) + ".png")  #對圖片進行儲存

執行結果截圖
在這裡插入圖片描述
在這裡插入圖片描述
角色發現圖(這一個不知道對不對)
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

總結

其中我對角色發現的理解可能是錯的,我之前這作業我不做不知道。做才發現網上有關networkx的使用教程少的可憐。而且都是相互抄來抄去的。估計等我這五個題做完,我的這幾篇部落格networkx的最全使用教程了吧。(_)II

相關文章