defgenCircle(N=5242): """ :param - N: number of nodes return type: snap.PUNGraph return: Circle graph with N nodes and N edges. Imagine the nodes form a circle and each node is connected to its two direct neighbors. """ ############################################################################ # TODO: Your code here! Graph = snap.PUNGraph.New() for i in range(N): Graph.AddNode(i) Graph.AddEdge(N - 1, 0) for i in range(N - 1): Graph.AddEdge(i, i + 1) ############################################################################ return Graph
defconnectNbrOfNbr(Graph, N=5242): """ :param - Graph: snap.PUNGraph object representing a circle graph on N nodes :param - N: number of nodes return type: snap.PUNGraph return: Graph object with additional N edges added by connecting each node to the neighbors of its neighbors """ ############################################################################ # TODO: Your code here! for i in range(N): n1 = (i + 1 + N) % N n2 = (i - 1 + N) % N Graph.AddEdge(n1, n2) ############################################################################ return Graph
defconnectRandomNodes(Graph, M=4000): """ :param - Graph: snap.PUNGraph object representing an undirected graph :param - M: number of edges to be added return type: snap.PUNGraph return: Graph object with additional M edges added by connecting M randomly selected pairs of nodes not already connected. """ ############################################################################ # TODO: Your code here! N = Graph.GetNodes() cnt = 0 while cnt < M: src = np.random.randint(0, N) dst = np.random.randint(0, N) ifnot Graph.IsEdge(src, dst): Graph.AddEdge(src, dst) cnt += 1 ############################################################################ return Graph
defgenSmallWorld(N=5242, E=14484): """ :param - N: number of nodes :param - E: number of edges return type: snap.PUNGraph return: Small-World graph with N nodes and E edges """ Graph = genCircle(N) Graph = connectNbrOfNbr(Graph, N) Graph = connectRandomNodes(Graph, 4000) return Graph
Question 1.1 Degree Distribution
计算Degree Distribution。Degree Distribution就是:
这里并不需要计算出分数,而是直接将度为k的节点数以log-log图画出来。
这里画图使用matplotlib,首先要生成x,y坐标上对应的数。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
defgetDataPointsToPlot(Graph): """ :param - Graph: snap.PUNGraph object representing an undirected graph return values: X: list of degrees Y: list of frequencies: Y[i] = fraction of nodes with degree X[i] """ ############################################################################ # TODO: Your code here! X, Y = [], [] DegToCntV = snap.TIntPrV() snap.GetDegCnt(Graph, DegToCntV) for item in DegToCntV: X.append(item.GetVal1()) Y.append(item.GetVal2()) ############################################################################ return X, Y
defcalcClusteringCoefficientSingleNode(Node, Graph): """ :param - Node: node from snap.PUNGraph object. Graph.Nodes() will give an iterable of nodes in a graph :param - Graph: snap.PUNGraph object representing an undirected graph return type: float returns: local clustering coeffient of Node """ ############################################################################ # TODO: Your code here! C = 0.0 neigbors = [] deg = Node.GetDeg() for i in range(deg): neigbors.append(Graph.GetNI(Node.GetNbrNId(i))) cnt_nbr = 0 for i in range(deg): for j in range(i): cnt_nbr += neigbors[i].IsInNId(neigbors[j].GetId()) if deg >= 2: C = 2 * cnt_nbr / (deg * (deg - 1.0)) ############################################################################ return C
defcalcClusteringCoefficient(Graph): """ :param - Graph: snap.PUNGraph object representing an undirected graph return type: float returns: clustering coeffient of Graph """ ############################################################################ # TODO: Your code here! If you filled out calcClusteringCoefficientSingleNode, # you'll probably want to call it in a loop here C = 0.0 V = Graph.GetNodes() for NI in Graph.Nodes(): Ci = calcClusteringCoefficientSingleNode(NI, Graph) C = C + Ci C = C / V
############################################################################ return C
# 所有1-hop节点放进去 for i in range(center_node.GetDeg()): nbr_id = center_node.GetNbrNId(i) Nodes.append(nbr_id) # 所有2-hop节点放进去 for i in range(len(Nodes)): mid_node = Graph.GetNI(Nodes[i]) for j in range(mid_node.GetDeg()): nbr_id = mid_node.GetNbrNId(j) Nodes.append(nbr_id) Nodes = list(set(Nodes))
for mid_id in Nodes: if mid_id == Node_id: colors.append('r') else: colors.append('b') # print(Nodes) for i in range(len(Nodes)): for j in range(i): if Graph.IsEdge(Nodes[i], Nodes[j]): Edges.append((Nodes[i], Nodes[j])) # print(len(Edges)) G = nx.Graph() G.add_nodes_from(Nodes) G.add_edges_from(Edges) nx.draw_networkx(G, node_color=colors) # plt.show()
运行结果如下:分别为直方图和2-hop子图。
Overall
最大的感觉就是光听一遍和写完一遍代码对于整个流程完全有着不同程度的理解,还是得多练啊。。。
中间也卡了不少次,花费了不少的时间T.T
Part 3 Community detection using the Louvain algorithm
Community is just sets of tightly connected nodes.
首先是定义一个优化目标,其应该是A measure of how well a network is partitioned into communities,该值正比于划分的好坏. 即对于每一个可能的partition都给出一个分数,目标就是找到使该分数最大的一个划分。这里使用的指标为:Modularity。定义如下图所示。