To avoid reinventing the wheel you should use networkx as suggested in comments and other answers.
If, for educational purposes, you want to reinvent the wheel you can create an adjacency matrix. The PageRank can be computed from that matrix:
The PageRank values are the entries of the dominant right eigenvector of the modified adjacency matrix.
Since each row/column of the adjacency matrix represents a node, you will need to enumerate the nodes so each node is represented by a unique number starting from 0.
import numpy as np
data = np.array([['P01106', 'Q09472'],
['P01106', 'Q13309'],
['P62136', 'Q13616'],
['P11831', 'P18146'],
['P13569', 'P20823'],
['P20823', 'P01100']])
nodes = np.unique(data) # mapping node name --> index
noidx = {n: i for i, n in enumerate(nodes)} # mapping node index --> name
n = nodes.size # number of nodes
numdata = np.vectorize(noidx.get)(data) # replace node id by node index
A = np.zeros((n, n))
for tail, head in numdata:
A[tail, head] = 1
#A[head, tail] = 1 # add this line for undirected graph
This results in the following graph representation A
:
array([[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 1., 1., 0.],
[ 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 1., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])
A 1 in row 5, column 0 for example means that there is an edge from node 5 to node 0, which corresponds to 'P20823'
--> 'P01100'
. Use the nodes
array to look up node names from indices:
print(nodes)
['P01100' 'P01106' 'P11831' 'P13569' 'P18146' 'P20823' 'P62136' 'Q09472'
'Q13309' 'Q13616']
If there are many nodes and few connections it's better to use a sparse matrix
for A
. But first try to stay with a dense matrix and only bother to switch to sparse of you have memory or performance issues.