Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding rich-core function and test #2706

Closed
wants to merge 8 commits into from
Closed

Conversation

iaciac
Copy link

@iaciac iaciac commented Oct 10, 2017

Extraction of the rich-core of complex networks ad in Ma A and Mondragón RJ (PLoS One, 2015).

@dschult
Copy link
Member

dschult commented Oct 29, 2017

Looks like you need to add an import of richcore into the __init__.py file in the algorithms directory.
Also, then your test can simply call nx.extract_rich_core



import networkx as nx
from networkx.utils import accumulate
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this import is needed.

def extract_rich_core(G, weight='weight'):
"""Returns the core/periphery structure of a weighted undirected network (see [1]).

Args
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section of the docstring should be called Parameters.
Look at other modules to see the expected format.

Also, it would be good to summarize the definition of core/periphery structure in a short paragraph separated from the one-line description by a blank line.

It looks like your docstring is indented an extra space. Some lines may also be too long. Check with the pep8 tool (which checks if your code follows PEP8 standards for python code).

You should use :math: mode for the equations in the docstring.

G = G.to_undirected()

#Looking for the minimal weight
weights = [e[2][weight] for e in G.edges_iter(data=True)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

G.edges_iter won't work with NetworkX V2.0.
Also, you can avoid creating a list of all weights.
Use: minw = min(wt for u, v, wt in G.edges.data(weight))

minw = min(weights)

#Normalising by the minimal weight
for e in G.edges_iter(data=True):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps: for u, v, wt in G.edges.data(weight):

Also, you are mutating the edge weight attribute in this function. A warning should be added to the doc_string or avoided by creating another attribute to store those values. Or even better -- just divide the sigma_i by minw when you store it. Then the original graph doesn't change and I think your calculations and sorting is the same. You also avoide this loop that way.

sigmas.append(sigma_i)

r_star = sigmas.index(max(sigmas))

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should consider a different return data structure.
Of course, it may depend what you expect people to do with the results.

A dict from nodes to sigma values is our usual way to return node properties.
This loses the order of rankings as well as r_star.
Perhaps r_star could be replaced by the node with maximal sigma -- since at this point it is a index of that node. Or you could just give the user the dict of sigma values and let the user find the node with max sigma value.

G.add_edge('a','d',weight=0.3)

sigmas, ranked_nodes, r_star = nx.richcore.extract_rich_core(G, weight='weight')
assert_equal(sigmas, [0, 19.0, 19.0, 19.0, 10.999999999999998, 30.0])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tests with floating point numbers are tricky to get exactly equal.
You might consider from nose.utils import assert_almost_equal for the tests.

There is also a nice way to make sure division works for floating point for python2 and 3. Use this at the top of the rich_core.py module: from __future__ import division Then you don't need to use 1.* when you divide.

@dschult
Copy link
Member

dschult commented Nov 25, 2017

I think the sigma values you return are actually the sigma^+ values, not the sigmas.
Which should be returned?

It also looks like the normalization of weights is not needed (or can be done after all computations).
Calculating strength, rank and boundary node can be done without scaling edge weights and the results for rank and boundary node are the same. Scaling strength by minw can be done after computations if desired, but is not necessary. Am I understanding this correctly?

"Rich-cores in networks".
PLoS One 10(3):e0119678.
"""
if nx.is_directed(G):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not needed, since there is decorator that checks it.


#Normalising by the minimal weight (adding a new attribute)
for u, v, wt in G.edges.data(weight):
G[u][v]['norm_weight']=wt/minw
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a note in the documentation that this function modifies the graph.

import networkx as nx
from collections import OrderedDict
from networkx.utils import not_implemented_for
from __future__ import division
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Must be before any other imports.


.. math::

\sigma_i = \sum_j \frac{w_ij}{w_{min}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be w_{ij}.

@not_implemented_for('directed')
@not_implemented_for('multigraph')
def extract_rich_core(G, weight='weight'):
r"""Returns the core/periphery structure of a the weighted undirected
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first sentence should fit in one line.

@not_implemented_for('directed')
@not_implemented_for('multigraph')
def extract_rich_core(G, weight='weight'):
r"""Returns the core/periphery structure of a the weighted undirected
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: of a the

for j in G.neighbors(i):
if norm_strength[j]>norm_strength[i]:
sigma_i += norm_strength[j]
else: continue
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is unnecessary.

norm_strength = G.degree(weight='norm_weight')
ranked_nodes = [n[0] for n in sorted(norm_strength, key=lambda x: x[1], reverse=True)]

sigmas=OrderedDict()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this line and others there is missing whitespace around the operator.

@dschult dschult added this to the networkx-2.3 milestone Jun 12, 2018
@dschult
Copy link
Member

dschult commented Jun 12, 2018

Needs tests and updates to reflect reviews above.

@dschult dschult modified the milestones: networkx-2.3, networkx-2.4 Mar 28, 2019
@dschult dschult modified the milestones: networkx-2.4, networkx-2.5 Sep 28, 2019
@hagberg hagberg marked this pull request as draft June 25, 2020 20:59
@dschult dschult modified the milestones: networkx-2.5, networkx-2.6 Aug 14, 2020
Base automatically changed from master to main March 4, 2021 18:20
@dschult dschult modified the milestones: networkx-2.6, networkx-3.0 May 18, 2021
@rossbar rossbar modified the milestones: networkx-2.7, networkx-3.0 Feb 12, 2022
@rossbar rossbar removed this from the networkx-3.0 milestone Nov 29, 2022
@rossbar rossbar added this to the networkx-3.1 milestone Nov 29, 2022
@jarrodmillman jarrodmillman removed this from the 3.2 milestone Jul 20, 2023
@MridulS
Copy link
Member

MridulS commented Nov 8, 2023

Thanks for this @iaciac!

This PR hasn't been touched in a while and will need some effort to make it work with the main branch, it's py3.10+ and a bunch of things have changed in networkx over the last 5 years. I'll go ahead and close this PR, feel free to open a new one if you have the bandwidth. Thanks again!

@MridulS MridulS closed this Nov 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

None yet

6 participants