In [1]:
import choix
import networkx as nx
import numpy as np
%matplotlib inline
In [2]:
n_items = 8
p_edge = 0.3
n_samples = 3000
# 1. Generate a network.
graph = nx.erdos_renyi_graph(n_items, p_edge, directed=True)
# 2. Generate a parameter for each node.
params = choix.generate_params(n_items, interval=2.0)
# 3. Generate samples of choices in the network.
transitions = np.zeros((n_items, n_items))
for _ in range(n_samples):
src = np.random.choice(n_items)
neighbors = graph.successors(src)
if len(neighbors) == 0:
continue
dst = choix.compare(neighbors, params)
transitions[src, dst] += 1
The network looks as follows
In [3]:
nx.draw(graph, with_labels=True)
Now we aggregate the all the transitions into incoming traffic and outgoing traffic.
In [4]:
traffic_in = transitions.sum(axis=0)
traffic_out = transitions.sum(axis=1)
print("incoming traffic:", traffic_in)
print("outgoing traffic:", traffic_out)
ChoiceRank can be used to recover the transitions on the network based only on:
ChoiceRank works under the assumption that each node has a latent "preference" score, and that transitions follow Luce's choice model.
In [5]:
params = choix.choicerank(graph, traffic_in, traffic_out)
We can attempt to reconstruct the transition matrix using the marginal traffic data and the parameters.
In [6]:
est = np.zeros((n_items, n_items))
for src in range(n_items):
neighbors = graph.successors(src)
if len(neighbors) == 0:
continue
probs = choix.probabilities(neighbors, params)
est[src,neighbors] = traffic_out[src] * probs
In [7]:
print("True transition matrix:")
print(transitions)
print("\nEstimated transition matrix:")
print(np.round_(est))
print("\nDifference:")
print(np.round_(transitions - est))