Repository: networkx/networkx

Issue:
Clustering coefficient of weighted graph
Hi! I'm trying to use networkx.algorithms.cluster.clustering to calculate the clustering coefficient of a weighted network. I noticed that the formula listed in the networkx reference is slightly different from the formula in the paper being cited [1]. Could I ask why?

In the [networkx reference](https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.cluster.clustering.html#networkx.algorithms.cluster.clustering), the constant number in the numerator is 1. In the paper[1], that constant number is 2. 

I believe it should be 2, as it should be adapted from the calculation of all possible triangles, namely deg(u)(deg(u-1))/2. 

Thanks!

[1] Intensity and coherence of motifs in weighted complex networks by J. P. Onnela, J. Saramäki, J. Kertész, and K. Kaski, Physical Review E, 71(6), 065103 (2005).


Discussion:
That is a confusing part of the docs. I think the confusion is caused by the code where the term `triangles` is used to represent what is actually two times the number of triangles. The code correctly includes the 2, but someone looking at the code might think the 2 is not there. So I suspect the docs incorrectly interpreted the code as not have the factor of 2. 

While we're changing the docs for `clustering`, they don't even show the formula used for a weighted directed clustering case.
Thanks for the clarification!

Resolving patch:
diff --git a/networkx/algorithms/cluster.py b/networkx/algorithms/cluster.py
--- a/networkx/algorithms/cluster.py
+++ b/networkx/algorithms/cluster.py
@@ -85,6 +85,9 @@ def _weighted_triangles_and_degree_iter(G, nodes=None, weight="weight"):
     """Return an iterator of (node, degree, weighted_triangles).
 
     Used for weighted clustering.
+    Note: this returns the geometric average weight of edges in the triangle.
+    Also, each triangle is counted twice (each direction).
+    So you may want to divide by 2.
 
     """
     if weight is None or G.number_of_edges() == 0:
@@ -105,7 +108,7 @@ def wt(u, v):
         seen = set()
         for j in inbrs:
             seen.add(j)
-            # This prevents double counting.
+            # This avoids counting twice -- we double at the end.
             jnbrs = set(G[j]) - seen
             # Only compute the edge weight once, before the inner inner
             # loop.
@@ -122,6 +125,8 @@ def _directed_triangles_and_degree_iter(G, nodes=None):
     (node, total_degree, reciprocal_degree, directed_triangles).
 
     Used for directed clustering.
+    Note that unlike `_triangles_and_degree_iter()`, this function counts
+    directed triangles so does not count triangles twice.
 
     """
     nodes_nbrs = ((n, G._pred[n], G._succ[n]) for n in G.nbunch_iter(nodes))
@@ -154,6 +159,8 @@ def _directed_weighted_triangles_and_degree_iter(G, nodes=None, weight="weight")
     (node, total_degree, reciprocal_degree, directed_weighted_triangles).
 
     Used for directed weighted clustering.
+    Note that unlike `_weighted_triangles_and_degree_iter()`, this function counts
+    directed triangles so does not count triangles twice.
 
     """
     if weight is None or G.number_of_edges() == 0:
@@ -300,7 +307,7 @@ def clustering(G, nodes=None, weight=None):
 
     .. math::
 
-       c_u = \frac{1}{deg^{tot}(u)(deg^{tot}(u)-1) - 2deg^{\leftrightarrow}(u)}
+       c_u = \frac{2}{deg^{tot}(u)(deg^{tot}(u)-1) - 2deg^{\leftrightarrow}(u)}
              T(u),
 
     where :math:`T(u)` is the number of directed triangles through node
@@ -362,6 +369,7 @@ def clustering(G, nodes=None, weight=None):
                 for v, dt, db, t in td_iter
             }
     else:
+        # The formula 2*T/(d*(d-1)) from docs is t/(d*(d-1)) here b/c t==2*T
         if weight is not None:
             td_iter = _weighted_triangles_and_degree_iter(G, nodes, weight)
             clusterc = {v: 0 if t == 0 else t / (d * (d - 1)) for v, d, t in td_iter}


Test patch: