# analisis-de-grafos-en-python-y-networkx
Análisis de Grafos en Python y NetworkX
Volver a la portada del cursoManipulación Avanzada de Grafos
Sección 3 · Manipulación de Grafos en Python
Notebook: manipulación avanzada de grafos
En el video anterior construiste la red de productos de PyShop a partir de los pedidos. En este notebook la manipulas: lees y escribes atributos, recortas subgrafos, filtras aristas por peso, renombras nodos, combinas grafos, guardas la red en disco y trabajas con un grafo dirigido. Esta guía acompaña al notebook manipulacion-avanzada-de-grafos y te dice qué buscar en cada sección y qué resultados debes obtener.
Objetivos
- Consultar y usar atributos de nodos y aristas.
- Extraer subgrafos con
subgraph,ego_graphyk_core. - Filtrar aristas por peso y entender cómo cambia la red con el umbral.
- Distinguir una vista de una copia.
- Renombrar nodos, combinar grafos y guardarlos en GraphML o como lista de aristas.
- Recorrer un
DiGraphcon sucesores, predecesores y componentes fuertes.
1. Datos y atributos
La primera celda copia datos.py; el notebook es autocontenido. Cada nodo tiene el atributo categoria y cada arista el atributo weight:
G = red_productos()
print(G.nodes["laptop"]) # {'categoria': 'computo'}
print(G.edges["laptop", "mouse"]) # {'weight': 134}
cat = nx.get_node_attributes(G, "categoria")
print(Counter(cat.values()))
El conteo da celulares 7, computo 7, cocina 7, hogar 6, deportes 6, audio 5 y accesorios 3 (los tres productos puente). G.nodes(data=True) y G.edges(data=True) devuelven todos los atributos a la vez.
2. Subgrafos
Un subgrafo conserva un conjunto de nodos y las aristas entre ellos. Con los 7 productos de cómputo:
computo = [n for n, c in cat.items() if c == "computo"]
S = G.subgraph(computo)
print(S.number_of_nodes(), S.number_of_edges()) # 7 16
print(round(nx.density(S), 3)) # 0.762
La densidad del grupo es 0.762, contra 0.166 de la red completa: dentro de una categoría casi todo se compra con todo. Dos recortes más:
nx.ego_graph(G, "cafetera")devuelve la cafetera y sus vecinos: 9 nodos y 26 aristas, entre ellos foco inteligente, lámpara de escritorio y termo. Conradius=2crece a 21 nodos y 64 aristas.nx.k_core(G, 4)conserva el subgrafo donde todo nodo tiene al menos 4 vecinos dentro de él: 34 nodos y 124 aristas. Quedan fuera cuchillos, mochila para laptop, organizador, power bank, reloj deportivo, tabla para picar y tocadiscos. El núcleo más alto,core_number7, lo forman 8 productos: 5 de celulares, 2 de audio y el cable usb-c.
3. Filtrar por peso
Para quedarte solo con los pares que se compran muy seguido, filtra las aristas:
fuertes = [(a, b) for a, b, w in G.edges(data="weight") if w >= 100]
F = G.edge_subgraph(fuertes)
print(F.number_of_nodes(), F.number_of_edges()) # 20 19
print(nx.number_connected_components(F)) # 6
Quedan 19 aristas entre 20 productos, repartidas en 6 grupos sueltos. La más fuerte une audífonos inalámbricos con audífonos de diadema (186 pedidos). edge_subgraph descarta los nodos que se quedan sin aristas; si en lugar de eso copias la red y borras las aristas débiles con remove_edges_from, los 41 nodos se conservan y aparecen 27 componentes, la mayoría nodos sueltos. Elige según la pregunta.
4. Componentes y el efecto del umbral
Con el umbral de 25 la red tiene 2 componentes: una de 40 productos y cuchillos, aislado. El notebook reconstruye la red con varios mínimos:
| Mínimo de pedidos | Aristas | Densidad | Componentes |
|---|---|---|---|
| 1 | 594 | 0.724 | 1 |
| 10 | 243 | 0.296 | 1 |
| 25 | 136 | 0.166 | 2 |
| 40 | 91 | 0.111 | 6 |
| 60 | 48 | 0.059 | 16 |
Con mínimo 1 casi todo se conecta con todo y no se distingue nada; con 60 la red se rompe en 16 pedazos. El 25 deja una red con estructura y casi toda conectada.
5. Vistas y copias
G.subgraph(...) no copia datos: es una vista de solo lectura. Si intentas S.add_node("x") obtienes NetworkXError: Frozen graph can't be modified. Para modificar un subgrafo, primero S.copy(). La ventaja de la vista es que no duplica memoria y refleja los cambios del grafo original.
6. Renombrar y combinar
nx.relabel_nodes(G, {n: n.upper() for n in G})devuelve una red con los nombres en mayúsculas;"laptop"ya no existe en ella.nx.convert_node_labels_to_integers(G, label_attribute="nombre")numera los nodos de 0 a 40 y guarda el nombre original como atributo: el nodo 0 es{'categoria': 'celulares', 'nombre': 'celular gama media'}.nx.compose(A, B)une dos grafos y fusiona los nodos con el mismo nombre.nx.union(A, B)exige que no compartan nodos: si los comparten lanzaNetworkXErrory sugiererenameodisjoint_union.
7. Guardar y leer
nx.write_graphml(G, "red.graphml")
H = nx.read_graphml("red.graphml")
print(H.number_of_nodes(), H.number_of_edges()) # 41 136
nx.write_weighted_edgelist(G, "red.txt", delimiter=";")
E = nx.read_weighted_edgelist("red.txt", delimiter=";")
print(E.number_of_nodes(), E.number_of_edges()) # 40 136
GraphML conserva los atributos y el nodo aislado. La lista de aristas pierde a cuchillos, porque un nodo sin aristas no aparece en ninguna línea, y pierde la categoría. Usa GraphML para guardar la red completa y la lista de aristas para intercambiar datos simples.
8. Grafo dirigido
El notebook arma el DiGraph de ejemplo Ana→Beto, Ana→Caro, Beto→Caro, Caro→Dani, Dani→Ana y Eva→Caro. D.successors("Ana") da Beto y Caro; D.predecessors("Caro") da Ana, Beto y Eva, así que el grado de entrada de Caro es 3 y el de Eva, 0. El grafo es débilmente conexo, pero no fuertemente conexo: sus componentes fuertes son {Ana, Beto, Caro, Dani} y {Eva}, porque nadie llega a Eva. D.to_undirected() lo convierte en un grafo de 6 aristas.
Qué debes obtener
Subgrafo de cómputo con 7 nodos, 16 aristas y densidad 0.762; ego de la cafetera con 9 nodos y 26 aristas; 4-core de 34 nodos; 19 aristas con peso de al menos 100; GraphML con 41 nodos y la lista de aristas con 40. Si tus números difieren, revisa la semilla (semilla=42) y el umbral (minimo=25). Como práctica, calcula el ego de radio 1 del cable usb-c y compara su densidad con la del subgrafo de cómputo.