La comunidad
Si una imagen es una descripción de un área, divídala en muchas subimágenes. Cuando la correlación dentro del subgrafo es tan grande como sea posible, y la correlación entre subgrafos es lo más baja posible, dicho subgrafo puede llamarse comunidad.
Algoritmo de descubrimiento comunitario
Existen muchos algoritmos de descubrimiento de comunidades, como LPA, HANP, SLPA y Lovaina, y diferentes algoritmos tienen diferentes efectos en la división de comunidades. El algoritmo de Lovaina es un algoritmo de descubrimiento comunitario basado en la modularidad. El algoritmo funciona bien tanto en eficiencia como en efectividad, y puede descubrir la estructura jerárquica de la comunidad. Su objetivo de optimización es maximizar la modularidad de toda la red comunitaria.
Modularidad
La modularidad es una medida para evaluar la calidad de una red comunitaria. Su significado físico es que el número de bordes conectados de nodos en la comunidad solo es diferente del número de bordes en un caso aleatorio. Su rango de valores es [−1 / 2,1) . Se puede entender simplemente como el peso de los bordes dentro de la comunidad menos el peso de todos los bordes conectados a los nodos de la comunidad, y el gráfico no dirigido se entiende mejor, es decir, el grado de los bordes dentro de la comunidad menos el grado total de los nodos dentro de la comunidad.
Algoritmo de Lovaina
Flujo de algoritmo:
1. Inicialmente, cada vértice se considera como una comunidad, y el número de comunidades es el mismo que el número de vértices.
2. Combine cada vértice con su vértice adyacente a su vez y calcule si su ganancia de modularidad es mayor que 0. Si es mayor que 0, coloque el nodo en la comunidad donde se encuentra el nodo adyacente.
3. Itere el segundo paso hasta que el algoritmo sea estable, es decir, las comunidades a las que pertenecen todos los vértices ya no cambian.
4. Comprima todos los nodos en cada comunidad en un nodo, el peso de los nodos en la comunidad se convierte en el peso del nuevo anillo de nodo, y el peso entre las comunidades se convierte en el peso del lado del nuevo nodo.
5. Repita los pasos 1-3 hasta que el algoritmo sea estable.
# coding=utf-8
import collections
import random
def load_graph(path):
G = collections.defaultdict(dict)
with open(path) as text:
for line in text:
vertices = line.strip().split()
v_i = int(vertices[0])
v_j = int(vertices[1])
w = float(vertices[2])
G[v_i][v_j] = w
G[v_j][v_i] = w
return G
class Vertex():
def __init__(self, vid, cid, nodes, k_in=0):
self._vid = vid
self._cid = cid
self._nodes = nodes
self._kin = k_in # 结点内部的边的权重
class Louvain():
def __init__(self, G):
self._G = G
self._m = 0 # 边数量
self._cid_vertices = {} # 需维护的关于社区的信息(社区编号,其中包含的结点编号的集合)
self._vid_vertex = {} # 需维护的关于结点的信息(结点编号,相应的Vertex实例)
for vid in self._G.keys():
self._cid_vertices[vid] = set([vid])
self._vid_vertex[vid] = Vertex(vid, vid, set([vid]))
self._m += sum([1 for neighbor in self._G[vid].keys() if neighbor > vid])
def first_stage(self):
mod_inc = False # 用于判断算法是否可终止
visit_sequence = self._G.keys()
random.shuffle(list(visit_sequence))
while True:
can_stop = True # 第一阶段是否可终止
for v_vid in visit_sequence:
v_cid = self._vid_vertex[v_vid]._cid
k_v = sum(self._G[v_vid].values()) + self._vid_vertex[v_vid]._kin
cid_Q = {}
for w_vid in self._G[v_vid].keys():
w_cid = self._vid_vertex[w_vid]._cid
if w_cid in cid_Q:
continue
else:
tot = sum(
[sum(self._G[k].values()) + self._vid_vertex[k]._kin for k in self._cid_vertices[w_cid]])
if w_cid == v_cid:
tot -= k_v
k_v_in = sum([v for k, v in self._G[v_vid].items() if k in self._cid_vertices[w_cid]])
delta_Q = k_v_in - k_v * tot / self._m # 由于只需要知道delta_Q的正负,所以少乘了1/(2*self._m)
cid_Q[w_cid] = delta_Q
cid, max_delta_Q = sorted(cid_Q.items(), key=lambda item: item[1], reverse=True)[0]
if max_delta_Q > 0.0 and cid != v_cid:
self._vid_vertex[v_vid]._cid = cid
self._cid_vertices[cid].add(v_vid)
self._cid_vertices[v_cid].remove(v_vid)
can_stop = False
mod_inc = True
if can_stop:
break
return mod_inc
def second_stage(self):
cid_vertices = {}
vid_vertex = {}
for cid, vertices in self._cid_vertices.items():
if len(vertices) == 0:
continue
new_vertex = Vertex(cid, cid, set())
for vid in vertices:
new_vertex._nodes.update(self._vid_vertex[vid]._nodes)
new_vertex._kin += self._vid_vertex[vid]._kin
for k, v in self._G[vid].items():
if k in vertices:
new_vertex._kin += v / 2.0
cid_vertices[cid] = set([cid])
vid_vertex[cid] = new_vertex
G = collections.defaultdict(dict)
for cid1, vertices1 in self._cid_vertices.items():
if len(vertices1) == 0:
continue
for cid2, vertices2 in self._cid_vertices.items():
if cid2 <= cid1 or len(vertices2) == 0:
continue
edge_weight = 0.0
for vid in vertices1:
for k, v in self._G[vid].items():
if k in vertices2:
edge_weight += v
if edge_weight != 0:
G[cid1][cid2] = edge_weight
G[cid2][cid1] = edge_weight
self._cid_vertices = cid_vertices
self._vid_vertex = vid_vertex
self._G = G
def get_communities(self):
communities = []
for vertices in self._cid_vertices.values():
if len(vertices) != 0:
c = set()
for vid in vertices:
c.update(self._vid_vertex[vid]._nodes)
communities.append(c)
return communities
def execute(self):
iter_time = 1
while True:
iter_time += 1
mod_inc = self.first_stage()
if mod_inc:
self.second_stage()
else:
break
return self.get_communities()
if __name__ == '__main__':
G = load_graph('s.txt')
algorithm = Louvain(G)
communities = algorithm.execute()
# 按照社区大小从大到小排序输出
communities = sorted(communities, key=lambda b: -len(b)) # 按社区大小排序
count = 0
for communitie in communities:
count += 1
print("社区", count, " ", communitie)
Networkx y división de comunidad comunitaria y visualización
Instalar
Use la comunidad para instalar python-louvain para
instalar pip python-louvain
pip install networkx
Para utilizar
Mejor división
community.best_partition(graph, partition=None, weight='weight', resolution=1.0)
Calcule la partición de los nodos del gráfico que maximiza la modularidad (o intente ...) utilizando la heurística de Lovaina.
Esta es la partición de mayor modularidad, es decir, la partición más alta del dendrograma generado por el algoritmo de Lovaina.
import community
import networkx as nx
import matplotlib.pyplot as plt
#better with karate_graph() as defined in networkx example.
#erdos renyi don't have true community structure
G = nx.erdos_renyi_graph(30, 0.05)
#first compute the best partition
partition = community.best_partition(G)
#drawing
size = float(len(set(partition.values())))
pos = nx.spring_layout(G)
count = 0.
for com in set(partition.values()) :
count = count + 1.
list_nodes = [nodes for nodes in partition.keys()
if partition[nodes] == com]
nx.draw_networkx_nodes(G, pos, list_nodes, node_size = 20,
node_color = str(count / size))
nx.draw_networkx_edges(G,pos, alpha=0.5)
plt.show()