Louvain是一個用于社區發現的傳統算法。這個算法出現于2008年,那么什么是社區發現呢?舉個例子:假設我們有一個圖,在這個圖中的節點是某個鎮的所有的人,圖中的每一條邊代表的是兩個人之間的說話的數量。(現實生活中這個可能難以統計)而社區發現就是在這個圖中我們需要確定哪些人之間是一個團體,這個所謂的團體可能是同一個小學,也可能是同一個家庭或者是同一個小區等等。論文的原文全稱是:Fast unfolding of communities in large networks 作者:Vincent D. Blondel, Jean-Loup Guillaume, Renaud Lambiotte and Etienne Lefebvre
'''Implements the Louvain method.Input: a weighted undirected graphOuput: a (partition, modularity) pair where modularity is maximum
'''classPyLouvain:'''Builds a graph from _path._path: a path to a file containing "node_from node_to" edges (one per line)'''@classmethoddeffrom_file(cls, path):#從txt中讀取一個netf =open(path,'r')lines = f.readlines()f.close()nodes ={}edges =[]for line in lines:n = line.split()ifnot n:breaknodes[n[0]]=1nodes[n[1]]=1w =1iflen(n)==3:w =int(n[2])edges.append(((n[0], n[1]), w))# rebuild graph with successive identifiersnodes_, edges_ = in_order(nodes, edges)print("%d nodes, %d edges"%(len(nodes_),len(edges_)))return nodes_, edges_ #此處作了一點修改'''Builds a graph from _path._path: a path to a file following the Graph Modeling Language specification'''@classmethoddeffrom_gml_file(cls, path):#從gml中讀取一個netf =open(path,'r')lines = f.readlines()f.close()nodes ={}edges =[]current_edge =(-1,-1,1)in_edge =0for line in lines:words = line.split()ifnot words:breakif words[0]=='id':nodes[int(words[1])]=1elif words[0]=='source':in_edge =1current_edge =(int(words[1]), current_edge[1], current_edge[2])elif words[0]=='target'and in_edge:current_edge =(current_edge[0],int(words[1]), current_edge[2])elif words[0]=='value'and in_edge:current_edge =(current_edge[0], current_edge[1],int(words[1]))elif words[0]==']'and in_edge:edges.append(((current_edge[0], current_edge[1]),1))current_edge =(-1,-1,1)in_edge =0nodes, edges = in_order(nodes, edges)print("%d nodes, %d edges"%(len(nodes),len(edges)))return nodes, edges #此處作了一點修改'''Initializes the method._nodes: a list of ints_edges: a list of ((int, int), weight) pairs'''def__init__(self, nodes, edges):self.nodes = nodesself.edges = edges# precompute m (sum of the weights of all links in network)# k_i (sum of the weights of the links incident to node i)self.m =0self.k_i =[0for n in nodes]self.edges_of_node ={}self.w =[0for n in nodes]self.orginer_network =[]self.orginer_k_i =[]for e in edges:self.m += e[1]self.k_i[e[0][0]]+= e[1]self.k_i[e[0][1]]+= e[1]# there's no self-loop initially# save edges by nodeif e[0][0]notin self.edges_of_node:self.edges_of_node[e[0][0]]=[e]else:self.edges_of_node[e[0][0]].append(e)if e[0][1]notin self.edges_of_node:self.edges_of_node[e[0][1]]=[e]elif e[0][0]!= e[0][1]:self.edges_of_node[e[0][1]].append(e)# access community of a node in O(1) timeself.communities =[n for n in nodes]self.actual_partition =[]self.orginer_k_i =[]for k in self.k_i:self.orginer_k_i.append(k)'''Applies the Louvain method.'''deffindRoot(self,node):for i,community inenumerate(self.actual_partition):if(node in community):return idefmy_compute_modularity(self):sum_Q =0for edge in self.orginer_network[1]:u,v = edge[0]w = edge[1]if(self.findRoot(u)== self.findRoot(v)):sum_Q =(w -(self.orginer_k_i[u]*self.orginer_k_i[v])/(2*self.m))/(2*self.m)return sum_Qdefapply_method(self):network =(self.nodes, self.edges)self.orginer_network = networkbest_partition =[[node]for node in network[0]]best_q =-1i =1while1:# print("pass #%d" % i)i +=1partition = self.first_phase(network)#q = self.compute_modularity(partition)q = self.my_compute_modularity()partition =[c for c in partition if c]# print("%s (%.8f)" % (partition, q))# clustering initial nodes with partitionif self.actual_partition:actual =[]for p in partition:part =[]for n in p:part.extend(self.actual_partition[n])actual.append(part)self.actual_partition = actualelse:self.actual_partition = partitionprint(q)if q == best_q:breaknetwork = self.second_phase(network, partition)best_partition = partitionbest_q = qreturn(self.actual_partition, best_q)'''Computes the modularity of the current network._partition: a list of lists of nodes'''defcompute_modularity(self, partition):q =0m2 = self.m *2for i inrange(len(partition)):q += self.s_in[i]/ m2 -(self.s_tot[i]/ m2)**2return q'''Computes the modularity gain of having node in community _c._node: an int_c: an int_k_i_in: the sum of the weights of the links from _node to nodes in _c'''defcompute_modularity_gain(self, node, c, k_i_in):return2* k_i_in - self.s_tot[c]* self.k_i[node]/ self.m'''Performs the first phase of the method._network: a (nodes, edges) pair'''deffirst_phase(self, network):# make initial partitionbest_partition = self.make_initial_partition(network)while1:improvement =0for node in network[0]:node_community = self.communities[node]# default best community is its ownbest_community = node_communitybest_gain =0# remove _node from its communitybest_partition[node_community].remove(node)best_shared_links =0for e in self.edges_of_node[node]:if e[0][0]== e[0][1]:continueif e[0][0]== node and self.communities[e[0][1]]== node_community or e[0][1]== node and \self.communities[e[0][0]]== node_community:best_shared_links += e[1]self.s_in[node_community]-=2*(best_shared_links + self.w[node])#self.s_tot[node_community] -= self.k_i[node]self.s_tot[node_community]-=(self.k_i[node]-2*best_shared_links)self.communities[node]=-1communities ={}# only consider neighbors of different communitiesfor neighbor in self.get_neighbors(node):community = self.communities[neighbor]if community in communities:continuecommunities[community]=1shared_links =0for e in self.edges_of_node[node]:if e[0][0]== e[0][1]:continueif e[0][0]== node and self.communities[e[0][1]]== community or e[0][1]== node and \self.communities[e[0][0]]== community:shared_links += e[1]# compute modularity gain obtained by moving _node to the community of _neighborgain = self.compute_modularity_gain(node, community, shared_links)if gain > best_gain:best_community = communitybest_gain = gainbest_shared_links = shared_links# insert _node into the community maximizing the modularity gainbest_partition[best_community].append(node)self.communities[node]= best_communityself.s_in[best_community]+=2*( best_shared_links + self.w[node])#self.s_tot[best_community] += (self.k_i[node])self.s_tot[best_community]+=(self.k_i[node]-2*best_shared_links)if node_community != best_community:improvement =1ifnot improvement:breakreturn best_partition'''Yields the nodes adjacent to _node._node: an int'''defget_neighbors(self, node):for e in self.edges_of_node[node]:if e[0][0]== e[0][1]:# a node is not neighbor with itselfcontinueif e[0][0]== node:yield e[0][1]if e[0][1]== node:yield e[0][0]'''Builds the initial partition from _network._network: a (nodes, edges) pair'''defmake_initial_partition(self, network):partition =[[node]for node in network[0]]self.s_in =[0for node in network[0]]self.s_tot =[self.k_i[node]for node in network[0]]for e in network[1]:if e[0][0]== e[0][1]:# only self-loopsself.s_in[e[0][0]]+= e[1]self.s_in[e[0][1]]+= e[1]return partition'''Performs the second phase of the method._network: a (nodes, edges) pair_partition: a list of lists of nodes'''defsecond_phase(self, network, partition):nodes_ =[i for i inrange(len(partition))]# relabelling communitiescommunities_ =[]d ={}i =0for community in self.communities:if community in d:communities_.append(d[community])else:d[community]= icommunities_.append(i)i +=1self.communities = communities_# building relabelled edgesedges_ ={}for e in network[1]:ci = self.communities[e[0][0]]cj = self.communities[e[0][1]]try:edges_[(ci, cj)]+= e[1]except KeyError:edges_[(ci, cj)]= e[1]edges_ =[(k, v)for k, v in edges_.items()]# recomputing k_i vector and storing edges by nodeself.k_i =[0for n in nodes_]self.edges_of_node ={}self.w =[0for n in nodes_]for e in edges_:self.k_i[e[0][0]]+= e[1]self.k_i[e[0][1]]+= e[1]if e[0][0]== e[0][1]:self.w[e[0][0]]+= e[1]if e[0][0]notin self.edges_of_node:self.edges_of_node[e[0][0]]=[e]else:self.edges_of_node[e[0][0]].append(e)if e[0][1]notin self.edges_of_node:self.edges_of_node[e[0][1]]=[e]elif e[0][0]!= e[0][1]:self.edges_of_node[e[0][1]].append(e)# resetting communitiesself.communities =[n for n in nodes_]return(nodes_, edges_)'''Rebuilds a graph with successive nodes' ids._nodes: a dict of int_edges: a list of ((int, int), weight) pairs
'''defin_order(nodes, edges):# rebuild graph with successive identifiersnodes =list(nodes.keys())nodes.sort()i =0nodes_ =[]d ={}for n in nodes:nodes_.append(i)d[n]= ii +=1edges_ =[]for e in edges:edges_.append(((d[e[0][0]], d[e[0][1]]), e[1]))return(nodes_, edges_)###################******************---下面是使用方法的一個例子---******************####################下面是Louvain的使用方式import argparse
import networkx as nx
import random
import matplotlib.pyplot as plt
defgetRandomColor():'''這是隨機獲取一種顏色。但是,不能保證獲取的顏色差距一定很大。所以,如果想要直觀的看到結果。有時候需要多運行幾次。'''return random.randint(0,255)defdrawNet_Louvain(G,part_list):'''將社區劃分完成的圖進行直觀的展示。'''for i inrange(len(part_list)):for j inrange(len(part_list[i])):part_list[i][j]+=1print(part_list)color_list =[]for part in part_list:color = getRandomColor()for node in part:color_list.append((node,color))color_list.sort(key =lambda x: x[0])print(color_list)color_list =[x[1]for x in color_list]plt.figure(figsize=(5,5))print("finish")print(len(G.nodes()))print(len(color_list))pos = nx.spring_layout(G)nx.draw(G, with_labels=True, node_color=color_list, pos=pos)plt.show()plt.savefig(r"filename.png")defmain(option):data_path = option.data_path#此處需要修改對應的數據文件的路徑if(data_path[-3:]=="txt"):#如果文件是在txt中的讀取方式net_G_nodes,net_G_edges = PyLouvain.from_file(data_path)#使他的方法進行數據讀取,返回的是點集和邊集net_G = nx.read_edgelist(data_path)#因為他使用的是完全自己實現的代碼,無法進行畫圖展示。所以,需要自己在讀入一個networkx的elif(data_path[-3:]=="gml"):#如果文件是在gml中的讀取方式net_G_nodes,net_G_edges = PyLouvain.from_gml_file(data_path)#使他的方法進行數據讀取,返回的是點集和邊集net_G = nx.read_gml(data_path,label="id")#因為他使用的是完全自己實現的代碼,無法進行畫圖展示。所以,需要自己在讀入一個networkx的new_G = PyLouvain(net_G_nodes,net_G_edges)#使用它的方法構造成一個類,傳入的參數依次是點集和邊集t,d = new_G.apply_method()#應用其中的方法,對社區進行分割。返回值分別是最佳的社區劃分,以及對應的Q值。drawNet_Louvain(net_G, t)#對分割完成的圖進行展示。if __name__ =="__main__":parser = argparse.ArgumentParser()parser.add_argument("--data_path",type=str, default="karate.gml",help="data_path is the path of the net")opt = parser.parse_args()main(opt)
然后是我根據我自己的理解所實現的算法 2.code
import networkx as nx
import argparsedefCalDeltaQ1(G,node_i,k_i_in,k_i,community_list,community_value,community_tot,community_id,neg_community_id,node_edge,edge_list,m,opt):'''function:用于計算deltaQparameter:G:當前的圖node_i:正在操作的節點的編號k_i_in:從i指向區域C的所有邊的權值和k_i:指向節點i的所有邊的權值和(包括自環的邊)community_list:每一個社區所包含的結點的編號community_value:社區內的所有這的權值和community_tot:社區指向外部節點的所有邊的權值和community_id :node_i 所處社區的編號neg_community_id:相鄰社區的社區編號node_edge:node_i這一節點的鄰邊edge_list:圖的所有邊的列表m:全圖的所有邊的和opt:其中有選擇deltaQ的計算方式的選項return:返回對應的deltaQ'''sumC = community_value[neg_community_id]sum_tot = community_tot[neg_community_id]+ community_value[neg_community_id]if(opt.calDeltaQfunction =="fun_copy"):#使用的是參考代碼中的公式將其中的2改成1就是優化后的論文中的公式return2*k_i_in - sum_tot*k_i/melif(opt.calDeltaQfunction =="my_fun"):#使用我自己推導的公式,因為沒有驗證過它的正確性。所以不推薦使用sum_k_i =0delta_Q =(k_i_in)/(2*m)k_j =0for edge in G[node_i]:if(edge in community_list[neg_community_id]):k_j += G.nodes[edge]["node_out"]+ G.nodes[edge]["value"]delta_Q -=(k_j*k_i)/(4*(m**2))return delta_Qelse:#原模原樣的使用論文中的公式m2 =2*mreturn((sumC + k_i_in)/m2 -((sum_tot + k_i)/m2)**2)-(sumC/m2-(sum_tot/m2)**2-(k_i/m2)**2)defPutNode2Community(node,community_list,community_value,community_tot,k_i_c,k_i,root_id,m,level):'''使用并查集的方法進行編號合并parameter:node:結點 包涵信息root_id: 需要把結點加入的社區的idm:全圖的權值總合level:經過的第幾次合并(不知道怎么用)return:無,在過程中會更新node_list中的各個結點的root_list屬性值'''node["root_list"][0]= root_idcommunity_list[root_id].append(node["node_id"])community_value[root_id]+=(node["value"]+2*k_i_c)community_tot[root_id]+=(k_i -2*k_i_c)defgetInitCommunity(G,node_list):#社區中所包涵的節點,社區value(sumC_in),社區的出度(sumC_tot)node2community =[]node2community_value =[]node2community_tot =[]for node in node_list:node2community.append([node])node2community_value.append(G.nodes[node]["value"])node2community_tot.append(G.nodes[node]["node_out"])return node2community,node2community_value,node2community_tot
defflag2Merge(G,node_list,m,level,opt):'''function :對接收的圖G進行社區劃分,返回劃分結果node_list:結點列表m :全圖的權值和level :迭代的次數opt :里面包含了deltaQ的計算方式return:社區劃分的表示形式。"set":每一個社區中所包含的節點的編號。"value":社區內部的權值。(社區內的邊的兩倍)"tot":社區內的節點指向,社區外的邊的和'''#對社區的信息進行初始化community_list,community_value,community_tot = getInitCommunity(G,node_list)while(True):promote =False#是否對于社區劃分是否有更新for node in node_list:#先將node結點移出node所對應的社區 可優化community_id = G.nodes[node]["root_list"][0]#該節點所屬的社區的編號community_list[community_id].remove(node)#將節點移出其所屬的社區k_i_c =0#從節點指向社區的所有邊的權值和for edge in G[node]:if(edge in community_list[community_id]):k_i_c += G[node][edge]["weight"]community_value[community_id]-=(2*k_i_c + G.nodes[node]["value"])#由于已經將節點移出社區,所以需要更新其區社的value值community_tot[community_id]-=(G.nodes[node]["node_out"]-2*k_i_c)#由于已經將節點移出社區,所以需要更新其區社的tot值#在相鄰的社區中找最優max_delta_Q =0max_k_i_c = k_i_cbest_community_id = community_id#k_i = sum([edge["weight"] for edge in G[node].values()]) #原寫法k_i = G.nodes[node]["node_out"]#此處先把k_i 表示為該節點指向其它節點的邊的權值和#嘗試將節點加入到相鄰的社區之中neg_community_use =set()for neg_node in G[node]:if(isinstance(neg_node,int)):neg_community = G.nodes[neg_node]["root_list"][0]#相鄰節點所屬的社區if(neg_community in neg_community_use):#如果已經嘗試過則不再嘗試continueelse:neg_community_use.add(neg_community)k_i_c =0#節點相相鄰節點之間的權值和for edge in G[node]:if(edge in community_list[neg_community]):k_i_c += G[node][edge]["weight"]#計算deltaQdelta_Q = CalDeltaQ1(G,node,k_i_c,k_i + G.nodes[node]["value"],community_list,community_value,community_tot,community_id,neg_community,G[node],G.edges(),m,opt)#更新最優劃分,以及相關信息if(delta_Q > max_delta_Q):max_delta_Q = delta_Qmax_k_i_c = k_i_cbest_community_id = G.nodes[neg_node]["root_list"][0]#將節點加入到最優劃分的區間中if(max_delta_Q >0and best_community_id != community_id):promote =True#將節點加入到最優的社區中,并且更新其comuniyu的相關屬性PutNode2Community(G.nodes[node], community_list,community_value,community_tot,max_k_i_c,k_i,best_community_id, m, level)if(not promote):breakreturn{"set":community_list,"value":community_value,"tot":community_tot}defMergeG2getNewG(G,community):'''function:根據其社區劃分的結果重新生成一個新的圖G:原先的圖結構community:社區劃分的結果,community["set"]——社區中所包含的節點的編號community["value"]——社區內部的所有邊的權值和的兩倍community["tot"]——所有社區內部節點指向社區外部節點的邊的權值和return:返回一個縮點后的圖,以及其中對應的邊'''new_G = nx.Graph()#一個新的圖cnt_community =0#對社區進行遍歷for i,community_set inenumerate(community["set"]):#將節點進行合并產生一批新圖中的總節點#node_id node_set root_list value outif(community_set):#如果在社區中有元素則構造新的節點,加入到圖中#編號i作為節點編號,community["set"]中的元素就是該社區所包含的對應的元素,將cnt_community作為臨時根,community["value"]作為該節點的編號,community["tot"]作為該節點的出度#community["value"] + community["tot"]就是指向該社區節點的所有邊的權值和new_G.add_node(i,node_id = i,node_set = community_set,root_list =[cnt_community],value = community["value"][i],node_out = community["tot"][i])cnt_community +=1for edge in G.edges():#將邊進行處理加入到適當的新圖中#weightnode1,node2 = edgeroot1 = G.nodes[node1]["root_list"][0]root2 = G.nodes[node2]["root_list"][0]if(root1 == root2):#這條邊的一個社區的內部#在community["value"]中已經加上,所以不用在這里再加。在PutNode2Community函數中#new_G.nodes[root1]["value"] += 2*G[node1][node2]["weight"]continueelse:#這條邊的兩個社區之間,則與其它的邊一同進行合并if((root1,root2)notin new_G.edges()):new_G.add_edge(root1,root2,weight = G[node1][node2]["weight"])else:new_G[root1][root2]["weight"]+= G[node1][node2]["weight"]return new_GdefdealSelfLoop(G):'''對圖中的所有的邊進行遍歷,如果存在自環就將其刪除,同時一個自環就對那個對應的節點上的值+2問題:對于networkx 而言它會自動的刪除重邊。所以在這一點上對于使用networkx對最終的結果會有影響。'''for node in G:cnt_self_node =0flag =Falsefor neg_node in G[node]:if(node == neg_node):#如果有重邊就刪除同時更新節點上的值flag =Truecnt_self_node +=2if(flag):G.remove_edge(node, node)G.nodes[node]["value"]= cnt_self_nodereturn GdefstateINIT(G):for node in G:for edge in G[node]:G[node][edge]["weight"]=1#每一條邊都有一個權值,由于是無權圖因此權值都需要變為1for i,node inenumerate(G.nodes):G.nodes[node]["node_id"]= node #節點的IDG.nodes[node]["node_set"]={node}#社區中所包含的節點(對于第一個圖用不上)G.nodes[node]["root_list"]=[i]#每一個節點從屬的社區的編號G.nodes[node]["node_out"]=sum([G[node][edge]["weight"]for edge in G[node]])#節點相鄰邊的權值和defgraphArrange(levelG_list):'''圖的整理,也就是根節點的向下傳遞更新每一層的圖的根節點'''l =-1*len(levelG_list)-1for level inrange(-2,l,-1):G1 = levelG_list[level +1]G2 = levelG_list[level]for node in G1.nodes():#獲取節點的根,然后將該社區內的所有節點的根也進行更新root_id = G1.nodes[node]["root_list"][-1]# print(root_id,":")for member_id in G1.nodes[node]["node_set"]:# print(member_id,end=" ")G2.nodes[member_id]["root_list"].append(root_id)# print("")# print(G1.nodes())# print(G2.nodes())defcalGraphQ(G,new_G,m,level,opt):'''function:計算圖在當前的社區劃分下的Q值G:原圖new_G:最近的經過縮點后的圖m:全圖的權值和level:遞歸的次數opt:其中指定了是使用哪一種Q的計算方法return:圖的Q值'''if(opt.calQFunction =="fun_copy"):#這是參考代碼中使用的Q的計算方式sum_Q =0for new_node in new_G:sum_in = new_G.nodes[new_node]["value"]sum_tot = new_G.nodes[new_node]["node_out"]sum_Q +=(sum_in/(2*m)-(sum_tot/(2*m))**2)return sum_Qelse:#這是在論文中使用的Q的計算方式sum_Q =1for edge in G.edges:u,v = edgeroot_u = G.nodes[u]["root_list"][-1]root_v = G.nodes[v]["root_list"][-1]if(root_u == root_v):#如果u和v同屬于一個社區#G.nodes[u]["value"]節點內部的邊(自環)#G.nodes[v]["node_out"] 節點的鄰邊sum_u = G.nodes[u]["value"]+ G.nodes[v]["node_out"]sum_v = G.nodes[v]["value"]+ G.nodes[v]["node_out"]sum_Q -= sum_u*sum_v/(4*(m**2))*2#乘二是因為(u,v)(v,u)要當作兩條邊來計算#sum_Q += (G[u][v]["weight"] - (sum_u)*(sum_v )/(2*m))/(2*m)return sum_QdefLouvain(G,m,opt):dealSelfLoop(G)#對自環進行處理stateINIT(G)#對G添加屬性,同時完成初始化level =0#記錄迭代次數merageG_list =[]#在這個列表中用于記錄在迭代過程中的所有形成的子圖best_q =-2#不斷更新,獲取最終的Q值while(True):level +=1#返回的是對圖的一個社區劃分,以及每一個社區中的信息#其中# community["set"]中存儲的是每一個社區中所包涵的結點的編號# community["value"] 中表示的是每一個社區的權值,其權值主要是自環的2倍# sommunity["tot"]中表示的是每一個社區內的結點指向外面的所有邊的權值和。(注意:此外不是指向所有社區內的所有邊的權值和)community = flag2Merge(G,list(G.nodes),m,level,opt)#將圖的社區劃分進行縮點重新組成一個新的圖,同時對于新的圖添加必要的信息new_G = MergeG2getNewG(G,community)#將新的圖添加到時圖列表中merageG_list.append(G)#將圖列表進行整理,只整理根節點的信息graphArrange(merageG_list)#重新更新使用的圖G = new_G#計算圖的Q值new_q = calGraphQ(merageG_list[0],G,m,level,opt)print(new_q)#如果Q值沒有變化則,線束算法if(new_q == best_q):break#更新最優的Q值(其實就是最后一種劃分的Q值)best_q = new_qreturn merageG_listdefCalGraphM1(net_G):#把單個邊當作無向圖的一條邊來處理#因為是無權所以邊的權值看作是1m =len(net_G.edges())return m
import random
import matplotlib.pyplot as plt
defgetRandomColor():return random.randint(0,255)defdrawNet_Louvain(G_Louvain_list,show_level):"""function:將每一次迭代產生的社區劃分結果進行展示"""show_G = G_Louvain_list[0]#print(len(G_Louvain_list[show_level].nodes))color_list =[]color_dict ={}for node in show_G.nodes():node_color = show_G.nodes[node]["root_list"][show_level]if(node_color in color_dict):color_list.append(color_dict[node_color])else:color = getRandomColor()color_dict[node_color]= colorcolor_list.append(color_dict[node_color])plt.figure(figsize=(5,5))#print("finish")#print(len(show_G.nodes()))#print(len(color_list))pos = nx.spring_layout(show_G)nx.draw(show_G,with_labels=True,node_color=color_list,pos=pos)#plt.show()plt.savefig("filename"+str(show_level)+".png")defmain(option):data_path = option.data_pathif(data_path[-3:]=="txt"):net_G = nx.read_edgelist(data_path,comments='#',delimiter=None,create_using=None,nodetype=int,data=True,edgetype=int,encoding='utf-8',)elif(data_path[-3:]=="gml"):net_G = nx.read_gml(data_path,label="id")m = CalGraphM1(net_G)#計算全圖換邊權和G_merage_list = Louvain(net_G,m,option)#進行Louvain算法for i inrange(len(G_merage_list)):#畫圖drawNet_Louvain(G_merage_list,i)if __name__ =="__main__":parser = argparse.ArgumentParser()parser.add_argument("--data_path",type=str,default="karate.gml",#數據的路徑help="data_path is the path of the net")parser.add_argument("--calQFunction",type=str,default="22",#計算Q的方式#Q的選擇只能是使用"fun_copy"或者其它,如果是"fun_copy"則使用的是code1中的Q的計算方法。如果是其它則使用的是原論文中的Q的計算方法help="calQFunction is the mode to calQ,should choose from ['fun_copy',other]") parser.add_argument("--calDeltaQfunction",type=str,default="my_fun",#計算deltaQ的方式#deltaQ的選擇只能是使用"fun_copy"或者其它,如果是"fun_copy"則使用的是code1中的deltaQ的計算方法。如果是"my_fun"則使用的是我自己的理解推的一個公式。如果是其它則使用的是原論文中的deltaQ的計算方法help="calDeltaQfunction the mode to calDeltaQ,should choose from ['fun_copy','my_fun',other]")opt = parser.parse_args()#如果使用的是jupyter需要把上面一行注釋掉修改成下面這一行#opt = args = parser.parse_args(args=[])main(opt)