Add vertex attributes to a weighted igraph Graph in python - python

I am learning python-igraph, and having difficulty in handling a graph which is divided to components (which are unconnected between them). When I apply one of the clustering algorithms on this graph it doesn't seem to work properly, and so I need to apply the algorithms to each subgraph (component) separately. So in order to maintain the identification of the vertices, I would like to add a vertex attribute that give me the id number in the original graph. My graph is constructed from a weighted adjacency matrix:
import numpy as np
import igraph
def symmetrize(a):
return a + a.T - 2*np.diag(a.diagonal())
A = symmetrize(np.random.random((100,100)))
G = igraph.Graph.Adjacency(A.tolist(),attr="weight",mode="UPPER")
I see that there should be a way to add vertex attributes, but I don't understand how to use it..

Adding a vertex attribute to all of the vertices works like this:
G.vs["attr"] = ["id1", "id2", "id3", ...]
You can also attach a vertex attribute to a single vertex:
G.vs[2]["attr"] = "id3"
For instance, if you simply need a unique identifier to all your vertices, you can do this:
G.vs["original_id"] = list(range(G.vcount()))
(You don't need the list() part if you are on Python 2.x as range() already produces a list).

Related

How to create a Spektral graph with edge weights and edge features

I want to create a Graph in Spektral which has both edged weights and edge labels. I have three matrices: a nxn adjacency matrix, an nx4 feature matrix for the nodes, and an nxnx2 matrix which represents the label for each edge. I do not know how to incorporate this third matrix into my Graph so that the edges will be labeled. I would also be happy to label the edges manually, but I don't know how to do that either. Thanks!
The spektral.data.Graph data structure has an attribute called e to store edge attributes.
So, if you have your data stored into numpy arrays you can do:
g = Graph(x=x, a=a, e=e)
where e is your edge attributes matrix.
They will be picked up automatically by the data loaders, if you use them.
Check out the documentation here.

From Adjacency matrix to Bipartite Graph in NewworkX

I have a csr matrix from which I extracted data, rows, and columns.
I want to create a bipartite graph using NetworkX, and I also tried several solutions without success (as an example: Plot bipartite graph using networkx in Python). The reasons why it doesn't work, in my opinion, is a matter of labeling. My two sets and the nodes inside them have no string name.
For example in a 10x10 matrix, the rows/cols indexes represent the name of the nodes of the two sets, while the intersection of these nodes is the weighted link between those nodes.
In my case, then, if I have (0,0)=0.5 it doesn't mean that it is a self-loop; instead, the link with weight 0.5 connects the "node 0" of the first set with the "node 0" of the second one.
import networkx as nx
from networkx.algorithms import bipartite
import matplotlib.pyplot as plt
def function(foo, n_row, n_col):
n_row=10
n_col=10
After the creation of the matrix, I obtain my data
weights = weights.tocsr()
wcoo = weights.tocoo()
m_data = wcoo.data
m_rows = wcoo.row
m_cols = wcoo.col
g = nx.Graph()
# TRIAL 1
g.add_nodes_from(m_cols, bipartite=0)
g.add_nodes_from(m_rows, bipartite=1)
bi_m = bipartite.matrix.biadjacency_matrix(g, m_data)
# TRIAL 2
g.add_weighted_edges_from(zip(m_cols, m_rows, m_data))
nx.draw(g, node_size=500)
plt.show()
I expected a bipartite graph with two sets of 10 nodes per each with a certain amount of weighted links among them (without link among the same set) as a result.
I, instead, obtained a classic non-oriented graph with 10 nodes in total.
At the same time, I'd like to optimize as well as I can my code to speed-up the computational time without affecting the readability.

How to generate a random network but keep the original node degree using networkx?

I have a network, and how to generate a random network but ensure each node retains the same degre of the original network using networkx? My first thought is to get the adjacency matrix, and perform a random in each row of the matrix, but this way is somwhat complex, e.g. need to avoid self-conneted (which is not seen in the original network) and re-label the nodes. Thanks!
I believe what you're looking for is expected_degree_graph. It generates a random graph based on a sequence of expected degrees, where each degree in the list corresponds to a node. It also even includes an option to disallow self-loops!
You can get a list of degrees using networkx.degree. Here's an example of how you would use them together in networkx 2.0+ (degree is slightly different in 1.0):
import networkx as nx
from networkx.generators.degree_seq import expected_degree_graph
N,P = 3, 0.5
G = nx.generators.random_graphs.gnp_random_graph(N, P)
G2 = expected_degree_graph([deg for (_, deg) in G.degree()], selfloops=False)
Note that you're not guaranteed to have the exact degrees for each node using expected_degree_graph; as the name implies, it's probabilistic given the expected value for each of the degrees. If you want something a little more concrete you can use configuration_model, however it does not protect against parallel edges or self-loops, so you'd need to prune those out and replace the edges yourself.

How to create a graph with vertices weight in python with igraph?

I searched but found there are many examples about how to create a graph with edges weight, but none of them shows how to create a graph with vertices weight. I start to wonder if it is possible.
If a vertices-weighted graph can be created with igraph, then is it possible to calculate the weighted independence or other weighted numbers with igraph?
As far as I know, there are no functions in igraph that accept arguments for weighted vertices. However, the SANTA package that is a part of the Bioconductor suite for R does have routines for weighted vertices, if you are willing to move to R for this. (Seems like maybe you can run bioconductor in python.)
Another hacky option is the use (when possible) unweighted routines from igraph and then back in the weights. E.g. something like this for weighted maximal independent sets:
def maxset(graph,weight):
ms = g.maximal_independent_vertex_sets()
w = []
t = []
for i in range(0, 150):
m = weights.loc[weights['ids'].isin(ms[i]),"weights"]
w.append(m)
s = sum(w[i])
t.append(s)
return(ms[t.index(max(t))])
maxset(g,weights)
(Where weights is a two column data frame with column 1 = vertex ids and column 2 = weights). This gets the maximal independent set taking vertex weights into consideration.
You want to use vs class to define vertices and their attributes in igraph.
As example for setting weight on vertices, taken from documentation:
http://igraph.org/python/doc/igraph.VertexSeq-class.html
g=Graph.Full(3) # generate a full graph as example
for idx, v in enumerate(g.vs):
v["weight"] = idx*(idx+1) # set the 'weight' of vertex to integer, in function of a progressive index
>>> g.vs["weight"]
[0, 2, 6]
Note that a sequence of vertices are called through g.vs, here g the instance of your Graph object.
I suggested you this page, I found it practical to look for iGraph methods here:
http://igraph.org/python/doc/identifier-index.html

Build a graph as a subset of another, larger, graph [iGraph, Python]

I need to compute the density of a subgraph made of vertices belonging to the same attribute "group".
ie., let g be an iGraph graph,
g.vs.select(group = 1)
gives me an object with all vertices belonging to group 1
Is there any way to compute density on the graph which is formed by these vertices and the connections between them?
In a fashion similar to this maybe?
g2.vs(g2.vs.select(group = i)).density()
Try this:
g.vs.select(group=1).subgraph().density()

Categories

Resources