Análisis Geoespacial del Transporte - Lección 2: Cálculo de Redes Complejas y sus Indicadores

Este documento son mis notas de clase.

Estrictamente hablando, debido a que la mitad de las notas son contenido del material didáctico del maestro, simplemente le agregué mi propia comprensión y explicación, por lo que mi maestro completó la mitad de la creación del contenido de esta nota.

  • Este curso trata principalmente sobre algunos métodos prácticos de análisis geoespacial.
  • Más que la teoría, me importa más cómo implementarla.
  • Lo combiné con Python que suelo utilizar para explicar y resolver problemas.
  • Basado en el cuaderno Jupyter

Compártelo aquí, espero que pueda ayudar a algunas personas.

Revisión de notas de análisis geoespaciales de transporte anteriores:


En la lección anterior, introdujimos una serie de conceptos básicos de la teoría de grafos, incluidos los conceptos de nodos y aristas, cómo usar matrices para representar gráficos, etc., y también brindamos algunas implementaciones en Python de métodos simples de teoría de grafos. Introdujimos algunos conceptos sobre redes y entramos en el concepto de redes complejas.

Hay muchos modelos adecuados para redes complejas en la vida real: Web, red de Internet, red de cooperación de actores de cine, red de cooperación científica, red de citas en papel, red de llamadas telefónicas, red lingüística, red eléctrica, red económica, red de transporte, propagación de enfermedades, redes neuronales. red Red, red de relaciones sexuales humanas, red de interacción de proteínas, red de relaciones de plegamiento de proteínas ...

En esta lección, continuaremos presentando algunos conceptos de redes complejas.

En esta nota, para familiarizarme con algunos métodos operativos prácticos, usaré Python para hacer algunos ejemplos, incluido el dibujo y algunos métodos de procesamiento de datos.

Las siguientes son las bibliotecas utilizadas en esta nota:

import numpy as np 
import networkx as nx
import matplotlib.pyplot as plt

Aquí me gustaría presentarles NetWorkX, el conjunto de herramientas que utilizo para solucionar problemas de planificación de redes. Aquí hay una breve introducción al kit de herramientas:

RedX

NetworkX es un paquete de Python para la creación, manipulación y estudio de la estructura, dinámica y funciones de redes complejas.

Consulte https://networkx.org para obtener la documentación completa.

NetWorkX es un paquete de Python que se utiliza para construir y operar estructuras de gráficos complejas y proporciona algoritmos para analizar gráficos. Se puede decir que este paquete está diseñado específicamente para gráficos de redes complejos y puede ayudarnos a realizar varios problemas en el procesamiento, análisis, cálculo y visualización de redes.

  • Herramientas para estudiar la estructura y dinámica de redes sociales, biológicas y de infraestructura;
  • Una interfaz de programación estándar e implementación de gráficos adecuada para una variedad de aplicaciones;
  • Proporcionar un entorno de desarrollo rápido para proyectos colaborativos y multidisciplinarios;
  • Interfaces con algoritmos numéricos existentes y código C, C++ y FORTRAN;
  • Capacidad para manejar grandes conjuntos de datos no estándar con facilidad.

Debido a que los documentos técnicos originales a menudo están bloqueados, le recomiendo que vaya al sitio de documentos espejo del sitio web oficial de la Open Source Geospatial Association para leer los documentos técnicos: NetWorkX - OSGeo Open Source Spatial Geography Association

Aquí están las configuraciones de dibujo para esta nota:

plt.rcParams.update(
    {
    
    
        # "figure.figsize":(8, 6), 
        "font.sans-serif":'SimHei', 
        "figure.dpi":100, 
        "axes.unicode_minus":False, 
        "image.cmap":'viridis'
    }
)

Métricas de red

En primer lugar, espero que todos puedan entender un concepto, es decir, la red se divide en buenos y malos , y la red se divide en buenos y malos, porque la red es un modelo conceptual que abstrajimos, y detrás de este modelo conceptual, Hay muchas cuestiones prácticas de construcción de ingeniería.

Por ejemplo, si queremos instalar cables ópticos en una aldea ahora, esperamos que el costo de los cables ópticos sea lo más bajo posible y al mismo tiempo lograr una conectividad estable. Entonces, suponiendo que abstraigamos los cables ópticos de toda la aldea en un modelo de red, esperamos que este modelo de red tenga buena conectividad y una longitud total corta. Pero la pregunta es ¿cómo definir la conectividad y la longitud total?

Hemos desarrollado los siguientes indicadores. Nota: Algunos de estos indicadores son para la red, mientras que otros son para puntos de la red, que deben examinarse para comprenderlos específicamente.

En este caso, para medir la calidad de una red, necesitamos desarrollar algunos indicadores para medirla.

Podemos utilizar el siguiente diagrama de red como ejemplo:

w = np.array(
    [
        [0, 2, 4, 5, 0, 0, 0],
        [2, 0, 0, 2, 0, 7, 0],
        [4, 0, 0, 1, 4, 0, 0],
        [5, 2, 1, 0, 3, 4, 0],
        [0, 0, 4, 3, 0, 1, 7],
        [0, 7, 0, 4, 1, 0, 5],
        [0, 0, 0, 0, 7, 5, 0]
     ]
)
G = nx.from_numpy_array(w, create_using = nx.Graph())
G = nx.convert_node_labels_to_integers(G, first_label = 1)
weights = nx.get_edge_attributes(G, "weight")

Dibujemos la red para este ejemplo.

pos = nx.spring_layout(G)
nx.draw_networkx(G, pos, with_labels = True)
nx.draw_networkx_edge_labels(G, pos, edge_labels = weights)
{(1, 2): Text(0.7243447156107068, 0.051857859258879646, '2'),
 (1, 3): Text(0.36250316341599337, -0.7783934189391077, '4'),
 (1, 4): Text(0.506341301696545, -0.3038377920385775, '5'),
 (2, 4): Text(0.4686328641327283, 0.3048069050985177, '2'),
 (2, 6): Text(0.3027391038445652, 0.6863178638748365, '7'),
 (3, 4): Text(0.1067913119380149, -0.5254443730994698, '1'),
 (3, 5): Text(-0.34659661811461046, -0.6187230923540853, '4'),
 (4, 5): Text(-0.20275847983405879, -0.14416746545355502, '3'),
 (4, 6): Text(0.08473568993040345, 0.33062221257737934, '4'),
 (5, 6): Text(-0.3686522401222219, 0.23734349332276378, '1'),
 (5, 7): Text(-0.7905569923698414, 0.11751992816374057, '7'),
 (6, 7): Text(-0.5030628226053793, 0.5923096061946749, '5')}

Insertar descripción de la imagen aquí

distribución de grados

El grado de un vértice se refiere al número de aristas conectadas a este vértice. En las redes dirigidas, se dividen en grados de entrada y de salida .

La investigación incluye: distribución de grados y sus características, y correlación de grados.

La distribución de valores de grados es una propiedad geométrica importante de la red.

  • El valor de grado de cada vértice de la red regular es el mismo, por lo que se ajusta a Δ \DeltaDistribución Δ .
  • Las redes aleatorias siguen una distribución de Poisson.

En NetWorkX, existen las siguientes dos funciones que pueden calcular el grado de cada nodo.

usar función
Obtener los grados de todos los nodos. G.grado()
Obtener el grado de salida de un nodo G.out_grado(i)
G.degree()
DegreeView({1: 3, 2: 3, 3: 3, 4: 5, 5: 4, 6: 4, 7: 2})

Los temas generales de investigación en teoría de redes complejas incluyen: grado y sus características de distribución, correlación de grado... (Estos solo se mencionan brevemente aquí sin una discusión en profundidad)

Las características de distribución de los valores de grados son propiedades geométricas importantes de la red.

  • El valor de grado de cada vértice de la red regular es el mismo, por lo que se ajusta a la distribución delta.
  • La red aleatoria sigue la distribución de Poisson.

Correlación de grado: Newman lo llama "patrón de coincidencia", lo que significa examinar si los puntos con un valor de grado grande tienden a estar conectados con puntos con un valor de grado grande, o si tienden a estar conectados con puntos con un valor de grado pequeño.

El análisis de redes reales muestra que diferentes redes tienen diferentes patrones de coincidencia, con correlaciones positivas y negativas. Correlación de grados In-Out basada en vértices (en redes dirigidas).

Por supuesto, existen cuestiones e indicadores más complejos con respecto a la distribución de grados de la red. Saltemos esto primero y veamos otros indicadores (para que podamos volver a estudiar la cuestión de la distribución de títulos más adelante).

longitud media del camino

Hay varios conceptos independientes en este problema y los presentaremos respectivamente.

camino más corto

Camino más corto : el camino más cortoi, j entre dos vértices de la red se define como el camino o caminos que pasan por la menor cantidad de otros vértices entre todos los caminos conectados.(i, j)

En otras palabras, puede haber más de un camino más corto en la red. En este caso, todos los caminos que cumplen con nuestra definición de camino más corto son lo que llamamos caminos más cortos.

Debido a que nuestro curso habla principalmente sobre algunas cosas conceptuales y luego, en última instancia, las pone en práctica teórica, aquí no nos preocupa mucho el algoritmo específico para obtener el camino más corto. Para estos conceptos en los que estamos involucrados, la red será relativamente simple: básicamente, puede encontrar todos los caminos más cortos a simple vista o mediante un algoritmo transversal. Pero podemos saber que uno de los algoritmos más utilizados es el algoritmo de Dijkstra.

El problema del camino más corto no es un problema de flujo mínimo

Hay una cuestión muy importante que es necesario aclarar: este problema del camino más corto no es un problema de flujo mínimo. Estas dos cuestiones son particularmente fáciles de confundir . Y muchos de los algoritmos que utilizan son los mismos, lo que resulta particularmente fácil de confundir. Este pequeño y sencillo problema me tuvo estancado durante media hora.

Para el problema de flujo mínimo, se calcula el peso en cada borde, es decir, cuando se usa Dijkstra para considerar el peso en cada borde, se encuentra un camino con el peso total más pequeño entre dos nodos.

El problema del camino más corto solo considera pasar por varios nodos y aristas, tratando de minimizar el número de nodos y aristas que pasan, en este caso cuando usamos el algoritmo de Dijkstra equivale a sumar directamente el peso de cada arista, el valor predeterminado es 1.

Si estos dos conceptos no se comprenden claramente, también cometerá errores al comprender los demás conceptos siguientes.

networkx.all_shortest_paths()Todos los caminos más cortos se pueden encontrar utilizando el siguiente método:

shortest_paths = nx.all_shortest_paths(
    G, 
    source = 1, # 起始节点标号
    target = 6, # 终末节点标号
    method = 'dijkstra', # 指定算法
)

Si queremos resolver el problema de flujo mínimo, entonces necesitamos traer parámetros weight = 'weight', lo que indica que el peso del gráfico de red especificado al asignar valores al gráfico de red se utiliza como estándar de peso del algoritmo de dijkstra. Antes era difícil solucionar este problema durante mucho tiempo.

El sitio web oficial describe este problema de la siguiente manera:

peso

Ninguno, cadena o función, opcional (predeterminado = Ninguno)

Si es Ninguno, cada borde tiene peso/distancia/coste 1. Si es una cadena, utilice este atributo de borde como peso del borde. Cualquier atributo de borde que no esté presente tiene el valor predeterminado 1. Si se trata de una función, el peso de un borde es el valor devuelto por la función. La función debe aceptar exactamente tres argumentos posicionales: los dos puntos finales de un borde y el diccionario de atributos de borde para ese borde. La función debe devolver un número.

método

cadena, opcional (predeterminado = 'dijkstra')

El algoritmo que se utilizará para calcular la ruta. Opciones admitidas: dijkstra, bellman-ford. Otras entradas producen un ValueError. Si weightes Ninguno, se utilizan métodos de gráficos no ponderados y se ignora esta sugerencia.

Pero no necesitamos eso aquí. Se puede ver que según la explicación en el sitio web oficial, si no se proporciona este parámetro, el peso predeterminado de cada borde es 1.

Hay otro problema aquí, es decir, el valor de retorno de este método es un objeto de tipo generador o un objeto de tipo iterador , que se llama en Python generator.

Generator es un tipo de datos especial en Python. La característica de este tipo de datos es que no se puede leer directamente como una lista. En cambio, realiza un cálculo independiente cada vez que el bucle llama al valor de salida. La ventaja de esto es que no No como una lista, es necesario ingresar una gran cantidad de datos cada vez que se crea, de lo contrario, se desperdiciará mucho espacio de memoria cuando la lista sea muy grande.

type(shortest_paths)
generator

En otras palabras, no puede print()obtener directamente la información del objeto a través de, este método solo devolverá generatorla dirección binaria del objeto. .

print(shortest_paths)
<generator object _build_paths_from_predecessors at 0x000001CE2BBAF660>

Si realmente queremos obtener la información de la ruta más corta, podemos elegir atravesar generatory al mismo tiempo print()( generatores un objeto iterable que generará datos durante el proceso de recorrido)

O como se muestra a continuación, convierta el resultado de salida en una sublista y agréguelo a una lista grande.

shortest_path_list = []
for path in shortest_paths:
    shortest_path_list.append( list(path) ) 
shortest_path_list
[[1, 2, 6], [1, 4, 6]]

De hecho, aquí también se diseña un problema oculto, que es la complejidad temporal del algoritmo de Dijkstra.

En pocas palabras, según cálculos matemáticos, se descubre que la complejidad temporal del algoritmo de Dijkstra no es tiempo polinómico. En el peor de los casos, la complejidad temporal del algoritmo de Dijkstra es:

O ( ( V + E ) Iniciar sesión ⁡ V ) O( ( V + E ) \log{ V })O (( V+mi )iniciar sesiónV )

donde V es el número de vértices del gráfico y E es el número de aristas del gráfico.

Esto se debe a que el algoritmo de Dijkstra requiere el uso de una cola de prioridad para seleccionar la siguiente ruta más corta y requiere operaciones de montón cada vez que se actualiza la distancia. Por lo tanto, la complejidad temporal del algoritmo de Dijkstra está relacionada con el número de vértices y aristas en el gráfico y no es una complejidad temporal polinomial.

Esto significa que cuando un gráfico de red tiene una gran cantidad de aristas y nodos, el algoritmo de Dijkstra llevará mucho tiempo, por lo que usar un generador en lugar de una lista generada una vez es una elección muy inteligente, porque en muchos casos En este En este caso, en realidad solo necesitamos encontrar una cantidad relativamente grande de caminos más cortos, no todos los caminos más cortos.

La notación O grande es un problema matemático muy complicado y, debido a mis rudimentarios conocimientos informáticos, no lo explicaré. Para obtener más información, consulte este artículo de blog: Análisis de complejidad temporal del algoritmo de Dijkstra-michealoven-CSDN . El análisis de esta publicación de blog es relativamente más detallado, considerando el algoritmo de Dijkstra que incluye el recorrido secuencial del conjunto T, usando un montón binario como cola de prioridad, usando un montón binomial como cola de prioridad y usando un montón de Fibonacci como cola de prioridad. Los cálculos de diferentes complejidades temporales en las cuatro formas de diseño de algoritmos son todos no polinomiales sin excepción.

A continuación queremos visualizar el camino más corto que encontramos:

Si queremos dibujar el camino más corto para él en el gráfico, entonces tenemos que marcar en listas los nodos y bordes por los que pasa el camino más corto.

path_edge_list = [] # 创建记录路径包含的边的列表
path_node_list = [] # 创建包含路径经过节点的列表
for sublist in shortest_path_list: # 遍历记录了所有最短路的列表
    for i in range( len(sublist)-1 ): 
        if [ sublist[i], sublist[i+1]] not in path_edge_list:
            path_edge_list.append([ sublist[i], sublist[i+1]])
    for node in sublist:
        if node not in path_node_list:
            path_node_list.append(node)

Permítanme explicar el principio de este código : la función de este código es generar una lista que contiene los bordes y nodos por los que pasa la ruta en función de la lista de rutas más cortas dada.

Primero, el código crea dos listas vacías: path_edge_listy path_node_list, que se utilizan para registrar los bordes contenidos en la ruta y los nodos pasados ​​por la ruta, respectivamente.

shortest_path_listA continuación, cada sublista (que representa la ruta más corta) se procesa atravesando la lista de rutas más cortas .

El primer bucle interno agrega cada borde (que consta de dos nodos adyacentes) iterando sobre los elementos de la sublista path_edge_list. Aquí se utiliza el juicio condicional if [sublist[i], sublist[i+1]] not in path_edge_list:para garantizar que los bordes no se agreguen repetidamente.

Porque sabemos que la ruta más corta que vemos aquí en realidad está escrita como una lista de una serie de números de nodo. Debe haber una conexión de borde entre el número de nodo anterior y el siguiente número de nodo en la lista, pero no necesariamente puede haber una conexión de borde entre dos números de nodo separados por un número de nodo en la lista; incluso si hay una conexión de borde, No debe ser el camino más corto. Por lo tanto, cuando recorremos los elementos de la sublista y los agregamos, solo necesitamos agregar bordes una vez por cada dos nodos. En este caso, suponiendo que la longitud del camino más corto es de n nodos, hay un total de n - 1 aristas entre estos nodos. por eso esfor i in range( len(sublist)-1 )

El segundo bucle interno agrega cada nodo de la sublista a path_node_list. El juicio condicional también se utiliza if node not in path_node_list:para evitar agregar nodos repetidamente.

Finalmente, cuando se hayan procesado todos los caminos más cortos, path_edge_listse incluirán los bordes por los que pasaron todos los caminos y path_node_listlos nodos por los que pasaron todos los caminos.

Mira los resultados:

print("包含的边:", path_edge_list)
print("包含的节点:", path_node_list)
包含的边: [[1, 2], [2, 6], [1, 4], [4, 6]]
包含的节点: [1, 2, 6, 4]

Luego podemos dibujar el camino más corto que se encuentra en la imagen:

# 绘制图形
pos = nx.spring_layout(G)  # 定义节点的布局位置
nx.draw_networkx_nodes(G, pos)  # 绘制节点
nx.draw_networkx_edges(G, pos)  # 绘制边

# 标记最短路径的边为红色,节点为橙色
nx.draw_networkx_edges(
    G, pos, 
    edgelist = path_edge_list,
    edge_color='red'
    )
nx.draw_networkx_nodes(
    G, pos, 
    nodelist = path_node_list,
    node_color='orange'
    )  # 绘制节点

# 绘制标签
nx.draw_networkx_labels(G, pos) # 绘制节点标签
nx.draw_networkx_edge_labels(G, pos, 
    edge_labels = weights
    ) # 绘制边权标签

{(1, 2): Text(0.7431046103364115, -0.19366616675567772, '2'),
 (1, 3): Text(0.10253599139712566, -0.9058957750675259, '4'),
 (1, 4): Text(0.4016773066925905, -0.47008285523609383, '5'),
 (2, 4): Text(0.5743088613970223, 0.14804252814328034, '2'),
 (2, 6): Text(0.5365892696416266, 0.5832644548689024, '7'),
 (3, 4): Text(-0.06625975754226353, -0.5641870801685679, '1'),
 (3, 5): Text(-0.5520885611755522, -0.5103461600670893, '4'),
 (4, 5): Text(-0.2529472458800874, -0.07453324023565716, '3'),
 (4, 6): Text(0.1951619659978056, 0.3068477663884863, '4'),
 (5, 6): Text(-0.29066683763548307, 0.36068868648996494, '1'),
 (5, 7): Text(-0.7555660399153519, 0.38681840036719195, '7'),
 (6, 7): Text(-0.3074568280374589, 0.7681994069913354, '5')}

Insertar descripción de la imagen aquí

Sí, este es el resultado que necesitamos. Hecho.

distancia entre nodos de red

La distancia dij d_{ij}i, j entre dos vértices dyoDefinido como el número de aristas en el camino más cortoi, j entre .

Con el concepto de distancia, podemos implementar una matriz de distancias . Una matriz de distancias es una matriz (es decir, una matriz bidimensional) que contiene las distancias entre un conjunto de puntos. Por lo tanto, dados N puntos en el espacio euclidiano, su matriz de distancias es una matriz simétrica N * N con números reales no negativos como elementos. Por ejemplo, para la siguiente red:

Insertar descripción de la imagen aquí

La matriz de distancias se puede escribir de la siguiente manera:

D = ( 0 1 1 2 1 0 1 1 2 0 2 2 0 3 0 ) D = \begin{pmatrix} 0 & 1 & 1 & 2 & 1 \\ & 0 & 1 & 1 & 2 \\ & & 0 & 2 & 2 \\ & & & 0 & 3 \\ & & & & 0 \\ \end{pmatrix}D= 010110212012230

No es necesario escribir el triángulo inferior izquierdo de la matriz, de todos modos, para un gráfico tan no dirigido, la matriz de distancias debe ser simétrica.

En Python, si queremos crear un gráfico usando una matriz de distancias, generalmente convertimos la matriz de distancias en una matriz de adyacencia. El método de conversión también es muy simple: si la distancia entre dos nodos es 1, significa que los dos nodos son adyacentes; por el contrario, no importa qué número distinto de 1 sea el valor entre los dos nodos, siempre que sea no es 1, entonces la Descripción no es adyacente.

dist_matrix = np.array(
    [
        [ 0, 1, 1, 2, 1 ],
        [ 1, 0, 1, 1, 2 ],
        [ 1, 1, 0, 2, 2 ],
        [ 2, 1, 2, 0, 3 ],
        [ 1, 2, 2, 3, 0 ],
    ]
)
adj_matrix = np.where( dist_matrix == 1, 1, 0 )
adj_matrix
array([[0, 1, 1, 0, 1],
       [1, 0, 1, 1, 0],
       [1, 1, 0, 0, 0],
       [0, 1, 0, 0, 0],
       [1, 0, 0, 0, 0]])

De esta manera, se puede obtener una matriz binaria de adyacencia con la misma forma que la matriz de distancias original, donde una posición igual a 1 indica que hay un borde (la distancia es 1) en la posición correspondiente en la matriz de distancias original, y una La posición igual a 0 indica que no hay borde.

Explique la implementación del código: np.where()es una función que devuelve elementos en una matriz según condiciones dadas.

En este código, np.where( dist_matrix == 1, 1, 0 )la función es dist_matrixreemplazar los elementos iguales a 1 en la matriz de distancias con 1, reemplazar los elementos restantes con 0 y devolver una nueva matriz.

Específicamente, itera a través de dist_matrixcada elemento y, si el elemento es igual a 1, establece el nuevo elemento de la matriz en la posición correspondiente en 1; si el elemento no es igual a 1, establece el nuevo elemento de la matriz en la posición correspondiente en 0. . De hecho, es equivalente al siguiente código:

for i in range(dist_matrix.shape[0]):
    for j in range(dist_matrix.shape[1]):
        if dist_matrix[i, j] == 1:
            adj_matrix[i, j] = 1
        else:
            adj_matrix[i, j] = 0

Pero usamos adj_matrix = np.where( dist_matrix == 1, 1, 0 )una oración en su lugar para reducir la complejidad del código.

Luego creamos el gráfico a través de la matriz de adyacencia:

demo_G = nx.from_numpy_array(adj_matrix, create_using = nx.Graph())
demo_G = nx.convert_node_labels_to_integers(demo_G, first_label = 1)

Hagamos un dibujo y podremos ver que la imagen resultante es la imagen que mencionamos anteriormente.

pos = nx.circular_layout(demo_G)
nx.draw_networkx(demo_G, pos)

Insertar descripción de la imagen aquí

En Python, si deseas obtener la matriz de distancias de un gráfico, puedes nx.all_pairs_shortest_path_length()obtenerla a través de la función. El valor de retorno de la función es un diccionario de adyacencia que contiene valores de distancia:

distanceDict = dict( nx.all_pairs_shortest_path_length(G) )
distanceDict
{1: {1: 0, 2: 1, 3: 1, 4: 1, 6: 2, 5: 2, 7: 3},
 2: {2: 0, 1: 1, 4: 1, 6: 1, 3: 2, 5: 2, 7: 2},
 3: {3: 0, 1: 1, 4: 1, 5: 1, 2: 2, 6: 2, 7: 2},
 4: {4: 0, 1: 1, 2: 1, 3: 1, 5: 1, 6: 1, 7: 2},
 5: {5: 0, 3: 1, 4: 1, 6: 1, 7: 1, 1: 2, 2: 2},
 6: {6: 0, 2: 1, 4: 1, 5: 1, 7: 1, 1: 2, 3: 2},
 7: {7: 0, 5: 1, 6: 1, 3: 2, 4: 2, 2: 2, 1: 3}}

Podemos generar una matriz de distancia atravesando los valores del diccionario y convertirla a un np.array()tipo familiar.

Aquí, debido a que los nombres de los nodos del gráfico son todos datos enteros, puede range()usar la función para recorrerlos directamente. Pero si el nombre del nodo es "A", "B", "C"un carácter como este, primero debe G.nodes()obtener el nombre del nodo a través de , convertirlo en una lista y luego recorrerlo. (Ya no se demuestra aquí)

n = len( distanceDict )
D_mat = np.zeros( (n, n) )
for node_i in range( 0, n ):
    for node_j in range( 0, n ):
        D_mat[node_i][node_j] = distanceDict[node_i + 1][node_j + 1]
D_mat
array([[0., 1., 1., 1., 2., 2., 3.],
       [1., 0., 2., 1., 2., 1., 2.],
       [1., 2., 0., 1., 1., 2., 2.],
       [1., 1., 1., 0., 1., 1., 2.],
       [2., 2., 1., 1., 0., 1., 1.],
       [2., 1., 2., 1., 1., 0., 1.],
       [3., 2., 2., 2., 1., 1., 0.]])

El diámetro de la red y la longitud media del camino de la red.

El diámetro de la red se define como la distancia máxima entre dos vértices cualesquiera de la red .

En pocas palabras, la distancia entre los dos puntos más lejanos de la red es el diámetro de la red.

Dado que la distancia se define como el número de aristas en el camino más corto , el diámetro de la red también es el número máximo de aristas en el camino más corto. Si ahora recorre la red en un círculo grande y luego especifica que este es el diámetro de la red, entonces esta definición es incorrecta. Esto se debe a que estás confundiendo la definición de distancia.

En NetWorkX, podemos utilizar nx.diameter()para obtener el diámetro de la red.

print( nx.diameter(G) )
3

La longitud promedio de la ruta de la red se define como la distancia promedio entre dos vértices cualesquiera de la red.

L = ∑ i > jdij CN 2 L = \dfrac{ \sum_{i \gt j}^{}{d_{ij}} }{ C_N^2 }l=Cnorte2yo > jdyo

Tenga en cuenta el CN ​​2 C_N^2 aquíCnorte2Quiere decir permutación y combinación.

Además, tenga en cuenta aquí: dado que la distancia se define como el número de bordes en el camino más corto , la longitud promedio del camino es en realidad el camino más corto promedio.

En Python, NetWorkX permite nx.average_shortest_path_length()obtener la longitud de ruta promedio.

print( nx.average_shortest_path_length(G) )
1.4761904761904763

Coeficiente de agrupamiento

En una red de amigos, es probable que dos de tus amigos sean amigos entre sí. Esta propiedad se denomina propiedad de agrupación de la red.

En lenguaje matemático, para un determinado nodo iii , su coeficiente de agrupamientoC i C_iCyoSe define como la relación entre el número de conexiones entre todos los nodos adyacentes y el número máximo posible de conexiones.

Específicamente, deje que el nodo iitengo kik_ikyoUn borde está conectado a él (es decir, el nodo iitengo kik_ikyovecinos), obviamente este nodo tiene como máximo C ki 2 C_{k_i}^{2}Ckyo2borde, supongamos que este ki k_ikyoEn realidad, hay E i E_i entre nodosmiyoSi los bordes están conectados, el coeficiente de agrupamiento C i = E i / C ki 2 C_i = E_i / C_{k_i}^2Cyo=miyo/ Ckyo2

El coeficiente de agrupamiento C de toda la red es el promedio de los coeficientes de agrupamiento de todos los nodos .

En una red aleatoria, C = p C = pC=p , (ya que la distribución de aristas es aleatoria)

En Python, puede utilizarlo networkx.clustering()para obtener el coeficiente de agrupamiento de cada nodo y utilizarlo networkx.average_clustering()para obtener el coeficiente de agrupamiento promedio.

print( "聚类系数:", nx.clustering(G) )
print( "平均聚类系数:", nx.average_clustering(G))
聚类系数: {1: 0.6666666666666666, 2: 0.6666666666666666, 3: 0.6666666666666666, 4: 0.5, 5: 0.5, 6: 0.5, 7: 1.0}
平均聚类系数: 0.6428571428571429

Modelo básico de topología de red y sus propiedades.

Introduzcamos las siguientes redes:

  • red regular
  • red aleatoria
  • Red Mundial Pequeña
  • Red libre de escala
  • red jerárquica

El módulo de Python networkx.random_graphsproporciona funciones para dibujar los siguientes gráficos. NOTA: Todos los gráficos aleatorios dibujados aquí producirán resultados diferentes cada vez que los dibuje.

Para conocer su uso, consulte este artículo: Cuatro modelos de red de teoría de grafos y herramienta de modelado de redes complejas Networkx

Luego, este artículo escribe la generación de cada red por sí mismo: Python implementa la generación de cuatro modelos de red, el cálculo del grado promedio y otros indicadores, y la visualización de funciones de distribución de grados.

red regular

Una red regular se refiere a una red de simetría traslacional, en la que el número de vecinos de cualquier punto de la red es el mismo .

Cada nodo tiene el mismo valor de grado.

La figura muestra la red de acoplamiento de vecinos más cercanos: cada nodo está conectado a K/2 nodos a su izquierda y derecha.

Insertar descripción de la imagen aquí

Los métodos se proporcionan en NetWorkX networkx.random_regular_graph(), lo que nos permite generar una red de reglas que satisfaga nuestras necesidades en un solo paso:

# 随机生成 20 个节点,每个节点的度都是 3
regular_G = nx.random_regular_graph(3, 30)
pos = nx.spectral_layout(regular_G)  # 根据图的拉普拉斯特征向量排列节点
nx.draw_networkx(regular_G, pos, with_labels = True )

Insertar descripción de la imagen aquí

Generalmente, las redes regulares tienen distancias promedio grandes pero mejor agregación .

print( "直径:", nx.diameter(regular_G) )
print( "平均路径长度:", nx.average_shortest_path_length(regular_G) )
print( "平均聚类系数:", nx.average_clustering(regular_G) )
直径: 6
平均路径长度: 3.1816091954022987
平均聚类系数: 0.06666666666666667

red aleatoria

Modelo de gráfico aleatorio ER: el valor de grado del vértice obedece a la distribución de Poisson, también llamado gráfico aleatorio de Poisson

La filosofía detrás de las redes aleatorias: colocar enlaces aleatoriamente entre nodos

El Apéndice 2 del artículo de Zhihu describe el modelo de red aleatoria y el modelo de mundo pequeño con relativamente detalle.

Proceso de construcción de la red:

  1. De NNComience con N nodos aislados;
  2. Seleccione un par de nodos y produzca un 0 00 a1 1Un número aleatorio entre 1 . Si el número aleatorio es menor que la probabilidad dadappp , coloque un enlace entre el par de nodos; de lo contrario, el par de nodos permanece desconectado;
  3. Para todos los pares de nodos (total N ( N − 1 ) 2 \dfrac{N(N-1)}{2}2norte ( norte1 )pares de nodos), repita el paso 2.

Simplemente podemos escribir la implementación de Python nosotros mismos: definimos la siguiente funciónrandom_matrix(N, p)

def random_matrix(N, p):
    import random
    import networkx as nx
    g = nx.Graph()
    for i in range(N):
        for j in range(i + 1, N):
            if random.random() < p:
                g.add_edge( i, j )
    return g

Aquí hay una explicación detallada del código:

Primero, random_matrixla función acepta dos parámetros: Ny p. El parámetro Nrepresenta el tamaño de la matriz que se generará, es decir, el número de nodos. El parámetro prepresenta la probabilidad de conectar dos nodos.

Se importan dos módulos a la función: randompara generar números aleatorios y networkxpara procesar estructuras de datos gráficos.

  • g = nx.Graph()Se crea un ggráfico vacío llamado .
  • Utilice bucles anidados para iterar sobre todos los pares posibles de nodos.
  • Para cada par de nodos (i, j), decida si desea agregar una arista entre ellos generando un número aleatorio entre 0 y 1.
  • Si el número aleatorio generado es menor que la probabilidad dada p, se agrega una arista entre nodo iy nodo .j
  • Devuelve el gráfico final generado g.

Al ajustar los valores de los parámetros Ny p, puede controlar el tamaño y la probabilidad de conexión del gráfico generado, obteniendo así diferentes tipos de gráficos aleatorios.

La red obtenida mediante el proceso anterior se denomina gráfico aleatorio o red aleatoria, también conocida como red Erdős-Rényi. Puedes usar G ( N , p ) G(N, p)GRAMO ( norte ,p ) para representar.

Podemos dibujar el gráfico que generamos para él:

random_model_G = random_matrix( 30, 0.2 )
pos = nx.spectral_layout(random_model_G)  # 根据图的拉普拉斯特征向量排列节点
nx.draw_networkx(random_model_G, pos, with_labels = True)

Insertar descripción de la imagen aquí

Por supuesto, NetWorkX también nos ha proporcionado métodos de interfaz listos para usar nx.erdos_renyi_graph(N, p)que se pueden llamar directamente.

# 随机生成 30 个节点,节点间的连接概率都是 0.2
random_G = nx.erdos_renyi_graph(30, 0.2)
pos = nx.spectral_layout(random_G)  # 根据图的拉普拉斯特征向量排列节点
nx.draw_networkx(random_G, pos, with_labels = True)

Insertar descripción de la imagen aquí

Luego, echemos un vistazo a los diversos parámetros indicadores de la red aleatoria. (Si se vuelve a ejecutar el código anterior para generar el gráfico, los indicadores siguientes también cambiarán en consecuencia. ¡La generación del gráfico es completamente aleatoria!)

print( "直径:", nx.diameter(random_G) )
print( "平均路径长度:", nx.average_shortest_path_length(random_G) )
print( "平均聚类系数:", nx.average_clustering(random_G) )
直径: 4
平均路径长度: 2.197701149425287
平均聚类系数: 0.24142857142857144

Las redes aleatorias son el otro extremo. por NNEn un gráfico compuesto por N vértices, CN 2 C_N^2Cnorte2bordes, desde los cuales conectamos aleatoriamente MMLa red compuesta por M aristas se llama red aleatoria.

Otra forma de generar una red aleatoria es dar una probabilidad ppp , paraCN 2 C_N^2Cnorte2Cualquiera de ellos puede estar conectado, lo intentamos nuevamente con probabilidad ppconexión p . Si elegimosM = p CN 2 M = p C_N^2METRO=pag Cnorte2Estos dos modelos de red estocástica se pueden vincular.

Por ejemplo: coeficiente de agrupamiento generado por Pajek: C = p ≪ 1 C = p \ll 1C=pag1 (debido a la extrema escasez)

En general, las redes aleatorias tienen distancias promedio pequeñas; pero al mismo tiempo, la agrupación será peor. .

¿Existe una pequeña red de ruta más corta con un alto grado de agregación al mismo tiempo?

Esta cuestión tiene un significado práctico muy profundo.

  • Para el modelo de enfermedades infecciosas, el grado de aglomeración promedio corresponde a la amplitud de la transmisión, y la distancia más corta promedio representa la profundidad de la transmisión.

  • Por lo tanto, si la red real tiene gran amplitud y profundidad, la propagación de enfermedades infecciosas en dicha red será obviamente mucho mayor que la de las redes regulares y aleatorias.

pequeña red mundial

En 1998, Watts y Strogatz encontraron un modelo de red de este tipo: la red Small World (publicada en Nature)

Ahora a menudo se llama: modelo WS

Método: Watts y Strogatz descubrieron que sólo se necesitan unos pocos cambios aleatorios en la red normal para poseer las dos propiedades anteriores al mismo tiempo.

El método de modificación es: para todos los bordes de cada vértice de la red regular, con probabilidad ppp desconecta un punto final y lo vuelve a conectar. El nuevo punto final conectado se selecciona aleatoriamente de otros vértices en la red; si el vértice seleccionado ya está conectado a este vértice, entonces se seleccionan aleatoriamente otros vértices para reconectarse.

cuando p = 0 p = 0pag=Cuando 0 , lo que se genera es una red regular,p = 1 p=1pag=1 es una red aleatoria. Para0 < p < 1 0 \lt p \lt 10<pag<En el caso de 1 , hay una gran cantidadde pp.El área de p tiene un grado de agregación grande y una distancia mínima pequeña.

Insertar descripción de la imagen aquí

  • Mecanismo de formación: red regular, con probabilidad pp .p desconecta un punto final y se conecta aleatoriamente

Python se puede utilizar watts_strogatz_graph(N, k, p)para crear modelos WS aleatorios.

#生成一个含有 30 个节点、每个节点有 6 个邻居
# 以概率 p = 0.5 随机化重连边的WS小世界网络
smallworld_G = nx.watts_strogatz_graph(30, 6, 0.5)
pos = nx.spectral_layout(smallworld_G)  # 根据图的拉普拉斯特征向量排列节点
nx.draw_networkx(smallworld_G, pos, with_labels = True)

Insertar descripción de la imagen aquí

print( "直径:", nx.diameter(smallworld_G) )
print( "平均路径长度:", nx.average_shortest_path_length(smallworld_G) )
print( "平均聚类系数:", nx.average_clustering(smallworld_G) )
直径: 4
平均路径长度: 2.0597701149425287
平均聚类系数: 0.2635714285714286

Red Mundial Pequeña del Noroeste

El proceso de construcción del modelo WS puede destruir la conectividad de la red.

En 1999, Newman y Watts propusieron el modelo NW: reemplazar la "reconexión aleatoria" por la "adición de bordes aleatoria".

Me referí a este blog: Implementación del código Python del modelo de red NW Small World y cálculo del coeficiente de agrupamiento de rutas promedio

El algoritmo de construcción específico de la red NW Small World es el siguiente

  • Comience con un diagrama de reglas

Dada una red de acoplamiento de vecino más cercano en forma de anillo que contiene N nodos, cada nodo está conectado a K/2 nodos adyacentes a su izquierda y derecha, donde K es un número par.

  • Aleatorizar los bordes

Agregue aristas entre pares de nodos NK/2 seleccionados aleatoriamente con probabilidad p, que estipula que no hay aristas duplicadas ni bucles automáticos. Cuando p = 0, tanto el modelo WS como el modelo NW corresponden a la red de acoplamiento del vecino más cercano original; cuando p = 1, el modelo WS es equivalente a un gráfico aleatorio y el modelo NW es equivalente a una red de acoplamiento del vecino más cercano regular. basado en Superponer un gráfico aleatorio con un cierto número de aristas. Cuando p es lo suficientemente pequeño y N es lo suficientemente grande, el modelo WS y el modelo NW pueden considerarse equivalentes.

El blog proporciona el código para generar la red, pero cuando lo escribí según ese código, descubrí que era un bucle infinito. Pasé los parámetros (30, 6, 0.2)y funcionó durante varios minutos sin parar. De todos modos, no lo entiendo del todo, es solo que es bastante extraño.

No hay mucha información sobre esto en Internet nacional, después de la búsqueda, solo hay estas dos oraciones que describen el método de construcción de este modelo. Lo escribí según mi propio entendimiento:

def NW_network(N, K, p):
    import random
    import networkx as nx
    g = nx.random_graphs.random_regular_graph( int(K / 2), int(N) )
    for i in range(N): # 遍历:增加边时的起始节点
        for j in range(i + 1, N): # 遍历:增加边时的中止节点节点
            if random.random() < p: # 如果随机数小于概率 p 
                g.add_edge( i, j )  # 那就增加一条边
    return g

Esta es una función simple, que se divide en tres pasos:

  1. Introducir dos bibliotecas: aleatoria y networkx
  2. Llame para nx.random_graphs.random_regular_graph( int(K / 2), int(N) )crear una red de acoplamiento de vecino más cercano en forma de anillo que contenga N nodos, donde cada nodo está conectado a sus K/2 nodos adyacentes a la izquierda y a la derecha.
    • Por si acaso, aquí se explica cómo convertirlo a int()tipo.
  3. Agregue aristas entre pares de nodos NK/2 seleccionados aleatoriamente y agregue aristas si el valor de probabilidad generado aleatoriamente es menor que p. Evite los bucles automáticos mediante el diseño de bucles anidados

Llamemos a la función para ver el efecto:

NWmodel_G = NW_network( 30, 6, 0.2 )
# pos = nx.spectral_layout(NWmodel_G)  # 根据图的拉普拉斯特征向量排列节点
pos = nx.spectral_layout(NWmodel_G)
nx.draw_networkx(NWmodel_G, pos, with_labels = True)

Insertar descripción de la imagen aquí

Hmm, parece estar funcionando normalmente (?) Yo tampoco estoy seguro.

Echemos un vistazo a los parámetros de este modelo.

print( "直径:", nx.diameter(NWmodel_G) )
print( "平均路径长度:", nx.average_shortest_path_length(NWmodel_G) )
print( "平均聚类系数:", nx.average_clustering(NWmodel_G) )
直径: 3
平均路径长度: 1.7563218390804598
平均聚类系数: 0.2531649831649832

Hay muchos modelos mejorados: agregar puntos, agregar aristas, eliminar puntos, eliminar aristas,

y la intersección de diferentes formas, lo que resulta en múltiples formas de modelos de mundos pequeños

Red libre de escala

El grado de nodo obedece a la distribución de la ley de potencias , lo que significa que la relación entre el número de nodos con un cierto grado y el grado específico se puede expresar aproximadamente mediante una función de potencia:

P ( k ) ∼ k − γ P(k) \sim k^{- \gamma}P ( k )k−c _

donde, P (k) P(k)P ( k ) es de gradokkLa probabilidad de que aparezca el nodo k ,γ \gammaγ es el exponente de la ley de potencia.

En esta fórmula, kkk representa el grado del nodo, yP ( k ) P(k)P ( k ) significa tener gradokkLa probabilidad de que aparezca el nodo k .

La distribución de la ley de potencia muestra que para grados mayores kkLa probabilidad de que aparezca el nodo correspondiente a k es menor y el grado menorkkEl nodo correspondiente a k tiene mayor probabilidad de aparecer.

La distribución de la ley de potencias tiene las siguientes características:

  1. Propiedad de cola larga: la distribución de ley de potencia es una distribución de cola larga, es decir, dentro de un rango de grados mayor, la probabilidad de que aparezca un nodo disminuye exponencialmente. Esto significa que hay una pequeña cantidad de nodos extremadamente conectados que tienen más conexiones que la mayoría de los demás nodos.

  2. Ilimitación: la distribución de la ley de potencia es teóricamente ilimitada, es decir, en teoría puede haber nodos altamente conectados. Sin embargo, en las redes reales, suele haber un límite superior o valor de corte debido a factores limitantes (como recursos, limitaciones físicas, etc.).

  3. Exponente de la ley de potencia γ \gammaγ : Exponente de la ley de potenciaγ \gammaγ es un parámetro importante que determina la forma de la distribución de la ley de potencia. γ \gammamás pequeñoLos valores de γ representan una distribución de ley de potencia más pronunciada yγ \gammaLos valores de γ representan una distribución de ley de potencia más plana.

Los principios matemáticos anteriores son relativamente complicados, pero podemos explicar simplemente este problema desde las siguientes dos perspectivas más intuitivas:

  1. Principio de “los ricos se hacen más ricos” : en redes sin escala, es más probable que los nodos con grados más altos sean seleccionados como vecinos de nuevos nodos . Esto se debe a que estos nodos altamente conectados ya tienen una gran cantidad de oportunidades de conexión y, debido a su alta conectividad, es más probable que otros nodos recién unidos los seleccionen como vecinos. Por tanto, estos nodos centrales tienden a atraer más conexiones, haciendo que su grado siga creciendo.
  2. Aleatoriedad en el crecimiento de la red : las redes sin escala generalmente se construyen agregando gradualmente nuevos nodos y conexiones. En este proceso, el nodo recién agregado seleccionará aleatoriamente algunos nodos existentes como vecinos. Debido a la existencia de aleatoriedad, es más probable que se seleccionen nodos con grados más altos porque tienen más oportunidades de conectarse. Esta aleatoriedad también contribuye a una distribución de ley de potencia.

La curva de función de potencia es una curva que disminuye relativamente lentamente, lo que permite que existan muchos nodos en la red.

Para redes aleatorias y redes regulares, el intervalo de distribución de grados es muy estrecho y es casi imposible encontrar un punto que se desvíe mucho del grado promedio de nodo, por lo que su grado promedio puede considerarse como una escala característica de su grado de nodo . En este sentido, llamamos a las redes cuyos grados de nodo obedecen a una distribución de ley de potencia redes libres de escala , y llamamos a esta distribución de grados de nodo de ley de potencia las características libres de escala de la red .

Para esto, consulte el artículo de Zhihu ¿ Qué es una red sin escala? | Enciclopedia JiZhi

Podemos escribir una implementación de función nosotros mismos según la definición anterior:

def SF_network(N, k):
    import networkx as nx
    import random
    g = nx.Graph()
    g.add_edge(0, 1)  # 初始情况下至少需要两个节点
    N = N - 2 # 因为我们已经给定了初始的两个节点,所以总节点数减去 2
    for i in range(2, N):
        node_list = list(g.nodes())
        degrees = [g.degree(node) for node in node_list]
        probabilities = [degree / sum(degrees) for degree in degrees]
        selected_nodes = random.choices(node_list, probabilities, k = k)
        for node in selected_nodes:
            g.add_edge(i, node)
    
    return g

Déjame explicarte este código en detalle:

Usamos networkxla biblioteca para crear y manipular objetos gráficos. El código primero crea un objeto gráfico vacío Gy luego agrega dos nodos iniciales. A continuación, a partir del tercer nodo, se agrega un nuevo nodo cada vez y los nodos existentes se seleccionan aleatoriamente para conectarse hasta alcanzar el número especificado de nodos N. El número de conexiones que cada nuevo nodo tiene con los nodos existentes está kcontrolado por el parámetro.

A continuación, degrees = [g.degree(node) for node in node_list]calcula el grado de cada nodo y almacena estos grados en una lista degrees.

Luego calcule la probabilidad de que se seleccione cada nodo:probabilities = [degree / sum(degrees) for degree in degrees]

probabilitieses una lista que almacena la probabilidad de que cada nodo sea seleccionado para conectarse a un nuevo nodo. La probabilidad de que cada nodo sea seleccionado para conectarse a un nuevo nodo es igual al grado actual del nodo dividido por el grado total de toda la red.

  • En otras palabras: para cada nodo, dividimos su grado por el grado total de todos los nodos para obtener un valor de probabilidad, que es la probabilidad de que se seleccione cada nodo.

  • De esta manera, los nodos con mayor grado tienen una mayor probabilidad de selección y, por lo tanto, es más probable que se conviertan en nodos recién conectados a la red. De esta forma se consigue la distribución de grados que simula la distribución de potencia.

  • En concreto, en una red sin escala, cada vez que se añade un nuevo nodo, se establecen conexiones con algunos nodos que ya existen. Según el principio de "conexión preferencial", es decir, es más probable que los nodos con grados más altos sean seleccionados como vecinos de nuevos nodos. Al calcular la probabilidad de que se seleccione cada nodo y almacenarlo en la lista de probabilidades, podemos seleccionar aleatoriamente nodos vecinos en función de estas probabilidades.

Utilice random.choicesla función para seleccionar m nodos objetivo de los nodos existentes según la probabilidad y almacene estos nodos objetivo en una lista selected_nodes.

Finalmente, iteramos sobre la lista de nodos de destino y usamos g.add_edgela función para agregar un borde al gráfico que conecta el nuevo nodo con el nodo de destino. Una vez finalizado el ciclo, devolvemos el objeto de red sin escala resultante g.

Generemos el dibujo del código y veamos el efecto. Como puedes ver, esta es la red sin báscula Scale Free que queremos

scaleFree_G = SF_network( 30, 1 )
pos = nx.spring_layout(scaleFree_G)  # 根据图的拉普拉斯特征向量排列节点
nx.draw_networkx(scaleFree_G, pos, with_labels = True)

Insertar descripción de la imagen aquí

Si aún no comprende lo que hace el código anterior, ¿por qué no dejar que el código genere las variables de cada paso del ciclo y observar más de cerca cómo funciona este proceso?

Primera ronda de bucle:

node list : [0, 1]
degrees : [1, 1]
probabilities : [0.5, 0.5]
selected nodes : [0]

Como puede ver, este ciclo comienza con dos nodos iniciales 0 y 1. Inicialmente, los dos nodos están configurados para estar conectados entre sí, por lo tanto, los grados de ambos nodos son 1 11 .

En este momento, el grado total de toda la red es 2 22 , ya que1/2 = 0,5 1/2 = 0,51/2=0,5 , por lo que en este momento la probabilidad de que los dos nodos estén conectados al nodo recién generado es1/2 1/21/2 .

Segunda ronda del bucle:

node list : [0, 1, 2]
degrees : [2, 1, 1]
probabilities : [0.5, 0.25, 0.25]
selected nodes : [2]

En el segundo ciclo, se agrega aquí un nuevo nodo 2.

El nuevo nodo 2 se agrega al gráfico de red al final del primer ciclo. A juzgar por los resultados de salida, el grado del nodo 0 es 2. Significa que el nodo 0 solo está conectado a dos nodos en este momento. Solo hay 3 nodos en total en el gráfico, por lo que al final del primer ciclo, el resultado del juicio de probabilidad debería ser que el nuevo nodo 1 se agregue al nodo 0.

Acabo de hablarles de los nodos aquí. La probabilidad de aumento sigue el principio de "los ricos se hacen más ricos". En este caso, el nodo 0 tiene un mayor número de posesiones que otros nodos. Por lo tanto, el nodo 0 se conecta al nuevo nodo La probabilidad también es mayor que la de otros nodos. Como se puede ver en los números a continuación, la probabilidad de que el nodo 0 se conecte a un nuevo nodo aquí es 0,5, mientras que otros nodos son solo 0,25.

Tercera ronda de bucle:

node list : [0, 1, 2, 3]
degrees : [2, 1, 2, 1]
probabilities : [0.3333333333333333, 0.16666666666666666, 0.3333333333333333, 0.16666666666666666]
selected nodes : [2]

Se puede ver que en el tercer ciclo aquí, se agrega un nuevo nodo 3. A juzgar por el grado de cada nodo, el nodo 3 recién agregado está conectado al nodo 2 que apareció originalmente al final de la primera ronda del ciclo. En este caso, el grado total de toda la imagen se convierte en 2 + 1 + 2 + 1 = 6 2+1+2+1 = 62+1+2+1=6. Al dividir el grado de cada nodo por este 6, se calcula la posibilidad de que cada nodo se conecte al siguiente nodo nuevo en el siguiente ciclo, y así sucesivamente, en secuencia.

Por supuesto, Python proporciona directamente un método para generar redes BA sin escala. Para demostrar mejor las características de la red Scale Free, configuro el diseño de la red enspring_layout()

#生成一个含有 20 个节点、每次加入 1 条边的 BA 无标度网络。
BAscalefree_G = nx.barabasi_albert_graph(30, 1)
pos = nx.spring_layout(BAscalefree_G)  # 根据图的拉普拉斯特征向量排列节点
nx.draw_networkx(BAscalefree_G, pos, with_labels = True)

Insertar descripción de la imagen aquí

print( "直径:", nx.diameter(BAscalefree_G) )
print( "平均路径长度:", nx.average_shortest_path_length(BAscalefree_G) )
print( "平均聚类系数:", nx.average_clustering(BAscalefree_G) )
直径: 4
平均路径长度: 2.52183908045977
平均聚类系数: 0.0

Para resumir los métodos de dibujo de Python mencionados anteriormente:

Tipo de red Método de dibujo parámetro
red regular gráfico_regular_aleatorio (grado, número de nodos)
red aleatoria erdos_renyi_grafo (número de nodos, probabilidad de conexión)
pequeña red mundial watts_strogatz_graph (número de nodos, vecinos, probabilidad de reconexión)
red sin escala barabasi_albert_graph (número de nodos, número de aristas agregadas cada vez)

Luego podemos juntar las cuatro redes y compararlas:

fig, axes = plt.subplots(2, 2, figsize = (12, 10))
axes[0][0].set_title("规则网络")
G_1 = nx.random_regular_graph(3, 20)
pos = nx.spectral_layout(G_1) 
nx.draw_networkx(G_1, pos, with_labels = True, ax = axes[0][0])
axes[1][0].set_title("随机网络")
G_2 = nx.erdos_renyi_graph(20, 0.2)
pos = nx.spectral_layout(G_2) 
nx.draw_networkx(G_2, pos, with_labels = True, ax = axes[1][0])
axes[0][1].set_title("小世界网络")
G_3 = nx.watts_strogatz_graph(20, 4, 0.1)
pos = nx.spectral_layout(G_3) 
nx.draw_networkx(G_3, pos, with_labels = True, ax = axes[0][1])
axes[1][1].set_title("无标度网络")
G_4 = nx.barabasi_albert_graph(20, 1)
pos = nx.pos = nx.spectral_layout(G_4) 
nx.draw_networkx(G_4, pos, with_labels = True, ax = axes[1][1])

Insertar descripción de la imagen aquí

Desarrollo y aplicación de la teoría de redes complejas.

Una breve historia de la investigación de redes complejas

tiempo (año) cifra evento
1736 Euler Problema de los siete puentes
1959 Erdos Kazu Renyi teoría de grafos aleatorios
1967 milgram experimento del pequeño mundo
1973 Granovetter La fuerza de una conexión débil
1998 Watts y Strogatz modelo de mundo pequeño
1999 Barrabás y Alberto red sin escala

Las principales razones del gran avance en la investigación de redes complejas a principios de siglo incluyen:

  1. Los dispositivos informáticos cada vez más potentes y el rápido desarrollo de Internet han permitido a las personas recopilar y procesar diferentes tipos de datos de red reales a gran escala. (El tamaño de la red estudiado en el pasado era demasiado pequeño)
  2. La intersección entre disciplinas permite a los investigadores comparar ampliamente varios tipos de datos de redes para revelar los puntos en común de redes complejas.
  3. El auge de la ciencia de la complejidad, que presenta una combinación de reduccionismo y holismo, también ha impulsado a la gente a comenzar a estudiar la relación entre la estructura y el desempeño de las redes en su conjunto.

Descubrimiento: descubrir las propiedades estadísticas que caracterizan la estructura de los sistemas de red y los métodos apropiados para medir estas propiedades.

Modelado: establecer modelos de red apropiados para ayudar a las personas a comprender el significado y el mecanismo de generación de estas propiedades estadísticas.

Análisis: analice y prediga el comportamiento de la red en función de las características de los nodos individuales y las propiedades estructurales de toda la red.

Control: Proponer métodos eficaces para mejorar el rendimiento de las redes existentes y diseñar nuevas redes, especialmente en términos de estabilidad, sincronización y flujo de datos.

Desde 2002, los investigadores nacionales y jóvenes académicos de diferentes disciplinas se han interesado cada vez más en la investigación de redes complejas. Hasta ahora, se han celebrado en China muchas conferencias y foros académicos sobre el tema de las redes complejas.

En abril de 2004, se organizó en Wuxi el primer Foro Académico de la Red Dinámica Compleja Nacional con más de 40 participantes.

La Universidad de Wuhan fue la primera en China en establecer un centro de investigación de redes complejas a nivel escolar y organizó la Conferencia Académica Nacional de Redes Complejas en la primavera de 2005.

En octubre de 2005 se celebró en Beijing el Segundo Foro Académico de la Red Compleja Nacional, organizado por el Centro de Investigación Académica Avanzada de China.

Algunas universidades de renombre internacional (como el MIT, la Universidad de Columbia y la Universidad de Michigan, etc.) han abierto sucesivamente cursos sobre redes complejas. El profesor Wang Xiaofan también abrió un curso sobre redes complejas para estudiantes de posgrado en la Universidad Jiao Tong de Shanghai.

Desafíos enfrentados

Fang Jinqing del Instituto Chino de Energía Atómica enumeró:

Uno de los desafíos: es urgente explorar en teoría los modelos matemáticos y físicos de redes dinámicas complejas y establecer marcos teóricos precisos, como la teoría de la preferencia híbrida unificada, la teoría de los seis grados de separación, las propiedades sin escala y las propiedades de múltiples escalas. y características de superfamilia, así como redes de información cuántica, etc. Este es un problema importante al que se enfrenta el desarrollo de redes.

Problema desafiante 2: explorar métodos aleatorios, métodos deterministas, varios métodos híbridos y las relaciones de transformación mutua de diferentes características de la red, para construir redes complejas que cumplan con los requisitos prácticos y las aplicaciones de ingeniería.

Tercera pregunta desafiante: si existen propiedades dinámicas universales en redes complejas, si hay más leyes de distribución estadística y leyes no estadísticas, si hay propiedades ricas en escala en redes complejas a gran escala y cuáles son las conexiones intrínsecas entre ellas.

Problema desafiante 4: Estudiar la complejidad espacio-temporal de los procesos dinámicos en redes complejas dinámicas no lineales y sus principales manifestaciones, incluyendo: bifurcación, caos, caos paroxístico, etc., y sus diversas formas bajo la misma y diferente dinámica de nodo. Sincronización generalizada. Sincronización Problemas de análisis, control y sincronización del mecanismo de generación.

Problema desafiante 5: Explorar la evolución no lineal de diferentes tipos de redes y el surgimiento de patrones espaciotemporales

Pregunta desafiante 6: Cómo describir mecanismos físicos complejos, por qué las características topológicas de las redes sociales son muy diferentes de las redes técnicas y las redes biológicas

Pregunta desafiante 7: Cómo desarrollar métodos de análisis cuantitativos y cualitativos para las cantidades características de las propiedades básicas de las redes dinámicas. No solo se necesitan descripciones geométricas, sino que se necesitan más descripciones, como físicas e información, para caracterizar eficazmente las principales características de las redes dinámicas complejas. redes.

Asunto desafiante No. 8: Mayor investigación y desarrollo de teorías estocásticas y deterministas generalizadas, métodos de teoría cruzada, métodos de teoría estadística de no equilibrio, métodos de teoría de cambio de fase, métodos de teoría del condensado de Bose-Einstein, etc., para avanzar en la complejidad general de In- investigación en profundidad sobre redes dinámicas

Asunto desafiante número 9: Investigación de aplicaciones de redes dinámicas complejas. Cómo aplicar los resultados de la investigación de redes complejas a los campos actuales de ingeniería y defensa nacional de mi país (como redes de comunicación inalámbricas ad hoc, etc.) lo antes posible. la necesidad de una investigación en profundidad en este campo, las necesidades urgentes y el impulso para un mayor desarrollo

Problema desafiante n.° 10: investigación sobre redes biológicas complejas

Supongo que te gusta

Origin blog.csdn.net/BOXonline1396529/article/details/132907253
Recomendado
Clasificación