Skip to content

Commit

Permalink
Merge 555baa1 into 07ccf04
Browse files Browse the repository at this point in the history
  • Loading branch information
dsalvaz committed Oct 18, 2019
2 parents 07ccf04 + 555baa1 commit 1231da0
Show file tree
Hide file tree
Showing 13 changed files with 765 additions and 28 deletions.
1 change: 1 addition & 0 deletions cdlib/__init__.py
@@ -1,3 +1,4 @@
from cdlib.classes.node_clustering import NodeClustering
from cdlib.classes.edge_clustering import EdgeClustering
from cdlib.classes.fuzzy_node_clustering import FuzzyNodeClustering
from cdlib.classes.attr_node_clustering import AttrNodeClustering
1 change: 1 addition & 0 deletions cdlib/algorithms/__init__.py
@@ -1,3 +1,4 @@
from .edge_clustering import *
from .crisp_partition import *
from .overlapping_partition import *
from .attribute_clustering import *
112 changes: 112 additions & 0 deletions cdlib/algorithms/attribute_clustering.py
@@ -0,0 +1,112 @@
import Eva

from collections import defaultdict
from cdlib import AttrNodeClustering

import networkx as nx

from cdlib.utils import convert_graph_formats

from cdlib.algorithms.internal.ILouvain import ML2

__all__ = ['eva', 'ilouvain']

def eva(g, labels, weight='weight', resolution=1., randomize=False, alpha=0.5):

"""
The Eva algorithm extends the Louvain approach in order to deal with the attributes of the nodes (aka Louvain Extended to Vertex Attributes).
It optimizes - combining them linearly - two quality functions, a structural and a clustering one, namely Newman's modularity and purity, estimated as the product of the frequencies of the most frequent labels carried by the nodes within the communities.
A parameter alpha tunes the importance of the two functions: an high value of alpha favors the clustering criterion instead of the structural one.
:param g: a networkx/igraph object
:param labels: dictionary specifying for each node (key) a dict (value) specifying the name attribute (key) and its value (value)
:param weight: str, optional the key in graph to use as weight. Default to 'weight'
:param resolution: double, optional Will change the size of the communities, default to 1.
:param randomize: boolean, optional Will randomize the node evaluation order and the community evaluation order to get different partitions at each call, default False
:param alpha: float, assumed in [0,1], optional Will tune the importance of modularity and purity criteria, default to 0.5
:return: AttrNodeClustering object
:Example:
>>> from cdlib.algorithms import eva
>>> import networkx as nx
>>> import random
>>> l1 = ['A', 'B', 'C', 'D']
>>> l2 = ["E", "F", "G"]
>>> g_attr = nx.barabasi_albert_graph(100, 5)
>>> labels=dict()
>>> for node in g_attr.nodes():
>>> labels[node]={"l1":random.choice(l1), "l2":random.choice(l2)}
>>> communities = eva(g_attr, labels, alpha=0.8)
:References:
1. #####
.. note:: Reference implementation: https://github.com/GiulioRossetti/Eva/tree/master/Eva
"""

g = convert_graph_formats(g, nx.Graph)
nx.set_node_attributes(g, labels)

coms, coms_labels = Eva.eva_best_partition(g, weight=weight, resolution=resolution, randomize=randomize, alpha=alpha)

# Reshaping the results
coms_to_node = defaultdict(list)
for n, c in coms.items():
coms_to_node[c].append(n)

coms_eva = [list(c) for c in coms_to_node.values()]
return AttrNodeClustering(coms_eva, g, "Eva", coms_labels, method_parameters={"weight": weight, "resolution": resolution,
"randomize": randomize, "alpha":alpha})


def ilouvain(g, labels, id):
"""
The I-Louvain algorithm extends the Louvain approach in order to deal only with the scalar attributes of the nodes.
It optimizes Newman's modularity combined with an entropy measure.
:param g: a networkx/igraph object
:param labels: dictionary specifying for each node (key) a dict (value) specifying the name attribute (key) and its value (value)
:param id: a dict specifying the node id
:return: AttrNodeClustering object
:Example:
>>> from cdlib.algorithms import ilouvain
>>> import networkx as nx
>>> import random
>>> l1 = [0.1, 0.4, 0.5]
>>> l2 = [34, 3, 112]
>>> g_attr = nx.barabasi_albert_graph(100, 5)
>>> labels=dict()
>>> for node in g_attr.nodes():
>>> labels[node]={"l1":random.choice(l1), "l2":random.choice(l2)}
>>> id = dict()
>>> for n in g.nodes():
>>> id[n] = n
>>> communities = ilouvain(g_attr, labels, id)
:References:
1. Combe D., Largeron C., Géry M., Egyed-Zsigmond E. "I-Louvain: An Attributed Graph Clustering Method". <https://link.springer.com/chapter/10.1007/978-3-319-24465-5_16> In: Fromont E., De Bie T., van Leeuwen M. (eds) Advances in Intelligent Data Analysis XIV. IDA (2015). Lecture Notes in Computer Science, vol 9385. Springer, Cham
"""


g = convert_graph_formats(g, nx.Graph)
nx.set_node_attributes(g, labels)
id = dict()
for n in g.nodes():
id[n] = n

algo = ML2(g,labels, id)
coms = algo.findPartition()

# Reshaping the results
coms_to_node = defaultdict(list)
for n, c in coms.items():
coms_to_node[c].append(n)

coms_ilouv = [list(c) for c in coms_to_node.values()]

return AttrNodeClustering(coms_ilouv, g, "ILouvain")
1 change: 0 additions & 1 deletion cdlib/algorithms/crisp_partition.py
Expand Up @@ -965,4 +965,3 @@ def sbm_dl_nested(g, B_min=None,B_max=None, deg_corr=True, **kwargs):
coms = affiliations2nodesets(affiliations)
coms = [list(v) for k,v in coms.items()]
return NodeClustering(coms, g, "SBM_nested", method_parameters={"B_min": B_min, "B_max": B_max, "deg_corr": deg_corr})

0 comments on commit 1231da0

Please sign in to comment.