Soy nuevo usando Python para trabajar con gráficos: NetworkX. Hasta ahora he usado Gephi. Allí los pasos estándar (pero no los únicos posibles) son:
Cargue la información de los nodos desde una tabla/hoja de cálculo; una de las columnas debe ser ID y el resto son metadatos sobre los nodos (los nodos son personas, por lo tanto, género, grupos... normalmente para colorear). Me gusta:
id;NormalizedName;Gender per1;Jesús;male per2;Abraham;male per3;Isaac;male per4;Jacob;male per5;Judá;male per6;Tamar;female ...
Luego cargue los bordes también desde una tabla/hoja de cálculo, usando los mismos nombres para los nodos que estaban en la ID de columna de la hoja de cálculo de nodos con normalmente cuatro columnas (Objetivo, Origen, Peso y Tipo):
Target;Source;Weight;Type per1;per2;3;Undirected per3;per4;2;Undirected ...
Estos son los dos marcos de datos que tengo y que quiero cargar en Python. Leyendo sobre NetworkX, parece que no es posible cargar dos tablas (una para nodos, otra para bordes) en el mismo gráfico y no estoy seguro de cuál sería la mejor manera:
¿Debo crear un gráfico solo con la información de los nodos del DataFrame y luego agregar (agregar) los bordes del otro DataFrame? Si es así y dado que nx.from_pandas_dataframe() espera información sobre los bordes, supongo que no debería usarlo para crear los nodos... ¿Debería simplemente pasar la información como listas?
¿Debo crear un gráfico solo con la información de los bordes del DataFrame y luego agregar a cada nodo la información del otro DataFrame como atributos? ¿Hay una mejor manera de hacerlo que iterar sobre el DataFrame y los nodos?
Cree el gráfico ponderado a partir de la tabla de bordes usando nx.from_pandas_dataframe
:
import networkx as nx import pandas as pd edges = pd.DataFrame({'source' : [0, 1], 'target' : [1, 2], 'weight' : [100, 50]}) nodes = pd.DataFrame({'node' : [0, 1, 2], 'name' : ['Foo', 'Bar', 'Baz'], 'gender' : ['M', 'F', 'M']}) G = nx.from_pandas_dataframe(edges, 'source', 'target', 'weight')
Luego agregue los atributos de nodo de los diccionarios usando set_node_attributes
:
nx.set_node_attributes(G, 'name', pd.Series(nodes.name, index=nodes.node).to_dict()) nx.set_node_attributes(G, 'gender', pd.Series(nodes.gender, index=nodes.node).to_dict())
O itere sobre el gráfico para agregar los atributos del nodo:
for i in sorted(G.nodes()): G.node[i]['name'] = nodes.name[i] G.node[i]['gender'] = nodes.gender[i]
A partir de nx 2.0
, el orden de los argumentos de nx.set_node_attributes
ha cambiado : (G, values, name=None)
Usando el ejemplo de arriba:
nx.set_node_attributes(G, pd.Series(nodes.gender, index=nodes.node).to_dict(), 'gender')
Y a partir de nx 2.4
, G.node[]
se reemplaza por G.nodes[]
.
Esta es básicamente la misma respuesta, pero actualizada con algunos detalles completos. Comenzaremos básicamente con la misma configuración, pero aquí no habrá índices para los nodos, solo nombres para abordar el comentario de @LancelotHolmes y hacerlo más general:
import networkx as nx import pandas as pd linkData = pd.DataFrame({'source' : ['Amy', 'Bob'], 'target' : ['Bob', 'Cindy'], 'weight' : [100, 50]}) nodeData = pd.DataFrame({'name' : ['Amy', 'Bob', 'Cindy'], 'type' : ['Foo', 'Bar', 'Baz'], 'gender' : ['M', 'F', 'M']}) G = nx.from_pandas_edgelist(linkData, 'source', 'target', True, nx.DiGraph())
Aquí, el parámetro True
le dice a NetworkX que mantenga todas las propiedades en linkData como propiedades de enlace. En este caso, lo convertí en un tipo DiGraph
, pero si no lo necesita, puede convertirlo en otro tipo de manera obvia.
Ahora, dado que necesita hacer coincidir los datos de nodo con el nombre de los nodos generados a partir de los datos de enlace, debe establecer el índice del marco de datos de datos de nodo para que sea la propiedad del name
, antes de convertirlo en un diccionario para que NetworkX 2.x pueda cargarlo. como los atributos del nodo.
nx.set_node_attributes(G, nodeData.set_index('name').to_dict('index'))
Esto carga todo el marco de datos de nodeData en un diccionario en el que la clave es el nombre y las otras propiedades son pares clave:valor dentro de esa clave (es decir, propiedades de nodo normales donde el índice de nodo es su nombre).
Un pequeño comentario:
from_pandas_dataframe no funciona en nx 2, refiriéndose a este
G = nx.from_pandas_dataframe(edges, 'source', 'target', 'weight')
Creo que en nx 2.0 va así:
G = nx.from_pandas_edgelist(edges, source = "Source", target = "Target")