mlnlib 0.2.36__tar.gz → 0.2.38__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: mlnlib
3
- Version: 0.2.36
3
+ Version: 0.2.38
4
4
  Summary: Memory-efficient library for loading and working with large unweighted multilayer networks.
5
5
  Author-email: Eszter Bokányi <e.bokanyi@uva.nl>
6
6
  Project-URL: Homepage, https://github.com/popnet-io/popnet_mln
@@ -97,7 +97,7 @@ Example loadings:
97
97
  ```
98
98
  # FROM FILES
99
99
  # import custom class for the network from mln
100
- import MultiLayeredNetwork
100
+ from mlnlib.mln import MultiLayeredNetwork
101
101
 
102
102
  # read the whole network
103
103
  popnet = MultiLayeredNetwork(
@@ -107,7 +107,7 @@ popnet = MultiLayeredNetwork(
107
107
 
108
108
  # FROM MEMORY
109
109
  # import custom class for the network
110
- from mln import MultiLayeredNetwork
110
+ from mlnlib.mln import MultiLayeredNetwork
111
111
 
112
112
  # read the whole network
113
113
  popnet = MultiLayeredNetwork(
@@ -117,7 +117,7 @@ popnet = MultiLayeredNetwork(
117
117
 
118
118
  # FROM LIBRARY
119
119
  # import custom class for the network
120
- from mln import MultiLayeredNetwork
120
+ from mlnlib.mln import MultiLayeredNetwork
121
121
 
122
122
  # read the whole network
123
123
  popnet = MultiLayeredNetwork(
@@ -77,7 +77,7 @@ Example loadings:
77
77
  ```
78
78
  # FROM FILES
79
79
  # import custom class for the network from mln
80
- import MultiLayeredNetwork
80
+ from mlnlib.mln import MultiLayeredNetwork
81
81
 
82
82
  # read the whole network
83
83
  popnet = MultiLayeredNetwork(
@@ -87,7 +87,7 @@ popnet = MultiLayeredNetwork(
87
87
 
88
88
  # FROM MEMORY
89
89
  # import custom class for the network
90
- from mln import MultiLayeredNetwork
90
+ from mlnlib.mln import MultiLayeredNetwork
91
91
 
92
92
  # read the whole network
93
93
  popnet = MultiLayeredNetwork(
@@ -97,7 +97,7 @@ popnet = MultiLayeredNetwork(
97
97
 
98
98
  # FROM LIBRARY
99
99
  # import custom class for the network
100
- from mln import MultiLayeredNetwork
100
+ from mlnlib.mln import MultiLayeredNetwork
101
101
 
102
102
  # read the whole network
103
103
  popnet = MultiLayeredNetwork(
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "mlnlib"
7
- version = "0.2.36"
7
+ version = "0.2.38"
8
8
  authors = [
9
9
  { name="Eszter Bokányi", email="e.bokanyi@uva.nl" },
10
10
  ]
@@ -72,7 +72,7 @@ import networkx as nx
72
72
 
73
73
  import gzip
74
74
 
75
- from mln.preparation import RawCSVtoMLN
75
+ from mlnlib.preparation import RawCSVtoMLN
76
76
 
77
77
  from scipy.sparse import csr_matrix, save_npz, load_npz, eye, block_diag, kron
78
78
  import json
@@ -1673,6 +1673,112 @@ class MultiLayerNetwork:
1673
1673
  self.N = mask.sum()
1674
1674
  self.A = self.A[mask,:][:,mask]
1675
1675
 
1676
+ def get_aggregated_network(self, aggregation_column=None, keep_layers = False, convert_A = "none"):
1677
+ """
1678
+ Return an aggregated network over a certain column in self.nodes.
1679
+
1680
+ It looks at unique values in the column, and aggregates the edges for
1681
+ each unique value. The resulting network has as many nodes as there
1682
+ are unique values in the column. The edges are aggregated by counting all
1683
+ edges from all layers that go between the groups.
1684
+
1685
+ The resulting network is a MultiLayerNetwork object, but instead of the binary
1686
+ adjacency matrix, it has a weighted adjacency matrix, where the weights are
1687
+ the edge counts between the groups.
1688
+
1689
+ Parameters:
1690
+ -------------
1691
+ aggregation_column : string, default None
1692
+ the column in self.nodes based on which the edges should be aggregated
1693
+ -------------
1694
+ """
1695
+
1696
+ if not aggregation_column in self.nodes.columns:
1697
+ raise ValueError(f"Column {aggregation_column} not found in self.nodes. Possible candidates are: ", self.nodes.columns)
1698
+
1699
+
1700
+ if self.use_polars:
1701
+ mask = self.nodes["active"] & self.nodes[aggregation_column].is_not_null()
1702
+ affil_edgelist = list(zip(self.nodes["label"].filter(mask), self.nodes[aggregation_column].filter(mask)))
1703
+ else:
1704
+ mask = self.nodes["active"] & (~pd.isnull(self.nodes[aggregation_column]))
1705
+ affil_edgelist = list(zip(self.nodes["label"][mask], self.nodes[aggregation_column][mask]))
1706
+
1707
+ self.create_affiliation_matrix(aggregation_column,affil_edgelist)
1708
+
1709
+ if convert_A == "boolean":
1710
+ G = self.affiliation_matrix[aggregation_column]["A"].T * self.A.sign() * self.affiliation_matrix[aggregation_column]["A"]
1711
+ elif convert_A == "multiplexity":
1712
+ A = deepcopy(self.A)
1713
+ # create lookup table for mapping binary values to number of layers / multiplexity
1714
+ lookup = {}
1715
+ for num in np.unique(A.data):
1716
+ lookup[num] = bin(num).count("1")
1717
+ # apply lookup table
1718
+ A.data = np.array([lookup[x] for x in A.data])
1719
+ G = self.affiliation_matrix[aggregation_column]["A"].T * A * self.affiliation_matrix[aggregation_column]["A"]
1720
+ elif convert_A == "none":
1721
+ G = self.affiliation_matrix[aggregation_column]["A"].T * self.A * self.affiliation_matrix[aggregation_column]["A"]
1722
+ else:
1723
+ ValueError("Invalid value for convert_A, please choose from none, booelan, or multiplexity.")
1724
+ uniques = [self.affiliation_matrix[aggregation_column]["column_id_to_label"][i] for i in range(self.affiliation_matrix[aggregation_column]["M"])]
1725
+ if 'weight' not in self.nodes.columns:
1726
+ # count occurrences in each aggregation group
1727
+ grp_counts = self.affiliation_matrix[aggregation_column]["A"].sum(axis=0).tolist()[0]
1728
+ else:
1729
+ # sum up previous weights
1730
+ grp_counts = self.nodes[mask].groupby(aggregation_column)['weight'].sum().loc[uniques]
1731
+
1732
+ if self.use_polars:
1733
+ nodes_selected = pl.DataFrame({
1734
+ 'label' : uniques,
1735
+ 'weight' : grp_counts,
1736
+ "id" : [i for i in range(self.affiliation_matrix[aggregation_column]["M"])]
1737
+ }
1738
+ )
1739
+ else:
1740
+ nodes_selected = pd.DataFrame(data={
1741
+ 'label' : uniques,
1742
+ 'weight' : grp_counts,
1743
+ "id" : [i for i in range(self.affiliation_matrix[aggregation_column]["M"])]
1744
+ }
1745
+ )
1746
+
1747
+ # add data related to particular aggregation level
1748
+ if self.use_polars:
1749
+ aggregation_nodes = self.nodes.select([c for c in self.nodes.columns if aggregation_column.split('_')[0] in c]).groupby([aggregation_column]).first()
1750
+ nodes_selected = nodes_selected.join(aggregation_nodes, left_on=['label'], right_on=[aggregation_column], how='left')
1751
+ else:
1752
+ aggregation_nodes = self.nodes.groupby([aggregation_column]).head(1)[[c for c in self.nodes.columns if aggregation_column.split('_')[0] in c]]
1753
+ nodes_selected = nodes_selected.merge(aggregation_nodes, left_on=['label'], right_on=[aggregation_column], how='left')
1754
+
1755
+ f = MultiLayerNetwork(
1756
+ edges = G.tocsr(),
1757
+ nodes = nodes_selected,
1758
+ **self._to_pass
1759
+ )
1760
+
1761
+ # this is only providing raw counts for all selected layers
1762
+ # TODO: it would be more elegant to keep layers!
1763
+ selection_layers = pd.DataFrame(data={'layer' : 1, 'label' : 'count', 'label_long' : 'count_'+convert_A, 'layer' : 'count', 'binary' : 1}, index=[0])
1764
+ selection_layers_dict = {
1765
+ 'binary_to_layer': {1 : 1},
1766
+ 'binary_to_layer' : {1 : 'count'},
1767
+ 'layer_to_layer' : {1 : 'count'},
1768
+ 'layer_to_binary' : {1 : 1},
1769
+ 'layer_to_binary' : {'count' : 1},
1770
+ 'layer_to_layer' : {'count' : 1}
1771
+ }
1772
+
1773
+ f.layers = selection_layers
1774
+ f._layer_conversion_dict = selection_layers_dict
1775
+ # The nodes have changed, therefore new mappings for to_nid and to_label are passed.
1776
+ f._map_label_to_id = dict(zip(f.nodes["label"],f.nodes["id"]))
1777
+ f._map_id_to_label = dict(zip(f.nodes["id"],f.nodes["label"]))
1778
+ f.adjacency_element = "weight"
1779
+
1780
+ return f
1781
+
1676
1782
 
1677
1783
 
1678
1784
 
@@ -1681,4 +1787,4 @@ class MultiLayerNetwork:
1681
1787
 
1682
1788
 
1683
1789
 
1684
-
1790
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: mlnlib
3
- Version: 0.2.36
3
+ Version: 0.2.38
4
4
  Summary: Memory-efficient library for loading and working with large unweighted multilayer networks.
5
5
  Author-email: Eszter Bokányi <e.bokanyi@uva.nl>
6
6
  Project-URL: Homepage, https://github.com/popnet-io/popnet_mln
@@ -97,7 +97,7 @@ Example loadings:
97
97
  ```
98
98
  # FROM FILES
99
99
  # import custom class for the network from mln
100
- import MultiLayeredNetwork
100
+ from mlnlib.mln import MultiLayeredNetwork
101
101
 
102
102
  # read the whole network
103
103
  popnet = MultiLayeredNetwork(
@@ -107,7 +107,7 @@ popnet = MultiLayeredNetwork(
107
107
 
108
108
  # FROM MEMORY
109
109
  # import custom class for the network
110
- from mln import MultiLayeredNetwork
110
+ from mlnlib.mln import MultiLayeredNetwork
111
111
 
112
112
  # read the whole network
113
113
  popnet = MultiLayeredNetwork(
@@ -117,7 +117,7 @@ popnet = MultiLayeredNetwork(
117
117
 
118
118
  # FROM LIBRARY
119
119
  # import custom class for the network
120
- from mln import MultiLayeredNetwork
120
+ from mlnlib.mln import MultiLayeredNetwork
121
121
 
122
122
  # read the whole network
123
123
  popnet = MultiLayeredNetwork(
File without changes
File without changes