InfluenceDiffusion 0.0.11__tar.gz → 0.0.13__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {influencediffusion-0.0.11 → influencediffusion-0.0.13}/InfluenceDiffusion/Graph.py +29 -104
- {influencediffusion-0.0.11 → influencediffusion-0.0.13}/InfluenceDiffusion/estimation_models/BaseWeightEstimator.py +3 -4
- {influencediffusion-0.0.11 → influencediffusion-0.0.13}/InfluenceDiffusion/influence_models.py +6 -4
- influencediffusion-0.0.13/InfluenceDiffusion.egg-info/PKG-INFO +96 -0
- influencediffusion-0.0.13/PKG-INFO +96 -0
- {influencediffusion-0.0.11 → influencediffusion-0.0.13}/setup.py +4 -2
- influencediffusion-0.0.11/InfluenceDiffusion.egg-info/PKG-INFO +0 -22
- influencediffusion-0.0.11/PKG-INFO +0 -22
- {influencediffusion-0.0.11 → influencediffusion-0.0.13}/InfluenceDiffusion/Trace.py +0 -0
- {influencediffusion-0.0.11 → influencediffusion-0.0.13}/InfluenceDiffusion/__init__.py +0 -0
- {influencediffusion-0.0.11 → influencediffusion-0.0.13}/InfluenceDiffusion/estimation_models/EMEstimation.py +0 -0
- {influencediffusion-0.0.11 → influencediffusion-0.0.13}/InfluenceDiffusion/estimation_models/OptimEstimation.py +0 -0
- {influencediffusion-0.0.11 → influencediffusion-0.0.13}/InfluenceDiffusion/estimation_models/__init__.py +0 -0
- {influencediffusion-0.0.11 → influencediffusion-0.0.13}/InfluenceDiffusion/utils.py +0 -0
- {influencediffusion-0.0.11 → influencediffusion-0.0.13}/InfluenceDiffusion/weight_samplers.py +0 -0
- {influencediffusion-0.0.11 → influencediffusion-0.0.13}/InfluenceDiffusion.egg-info/SOURCES.txt +0 -0
- {influencediffusion-0.0.11 → influencediffusion-0.0.13}/InfluenceDiffusion.egg-info/dependency_links.txt +0 -0
- {influencediffusion-0.0.11 → influencediffusion-0.0.13}/InfluenceDiffusion.egg-info/requires.txt +0 -0
- {influencediffusion-0.0.11 → influencediffusion-0.0.13}/InfluenceDiffusion.egg-info/top_level.txt +0 -0
- {influencediffusion-0.0.11 → influencediffusion-0.0.13}/LICENSE +0 -0
- {influencediffusion-0.0.11 → influencediffusion-0.0.13}/README.md +0 -0
- {influencediffusion-0.0.11 → influencediffusion-0.0.13}/setup.cfg +0 -0
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import pandas as pd
|
|
2
1
|
import numpy as np
|
|
3
2
|
from typing import List, Tuple, Union, Dict
|
|
4
3
|
import networkx as nx
|
|
@@ -7,67 +6,41 @@ __all__ = ["Graph"]
|
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
class Graph(nx.DiGraph):
|
|
10
|
-
def __init__(self,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
Parameters
|
|
17
|
-
----------
|
|
18
|
-
edge_list : List[Tuple[int, int]]
|
|
19
|
-
List of tuples (source, sink) representing edges of the graph.
|
|
20
|
-
directed : bool, optional
|
|
21
|
-
Flag to indicate whether the graph is directed (default is True).
|
|
22
|
-
weights : Union[None, List[float]], optional
|
|
23
|
-
Optional weights for each edge. If None, all edges are assigned a weight of 1.
|
|
24
|
-
"""
|
|
25
|
-
self.directed = directed
|
|
26
|
-
self.edge_array = np.array(edge_list, dtype=int)
|
|
27
|
-
|
|
28
|
-
if not self.directed:
|
|
29
|
-
reverse_edge_array = self.edge_array[:, [1, 0]]
|
|
30
|
-
self.edge_array = np.concatenate([self.edge_array, reverse_edge_array])
|
|
31
|
-
|
|
32
|
-
super().__init__(self.edge_array.tolist())
|
|
33
|
-
|
|
34
|
-
if weights is not None:
|
|
35
|
-
assert len(weights) == len(edge_list), "number of edges is different from number of weights"
|
|
9
|
+
def __init__(self, incoming_graph_data=None, weights: Union[List, np.array] = None, **attr):
|
|
10
|
+
super().__init__(incoming_graph_data, **attr)
|
|
11
|
+
self.edge_array = np.array(self.edges)
|
|
12
|
+
if weights is None:
|
|
13
|
+
self.weights = np.ones(len(self.edges))
|
|
36
14
|
else:
|
|
37
|
-
weights
|
|
38
|
-
|
|
39
|
-
|
|
15
|
+
assert len(weights) == self.count_edges(), "number of weights different from the number of edges"
|
|
16
|
+
self.weights = np.array(weights)
|
|
17
|
+
nx.set_edge_attributes(self, dict(zip(self.edges, self.weights)), "weight")
|
|
40
18
|
|
|
41
|
-
def
|
|
42
|
-
|
|
43
|
-
|
|
19
|
+
def add_edge(self, u_of_edge, v_of_edge, **attr):
|
|
20
|
+
super().add_edge(u_of_edge, v_of_edge, **attr)
|
|
21
|
+
self.edge_array = np.array(self.edges)
|
|
22
|
+
self.weights = self._get_edge_weight_attributes()
|
|
44
23
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
If None, re-indexes vertices to [0, 1, ..., |V|-1].
|
|
24
|
+
def add_edges_from(self, ebunch_to_add, **attr):
|
|
25
|
+
super().add_edges_from(ebunch_to_add, **attr)
|
|
26
|
+
self.edge_array = np.array(self.edges)
|
|
27
|
+
self.weights = self._get_edge_weight_attributes()
|
|
50
28
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"""
|
|
56
|
-
if old_2_new_vertex_name_dict is None:
|
|
57
|
-
old_vertex_names = sorted(list(self.get_vertices()))
|
|
58
|
-
old_2_new_vertex_name_dict = {name: idx for idx, name in enumerate(old_vertex_names)}
|
|
29
|
+
def add_weighted_edges_from(self, ebunch_to_add, weight='weight', **attr):
|
|
30
|
+
super().add_weighted_edges_from(ebunch_to_add, weight=weight, **attr)
|
|
31
|
+
self.edge_array = np.array(self.edges)
|
|
32
|
+
self.weights = self._get_edge_weight_attributes()
|
|
59
33
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return self
|
|
34
|
+
def _get_edge_weight_attributes(self):
|
|
35
|
+
return np.array([edge[2] for edge in self.edges.data("weight", default=1)])
|
|
63
36
|
|
|
64
|
-
def set_weights(self, weights: Union[
|
|
37
|
+
def set_weights(self, weights: Union[List, np.array]) -> "Graph":
|
|
65
38
|
"""
|
|
66
39
|
Set weights for the edges in the graph.
|
|
67
40
|
|
|
68
41
|
Parameters
|
|
69
42
|
----------
|
|
70
|
-
weights : Union[
|
|
43
|
+
weights : Union[list, np.array]
|
|
71
44
|
Array of weights for the edges.
|
|
72
45
|
|
|
73
46
|
Returns
|
|
@@ -81,7 +54,8 @@ class Graph(nx.DiGraph):
|
|
|
81
54
|
If the number of weights does not match the number of edges.
|
|
82
55
|
"""
|
|
83
56
|
assert len(weights) == self.count_edges(), "number of weights different from the number of edges"
|
|
84
|
-
self.
|
|
57
|
+
nx.set_edge_attributes(self, dict(zip(self.edges, weights)), 'weight')
|
|
58
|
+
self.weights = self._get_edge_weight_attributes()
|
|
85
59
|
return self
|
|
86
60
|
|
|
87
61
|
def get_edges(self, as_array: bool = False) -> Union[np.array, List[Tuple[int, int]]]:
|
|
@@ -100,7 +74,7 @@ class Graph(nx.DiGraph):
|
|
|
100
74
|
"""
|
|
101
75
|
if as_array:
|
|
102
76
|
return self.edge_array
|
|
103
|
-
return
|
|
77
|
+
return list(self.edges)
|
|
104
78
|
|
|
105
79
|
def get_vertices(self) -> set:
|
|
106
80
|
"""
|
|
@@ -144,7 +118,7 @@ class Graph(nx.DiGraph):
|
|
|
144
118
|
int
|
|
145
119
|
The total number of edges.
|
|
146
120
|
"""
|
|
147
|
-
return len(self.
|
|
121
|
+
return len(self.edges)
|
|
148
122
|
|
|
149
123
|
def count_vertices(self) -> int:
|
|
150
124
|
"""
|
|
@@ -155,7 +129,7 @@ class Graph(nx.DiGraph):
|
|
|
155
129
|
int
|
|
156
130
|
The total number of vertices.
|
|
157
131
|
"""
|
|
158
|
-
return len(self.
|
|
132
|
+
return len(self.nodes)
|
|
159
133
|
|
|
160
134
|
def get_children_mask(self, vertex: int) -> np.array:
|
|
161
135
|
"""
|
|
@@ -392,38 +366,6 @@ class Graph(nx.DiGraph):
|
|
|
392
366
|
"""
|
|
393
367
|
return np.mean(self.get_all_indegrees(weighted))
|
|
394
368
|
|
|
395
|
-
def get_edge_index(self, edge: Tuple[int, int]) -> int:
|
|
396
|
-
"""
|
|
397
|
-
Get the index of a specified edge.
|
|
398
|
-
|
|
399
|
-
Parameters
|
|
400
|
-
----------
|
|
401
|
-
edge : Tuple[int, int]
|
|
402
|
-
The edge for which to find the index.
|
|
403
|
-
|
|
404
|
-
Returns
|
|
405
|
-
-------
|
|
406
|
-
int
|
|
407
|
-
The index of the edge in the graph.
|
|
408
|
-
"""
|
|
409
|
-
return self.edge_2_index[tuple(edge)]
|
|
410
|
-
|
|
411
|
-
def get_edge_weight(self, edge: Tuple[int, int]) -> float:
|
|
412
|
-
"""
|
|
413
|
-
Get the weight of a specified edge.
|
|
414
|
-
|
|
415
|
-
Parameters
|
|
416
|
-
----------
|
|
417
|
-
edge : Tuple[int, int]
|
|
418
|
-
The edge for which to retrieve the weight.
|
|
419
|
-
|
|
420
|
-
Returns
|
|
421
|
-
-------
|
|
422
|
-
float
|
|
423
|
-
The weight of the edge.
|
|
424
|
-
"""
|
|
425
|
-
return self.weights[self.get_edge_index(edge)]
|
|
426
|
-
|
|
427
369
|
def get_edges_mask_from_set_to_vertex(self, vertex_set: set, vertex: int) -> np.array:
|
|
428
370
|
"""
|
|
429
371
|
Create a mask for edges leading from a set of vertices to a specified vertex.
|
|
@@ -445,23 +387,6 @@ class Graph(nx.DiGraph):
|
|
|
445
387
|
parent_edges_mask[parent_edges_mask] = [(parent in vertex_set) for parent in parent_vertices]
|
|
446
388
|
return parent_edges_mask
|
|
447
389
|
|
|
448
|
-
def get_adj_matrix(self) -> np.array:
|
|
449
|
-
"""
|
|
450
|
-
Generate the adjacency matrix of the graph.
|
|
451
|
-
|
|
452
|
-
Returns
|
|
453
|
-
-------
|
|
454
|
-
np.array
|
|
455
|
-
The adjacency matrix as a numpy array.
|
|
456
|
-
"""
|
|
457
|
-
vertices = list(self.get_vertices())
|
|
458
|
-
n_vertex = len(vertices)
|
|
459
|
-
adj_matrix = pd.DataFrame(np.zeros((n_vertex, n_vertex)), columns=vertices, index=vertices)
|
|
460
|
-
for (v1, v2), weight in zip(self.edge_array, self.weights):
|
|
461
|
-
adj_matrix.at[v1, v2] = weight
|
|
462
|
-
|
|
463
|
-
return adj_matrix
|
|
464
|
-
|
|
465
390
|
def is_edge_in_graph(self, edge: Tuple[int, int]) -> bool:
|
|
466
391
|
"""
|
|
467
392
|
Check if a specified edge exists in the graph.
|
|
@@ -2,7 +2,6 @@ from typing import List, Union, Dict
|
|
|
2
2
|
import os
|
|
3
3
|
import pickle
|
|
4
4
|
import numpy as np
|
|
5
|
-
from tqdm import tqdm
|
|
6
5
|
from joblib import Parallel, delayed
|
|
7
6
|
from scipy.stats import uniform
|
|
8
7
|
from scipy.stats._distn_infrastructure import rv_frozen
|
|
@@ -144,13 +143,13 @@ class BaseWeightEstimator:
|
|
|
144
143
|
vertex_2_active_parent_mask_t = {vertex: [] for vertex in self.informative_vertices}
|
|
145
144
|
failed_vertices_masks = {vertex: [] for vertex in self.informative_vertices}
|
|
146
145
|
|
|
147
|
-
for vertex, vertex_pseudo_traces in
|
|
146
|
+
for vertex, vertex_pseudo_traces in traces.items():
|
|
148
147
|
for vertices_tm1, new_vertices_t in vertex_pseudo_traces:
|
|
149
148
|
parents = self.graph.get_parents(vertex, out_type=np.array)
|
|
150
|
-
active_parents_mask_tm1 = np.
|
|
149
|
+
active_parents_mask_tm1 = np.isin(parents, np.array(list(vertices_tm1)))
|
|
151
150
|
if new_vertices_t:
|
|
152
151
|
vertices_t = vertices_tm1 | new_vertices_t
|
|
153
|
-
active_parents_mask_t = np.
|
|
152
|
+
active_parents_mask_t = np.isin(parents, np.array(list(vertices_t)))
|
|
154
153
|
vertex_2_active_parent_mask_tm1[vertex].append(active_parents_mask_tm1)
|
|
155
154
|
vertex_2_active_parent_mask_t[vertex].append(active_parents_mask_t)
|
|
156
155
|
else:
|
{influencediffusion-0.0.11 → influencediffusion-0.0.13}/InfluenceDiffusion/influence_models.py
RENAMED
|
@@ -48,6 +48,7 @@ class InfluenceModel:
|
|
|
48
48
|
self.vertices = list(self.g.get_vertices())
|
|
49
49
|
self.random_state = random_state
|
|
50
50
|
self.n_jobs = n_jobs
|
|
51
|
+
self._edge_2_index = {edge: idx for idx, edge in enumerate(g.edges)}
|
|
51
52
|
if check_init:
|
|
52
53
|
self.check_param_init_correctness()
|
|
53
54
|
|
|
@@ -179,7 +180,7 @@ class InfluenceModel:
|
|
|
179
180
|
self._pre_simulation_init(seed_set, simulation_rvs=simulation_rvs)
|
|
180
181
|
return self._simulate_trace(out_trace_type=out_trace_type)
|
|
181
182
|
|
|
182
|
-
def make_simulation(self, seed_set: Set[int], simulation_rvs=None) ->
|
|
183
|
+
def make_simulation(self, seed_set: Set[int], simulation_rvs=None) -> Union[Trace, List[Set[int]]]:
|
|
183
184
|
"""Run a simulation and return the propagation trace.
|
|
184
185
|
|
|
185
186
|
Parameters
|
|
@@ -219,7 +220,8 @@ class InfluenceModel:
|
|
|
219
220
|
seed_sets = self._sample_seeds(n_seeds=n_traces, seed_size_range=seed_size_range)
|
|
220
221
|
return self.sample_traces_from_seeds(seed_sets, out_trace_type=out_trace_type)
|
|
221
222
|
|
|
222
|
-
def sample_traces_from_seeds(self, seed_sets: List[Set[int]],
|
|
223
|
+
def sample_traces_from_seeds(self, seed_sets: List[Set[int]],
|
|
224
|
+
out_trace_type: bool = True) -> Union[Traces, List[List[Set[int]]]]:
|
|
223
225
|
"""Sample traces from a list of seed sets.
|
|
224
226
|
|
|
225
227
|
Parameters
|
|
@@ -441,7 +443,7 @@ class LTM(InfluenceModel):
|
|
|
441
443
|
bool
|
|
442
444
|
True if the adjacent vertex is influenced, otherwise False.
|
|
443
445
|
"""
|
|
444
|
-
self.vertex_2_influence_counter[v_adj] += self.g.
|
|
446
|
+
self.vertex_2_influence_counter[v_adj] += self.g.get_edge_data(v, v_adj)["weight"]
|
|
445
447
|
return self.vertex_2_threshold[v_adj] <= self.vertex_2_influence_counter[v_adj]
|
|
446
448
|
|
|
447
449
|
def check_param_init_correctness(self, eps: float = 1e-6) -> None:
|
|
@@ -574,7 +576,7 @@ class ICM(InfluenceModel):
|
|
|
574
576
|
bool
|
|
575
577
|
True if the adjacent vertex is influenced, otherwise False.
|
|
576
578
|
"""
|
|
577
|
-
return self.edge_activations[self.
|
|
579
|
+
return self.edge_activations[self._edge_2_index[(v, v_adj)]]
|
|
578
580
|
|
|
579
581
|
def _generate_simulation_rvs(self, n_runs: int = 1) -> List:
|
|
580
582
|
"""Generate random activations for edges.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: InfluenceDiffusion
|
|
3
|
+
Version: 0.0.13
|
|
4
|
+
Summary: InfluenceDiffusion package
|
|
5
|
+
Author: Alexander Kagan
|
|
6
|
+
Author-email: <amkagan@umich.edu>
|
|
7
|
+
Keywords: python,Influence Maximization,Network diffusion models,General Linear Threshold model,Social Networks,Independent Cascade model
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Education
|
|
10
|
+
Classifier: Programming Language :: Python :: 2
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
13
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: numpy
|
|
17
|
+
Requires-Dist: scipy
|
|
18
|
+
Requires-Dist: networkx
|
|
19
|
+
Requires-Dist: typing
|
|
20
|
+
Requires-Dist: joblib
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# InfluenceDiffusion
|
|
24
|
+
|
|
25
|
+
InfluenceDiffusion is a Python library that provides instruments for working with influence diffusion models on graphs. In particular, it contains implementations of
|
|
26
|
+
- Popular diffusion models such as Independent Cascade, (General) Linear Threshold, etc.
|
|
27
|
+
- Methods for estimating parameters of these models
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
Use the package manager [pip](https://pip.pypa.io/en/stable/) to install InfluenceDiffusion.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install InfluenceDiffusion
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
# Imports
|
|
42
|
+
import matplotlib.pyplot as plt
|
|
43
|
+
from networkx import erdos_renyi_graph
|
|
44
|
+
|
|
45
|
+
from InfluenceDiffusion.Graph import Graph # class inheriting from nx.DiGraph
|
|
46
|
+
from InfluenceDiffusion.influence_models import LTM
|
|
47
|
+
from InfluenceDiffusion.estimation_models.EMEstimation import LTWeightEstimatorEM
|
|
48
|
+
from InfluenceDiffusion.weight_samplers import make_random_weights_with_indeg_constraint
|
|
49
|
+
|
|
50
|
+
# Sample an Erdos-Renyi graph
|
|
51
|
+
g_nx = erdos_renyi_graph(50, p=0.1, directed=True)
|
|
52
|
+
g = Graph(edge_list=g_nx.edges)
|
|
53
|
+
|
|
54
|
+
# Set ground-truth LT model edge weights (in-degree of each node is at most 1)
|
|
55
|
+
weights = make_random_weights_with_indeg_constraint(g, indeg_ub=1)
|
|
56
|
+
g.set_weights(weights)
|
|
57
|
+
|
|
58
|
+
# Sample traces from an LT model on this graph
|
|
59
|
+
ltm = LTM(g)
|
|
60
|
+
traces = ltm.sample_traces(1000)
|
|
61
|
+
|
|
62
|
+
# Estimate the weights using the traces
|
|
63
|
+
ltm_estimator = LTWeightEstimatorEM(g)
|
|
64
|
+
pred_weights = ltm_estimator.fit(traces)
|
|
65
|
+
|
|
66
|
+
# Compare with the ground-truth weights
|
|
67
|
+
plt.scatter(weights, pred_weights)
|
|
68
|
+
plt.plot([0, 1], [0, 1], linestyle='--', c='black')
|
|
69
|
+
plt.xlabel("True weights")
|
|
70
|
+
plt.ylabel("Predicted weights")
|
|
71
|
+
plt.show()
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## License
|
|
75
|
+
|
|
76
|
+
MIT License
|
|
77
|
+
|
|
78
|
+
Copyright (c) 2024 Alexander Kagan
|
|
79
|
+
|
|
80
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
81
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
82
|
+
in the Software without restriction, including without limitation the rights
|
|
83
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
84
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
85
|
+
furnished to do so, subject to the following conditions:
|
|
86
|
+
|
|
87
|
+
The above copyright notice and this permission notice shall be included in all
|
|
88
|
+
copies or substantial portions of the Software.
|
|
89
|
+
|
|
90
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
91
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
92
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
93
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
94
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
95
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
96
|
+
SOFTWARE.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: InfluenceDiffusion
|
|
3
|
+
Version: 0.0.13
|
|
4
|
+
Summary: InfluenceDiffusion package
|
|
5
|
+
Author: Alexander Kagan
|
|
6
|
+
Author-email: <amkagan@umich.edu>
|
|
7
|
+
Keywords: python,Influence Maximization,Network diffusion models,General Linear Threshold model,Social Networks,Independent Cascade model
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Education
|
|
10
|
+
Classifier: Programming Language :: Python :: 2
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
13
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: numpy
|
|
17
|
+
Requires-Dist: scipy
|
|
18
|
+
Requires-Dist: networkx
|
|
19
|
+
Requires-Dist: typing
|
|
20
|
+
Requires-Dist: joblib
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# InfluenceDiffusion
|
|
24
|
+
|
|
25
|
+
InfluenceDiffusion is a Python library that provides instruments for working with influence diffusion models on graphs. In particular, it contains implementations of
|
|
26
|
+
- Popular diffusion models such as Independent Cascade, (General) Linear Threshold, etc.
|
|
27
|
+
- Methods for estimating parameters of these models
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
Use the package manager [pip](https://pip.pypa.io/en/stable/) to install InfluenceDiffusion.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install InfluenceDiffusion
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
# Imports
|
|
42
|
+
import matplotlib.pyplot as plt
|
|
43
|
+
from networkx import erdos_renyi_graph
|
|
44
|
+
|
|
45
|
+
from InfluenceDiffusion.Graph import Graph # class inheriting from nx.DiGraph
|
|
46
|
+
from InfluenceDiffusion.influence_models import LTM
|
|
47
|
+
from InfluenceDiffusion.estimation_models.EMEstimation import LTWeightEstimatorEM
|
|
48
|
+
from InfluenceDiffusion.weight_samplers import make_random_weights_with_indeg_constraint
|
|
49
|
+
|
|
50
|
+
# Sample an Erdos-Renyi graph
|
|
51
|
+
g_nx = erdos_renyi_graph(50, p=0.1, directed=True)
|
|
52
|
+
g = Graph(edge_list=g_nx.edges)
|
|
53
|
+
|
|
54
|
+
# Set ground-truth LT model edge weights (in-degree of each node is at most 1)
|
|
55
|
+
weights = make_random_weights_with_indeg_constraint(g, indeg_ub=1)
|
|
56
|
+
g.set_weights(weights)
|
|
57
|
+
|
|
58
|
+
# Sample traces from an LT model on this graph
|
|
59
|
+
ltm = LTM(g)
|
|
60
|
+
traces = ltm.sample_traces(1000)
|
|
61
|
+
|
|
62
|
+
# Estimate the weights using the traces
|
|
63
|
+
ltm_estimator = LTWeightEstimatorEM(g)
|
|
64
|
+
pred_weights = ltm_estimator.fit(traces)
|
|
65
|
+
|
|
66
|
+
# Compare with the ground-truth weights
|
|
67
|
+
plt.scatter(weights, pred_weights)
|
|
68
|
+
plt.plot([0, 1], [0, 1], linestyle='--', c='black')
|
|
69
|
+
plt.xlabel("True weights")
|
|
70
|
+
plt.ylabel("Predicted weights")
|
|
71
|
+
plt.show()
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## License
|
|
75
|
+
|
|
76
|
+
MIT License
|
|
77
|
+
|
|
78
|
+
Copyright (c) 2024 Alexander Kagan
|
|
79
|
+
|
|
80
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
81
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
82
|
+
in the Software without restriction, including without limitation the rights
|
|
83
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
84
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
85
|
+
furnished to do so, subject to the following conditions:
|
|
86
|
+
|
|
87
|
+
The above copyright notice and this permission notice shall be included in all
|
|
88
|
+
copies or substantial portions of the Software.
|
|
89
|
+
|
|
90
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
91
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
92
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
93
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
94
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
95
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
96
|
+
SOFTWARE.
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
from setuptools import setup, find_packages
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
this_directory = Path(__file__).parent
|
|
4
|
+
LONG_DESCRIPTION = (this_directory / "README.md").read_text()
|
|
2
5
|
|
|
3
|
-
VERSION = '0.0.
|
|
6
|
+
VERSION = '0.0.13'
|
|
4
7
|
DESCRIPTION = 'InfluenceDiffusion package'
|
|
5
|
-
LONG_DESCRIPTION = 'In this package, we implement popular network diffusion models and methods for their estimation.'
|
|
6
8
|
|
|
7
9
|
setup(
|
|
8
10
|
name="InfluenceDiffusion",
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: InfluenceDiffusion
|
|
3
|
-
Version: 0.0.11
|
|
4
|
-
Summary: InfluenceDiffusion package
|
|
5
|
-
Author: Alexander Kagan
|
|
6
|
-
Author-email: <amkagan@umich.edu>
|
|
7
|
-
Keywords: python,Influence Maximization,Network diffusion models,General Linear Threshold model,Social Networks,Independent Cascade model
|
|
8
|
-
Classifier: Development Status :: 3 - Alpha
|
|
9
|
-
Classifier: Intended Audience :: Education
|
|
10
|
-
Classifier: Programming Language :: Python :: 2
|
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Operating System :: MacOS :: MacOS X
|
|
13
|
-
Classifier: Operating System :: Microsoft :: Windows
|
|
14
|
-
Description-Content-Type: text/markdown
|
|
15
|
-
License-File: LICENSE
|
|
16
|
-
Requires-Dist: numpy
|
|
17
|
-
Requires-Dist: scipy
|
|
18
|
-
Requires-Dist: networkx
|
|
19
|
-
Requires-Dist: typing
|
|
20
|
-
Requires-Dist: joblib
|
|
21
|
-
|
|
22
|
-
In this package, we implement popular network diffusion models and methods for their estimation.
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: InfluenceDiffusion
|
|
3
|
-
Version: 0.0.11
|
|
4
|
-
Summary: InfluenceDiffusion package
|
|
5
|
-
Author: Alexander Kagan
|
|
6
|
-
Author-email: <amkagan@umich.edu>
|
|
7
|
-
Keywords: python,Influence Maximization,Network diffusion models,General Linear Threshold model,Social Networks,Independent Cascade model
|
|
8
|
-
Classifier: Development Status :: 3 - Alpha
|
|
9
|
-
Classifier: Intended Audience :: Education
|
|
10
|
-
Classifier: Programming Language :: Python :: 2
|
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Operating System :: MacOS :: MacOS X
|
|
13
|
-
Classifier: Operating System :: Microsoft :: Windows
|
|
14
|
-
Description-Content-Type: text/markdown
|
|
15
|
-
License-File: LICENSE
|
|
16
|
-
Requires-Dist: numpy
|
|
17
|
-
Requires-Dist: scipy
|
|
18
|
-
Requires-Dist: networkx
|
|
19
|
-
Requires-Dist: typing
|
|
20
|
-
Requires-Dist: joblib
|
|
21
|
-
|
|
22
|
-
In this package, we implement popular network diffusion models and methods for their estimation.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{influencediffusion-0.0.11 → influencediffusion-0.0.13}/InfluenceDiffusion/weight_samplers.py
RENAMED
|
File without changes
|
{influencediffusion-0.0.11 → influencediffusion-0.0.13}/InfluenceDiffusion.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{influencediffusion-0.0.11 → influencediffusion-0.0.13}/InfluenceDiffusion.egg-info/requires.txt
RENAMED
|
File without changes
|
{influencediffusion-0.0.11 → influencediffusion-0.0.13}/InfluenceDiffusion.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|