Skip to content

Commit c67903d

Browse files
committed
minor changes
1 parent 9a3e53d commit c67903d

File tree

5 files changed

+113
-29
lines changed

5 files changed

+113
-29
lines changed

examples/multinet.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414

1515

1616
Y, X, lmbda, delta, probas, dists, z = correlated_dynamic_multilayer_network(
17-
n_nodes=100, n_layers=4, n_time_steps=10, n_features=2,
18-
center=0.75, tau=[0.25, 0.5], include_delta=True,
19-
rho=0., rho_t=0.8, sigma=0.01,
17+
n_nodes=100, n_layers=5, n_time_steps=10, n_features=2,
18+
center=1, tau=[0.5, 0.75], include_delta=True,
19+
rho=0., rho_t=0.4, sigma=0.01,
2020
random_state=1)
2121
print(lmbda)
2222

@@ -35,7 +35,7 @@
3535
for t in range(n_time_steps):
3636
print('t = {}'.format(t))
3737
model = MultilayerNetworkLSM(
38-
max_iter=50, n_features=2,
38+
max_iter=500, n_features=2,
3939
init_covariance_type='full',
4040
tol=1e-2, n_init=10,
4141
stopping_criteria='loglik',
@@ -55,7 +55,7 @@
5555
print(calculate_auc(Y, probas_pred, test_indices=test_indices))
5656

5757
model_joint = DynamicMultilayerNetworkLSM(
58-
max_iter=50, n_features=2,
58+
max_iter=500, n_features=2,
5959
init_covariance_type='full',
6060
approx_type='structured',
6161
tol=1e-2, n_init=10,

examples/svi_mf.py

+36-21
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@
1717
sigma = 0.05
1818

1919
Y, X, lmbda, delta, probas, dists, z = correlated_dynamic_multilayer_network(
20-
n_nodes=100, n_layers=4, n_time_steps=10, n_features=2,
21-
tau=np.array([0.5, 0.75]),
22-
rho=0., rho_t=0.8, sigma=sigma,
23-
random_state=3)
20+
n_nodes=100, n_layers=5, n_time_steps=20,
21+
n_features=2, tau=np.array([0.5, 0.75]),
22+
center=1, rho_t=0.4, sigma=0.05,
23+
random_state=83529)
2424

2525
n_layers, n_time_steps, n_nodes, _ = Y.shape
2626
n_dyads = 0.5 * n_layers * n_time_steps * n_nodes * (n_nodes - 1)
@@ -29,17 +29,17 @@
2929

3030
Y_train, test_indices = train_test_split(Y, test_size=0.2, random_state=23)
3131

32-
#model_mf = DynamicMultilayerNetworkLSM(
33-
# max_iter=50, n_features=2,
34-
# init_covariance_type='spherical',
35-
# approx_type='mean_field',
36-
# tol=1e-2, n_init=10,
37-
# stopping_criteria=None,
38-
# n_jobs=-1,
39-
# random_state=123)
40-
#
41-
#callback = TestMetricsCallback(Y=Y, probas=probas, test_indices=test_indices)
42-
#model_mf.fit(Y_train, callback=callback)
32+
model_mf = DynamicMultilayerNetworkLSM(
33+
max_iter=50, n_features=2,
34+
init_covariance_type='full',
35+
approx_type='mean_field',
36+
tol=1e-2, n_init=10,
37+
stopping_criteria=None,
38+
n_jobs=-1,
39+
random_state=123)
40+
41+
callback = TestMetricsCallback(Y=Y, probas=probas, test_indices=test_indices)
42+
model_mf.fit(Y_train, callback=callback)
4343
#print('MF Bias(sigma_sq): ', np.abs(model_mf.sigma_sq_ - sigma**2))
4444
#
4545
## forecast accuracy
@@ -55,7 +55,11 @@
5555
#print('forecast AUC:', roc_auc_score(y_true, y_pred))
5656
#print('forecast correlation:', pearsonr(y_true_probas, y_pred)[0])
5757
#
58-
#plt.plot(model_mf.callback_.times_, model_mf.callback_.correlations_, label='mean_field')
58+
plt.plot(model_mf.callback_.times_, model_mf.callback_.correlations_,
59+
linewidth=2, linestyle='dashed', label='mean_field')
60+
for i in range(10):
61+
plt.plot(model_mf._callbacks[i].times_, model_mf._callbacks[i].correlations_,
62+
alpha=0.25, c='black', linestyle='dashed')
5963

6064
model_svi = DynamicMultilayerNetworkLSM(
6165
max_iter=50, n_features=2,
@@ -70,13 +74,24 @@
7074
model_svi.fit(Y_train, callback=callback)
7175
#print('SVI Bias(sigma_sq): ', np.abs(model_svi.sigma_sq_ - sigma**2))
7276
#
73-
#plt.plot(model_svi.callback_.times_, model_svi.callback_.correlations_, label='structured')
77+
plt.plot(model_svi.callback_.times_, model_svi.callback_.correlations_, linewidth=2, label='structured')
78+
for i in range(10):
79+
plt.plot(model_svi._callbacks[i].times_, model_svi._callbacks[i].correlations_,
80+
alpha=0.25, c='black')
81+
7482
#
7583
#plt.legend()
76-
#plt.xlabel('Wallclock Time [s]')
77-
#plt.ylabel('Pearson Correlation')
78-
#plt.show()
79-
#
84+
plt.xlabel('Wallclock Time [s]')
85+
plt.ylabel('Pearson Correlation')
86+
plt.show()
87+
88+
89+
plt.plot(model_mf.callback_.correlations_, label='Structured VI')
90+
plt.plot(model_svi.callback_.correlations_, label='Mean Field')
91+
plt.xlabel('# of Iterations')
92+
plt.ylabel('Pearson Correlation')
93+
plt.show()
94+
8095
## forecast accuracy
8196
#y_true = []
8297
#y_true_probas = []

multidynet/datasets/synthetic.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ def correlated_dynamic_multilayer_network(n_nodes=100, n_layers=4, n_time_steps=
176176
X[t] = X[t-1] + errors[..., t-1]
177177
X[t] -= np.mean(X[t], axis=0)
178178

179-
# sample assortativity parameters from a U(-2, 2)
179+
# sample assortativity parameters from a U(-1, 2) (average is 0.5)
180180
lmbda = np.zeros((n_layers, n_features))
181181
lmbda[0] = rng.choice([-1, 1], size=n_features)
182182
lmbda[1:] = rng.uniform(

multidynet/metrics.py

+46
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,52 @@
77
from sklearn.metrics import roc_auc_score
88

99

10+
def calculate_metric_single(Y_true, Y_pred, metric, test_indices=None):
11+
n_time_steps, n_nodes, _ = Y_true.shape
12+
indices = np.tril_indices_from(Y_true[0], k=-1)
13+
14+
y_true = []
15+
y_pred = []
16+
for t in range(n_time_steps):
17+
y_true_vec = Y_true[t][indices]
18+
y_pred_vec = Y_pred[t][indices]
19+
20+
if test_indices is None:
21+
subset = y_true_vec != -1.0
22+
else:
23+
subset = test_indices[t]
24+
y_true.extend(y_true_vec[subset])
25+
y_pred.extend(y_pred_vec[subset])
26+
27+
return metric(y_true, y_pred)
28+
29+
30+
def calculate_metric(Y_true, Y_pred, metric, test_indices=None):
31+
if Y_true.ndim == 3:
32+
return calculate_metric_single(
33+
Y_true, Y_pred, metric, test_indices=test_indices)
34+
35+
n_layers, n_time_steps, n_nodes, _ = Y_true.shape
36+
indices = np.tril_indices_from(Y_true[0, 0], k=-1)
37+
38+
y_true = []
39+
y_pred = []
40+
for k in range(n_layers):
41+
for t in range(n_time_steps):
42+
y_true_vec = Y_true[k, t][indices]
43+
y_pred_vec = Y_pred[k, t][indices]
44+
45+
if test_indices is None:
46+
subset = y_true_vec != -1.0
47+
else:
48+
subset = test_indices[k][t]
49+
50+
y_true.extend(y_true_vec[subset])
51+
y_pred.extend(y_pred_vec[subset])
52+
53+
return metric(y_true, y_pred)
54+
55+
1056
def calculate_auc_single(Y_true, Y_pred, test_indices=None):
1157
n_time_steps, n_nodes, _ = Y_true.shape
1258
indices = np.tril_indices_from(Y_true[0], k=-1)

multidynet/multidynet.py

+25-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
from scipy.special import logit, gammainc, expit, logsumexp
88
from sklearn.exceptions import ConvergenceWarning
99
from sklearn.utils import check_array, check_random_state
10+
from scipy.optimize import linear_sum_assignment
1011
from sklearn.linear_model import LogisticRegression
11-
from sklearn.metrics import log_loss
12+
from sklearn.metrics import log_loss, f1_score
1213
from tqdm import tqdm
1314

1415
from .omega import update_omega
@@ -18,7 +19,7 @@
1819
from .variances import update_tau_sq, update_sigma_sq, update_X0_precision, update_diag_tau_sq
1920
from .variances import update_tau_sq_delta, update_sigma_sq_delta
2021
from .log_likelihood import log_likelihood, pointwise_log_likelihood
21-
from .metrics import calculate_auc
22+
from .metrics import calculate_auc, calculate_metric
2223
from .sample_lds import sample_gssm
2324
from .model_selection import dynamic_multilayer_adjacency_to_vec
2425

@@ -60,6 +61,22 @@ def __init__(self, omega, X, X_sigma, X_cross_cov,
6061
self.callback_ = callback
6162

6263

64+
def find_permutation(U, U_ref):
65+
_, n_features = U.shape
66+
C = U_ref.T @ U
67+
perm = linear_sum_assignment(np.maximum(C, -C), maximize=True)[1]
68+
sign = np.sign(C[np.arange(n_features), perm])
69+
return sign * U[:, perm]
70+
71+
72+
def smooth_positions(U):
73+
n_time_steps, _, _ = U.shape
74+
for t in range(1, n_time_steps):
75+
U[t] = find_permutation(U[t], U[t-1])
76+
77+
return U
78+
79+
6380
def sample_socialities(model, size=500, random_state=None):
6481
samples = model.sample(size=size, random_state=random_state)
6582
deltas = samples['delta']
@@ -556,6 +573,9 @@ def fit(self, Y, callback=None, n_samples=None):
556573

557574
self._set_parameters(best_model)
558575

576+
# save all callbacks
577+
self._callbacks = [models[i].callback_ for i in range(len(models))]
578+
559579
# calculate dyad-probabilities
560580
self.probas_ = calculate_probabilities(
561581
self.X_, self.lambda_, self.delta_)
@@ -659,6 +679,9 @@ def _set_parameters(self, model):
659679
self.X_sigma_ = model.X_sigma_
660680
self.X_cross_cov_ = model.X_cross_cov_
661681

682+
# match signed-permutations across time
683+
self.X_ = smooth_positions(self.X_)
684+
662685
# transform to identifiable parameterization
663686
if self.X_ is not None:
664687
self.Z_ = (self.X_ -

0 commit comments

Comments
 (0)