如何检查网络是否无标度?

时间:2018-04-18 19:56:38

标签: python numpy matplotlib networkx complex-networks

鉴于无向网络X图graph,我想检查它是否无标度。

为此,据我所知,我需要找到每个节点的k度,以及整个网络中该度P(k)的频率。由于度数的频率与度数本身之间的关系,这应该代表幂律曲线。

绘制P(k)和k的计算结果会显示预期的功率曲线,但是当我对其进行双重记录时,不会绘制直线。

以1000个节点获得以下图表。

P(k) - k graph

double log graph of P(k) - k

代码如下:

k = []
Pk = []

for node in list(graph.nodes()):
    degree = graph.degree(nbunch=node)
    try:
        pos = k.index(degree)
    except ValueError as e:
        k.append(degree)
        Pk.append(1)
    else:
        Pk[pos] += 1

# get a double log representation
for i in range(len(k)):
    logk.append(math.log10(k[i]))
    logPk.append(math.log10(Pk[i]))

order = np.argsort(logk)
logk_array = np.array(logk)[order]
logPk_array = np.array(logPk)[order]
plt.plot(logk_array, logPk_array, ".")
m, c = np.polyfit(logk_array, logPk_array, 1)
plt.plot(logk_array, m*logk_array + c, "-")

m应该表示缩放系数,如果它在2到3之间,那么网络应该是无标度的。

通过调用NetworkX的scale_free_graph方法获取图形,然后将其用作Graph构造函数的输入。

更新

根据@Joel的要求,下面是10000个节点的图 此外,生成图表的确切代码如下:
graph = networkx.Graph(networkx.scale_free_graph(num_of_nodes))

正如我们所看到的,大量值似乎形成一条直线,但网络似乎在其双重日志形式中有一个奇怪的尾部。

P(k) plot from 10000 nodes double log P(k) plot from 10000 nodes

3 个答案:

答案 0 :(得分:1)

您是否在python中尝试过powerlaw模块? 非常简单。

首先,从您的网络中创建一个学位分布变量:

degree_sequence = sorted([d for n, d in G.degree()], reverse=True) # used for degree distribution and powerlaw test

然后将数据拟合到幂律和其他分布:

import powerlaw # Power laws are probability distributions with the form:p(x)∝x−α
fit = powerlaw.Fit(degree_sequence) 

要考虑到幂律,它会通过从数据集中的每个唯一值开始创建幂律拟合来自动找到xmin的最佳alpha值,然后选择一个导致数据之间最小Kolmogorov-Smirnov距离D的幂律。和适合。如果要包含所有数据,则可以如下定义xmin值:

fit = powerlaw.Fit(degree_sequence, xmin=1)

然后您可以绘制:

fig2 = fit.plot_pdf(color='b', linewidth=2)
fit.power_law.plot_pdf(color='g', linestyle='--', ax=fig2)

这将产生如下输出:

powerlaw fit

另一方面,它可能不是幂律分布,而是任何其他分布,例如对数线性等,您也可以检查powerlaw.distribution_compare:

R, p = fit.distribution_compare('power_law', 'exponential', normalized_ratio=True)
print (R, p)

其中,R是两个候选分布之间的似然比。如果第一次发布中的数据可能性更大,则此数字为正,但您还应检查p <0.05

最后,一旦您选择了xmin作为分布,就可以在社交网络的一些常规学位分布之间进行比较:

plt.figure(figsize=(10, 6))
fit.distribution_compare('power_law', 'lognormal')
fig4 = fit.plot_ccdf(linewidth=3, color='black')
fit.power_law.plot_ccdf(ax=fig4, color='r', linestyle='--') #powerlaw
fit.lognormal.plot_ccdf(ax=fig4, color='g', linestyle='--') #lognormal
fit.stretched_exponential.plot_ccdf(ax=fig4, color='b', linestyle='--') #stretched_exponential

lognornal vs powerlaw vs stretched exponential

最后,考虑到网络中的幂律分布正在讨论中,因此从经验上讲,高度无标度的网络似乎很少见

https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6399239/

答案 1 :(得分:0)

你的一部分问题是,你不能包括缺少适合你的生产线的学位。有一小部分大学位节点,你可以在你的队伍中包含这些节点,但是你忽略了许多大学位不存在的事实。你的最大学位在1000-2000范围内,但只有2个观察。实际上,对于如此大的值,我期待随机节点具有如此大的2 /(1000 * N)的概率(或者实际上,它甚至可能甚至小于该值)。但是,在你的情况下,你将它们视为两个特定度数的概率是2 / N,并且你忽略了其他度数。

简单的解决方法是仅使用较小的度数。

更健壮的方法是适应互补的累积分布。不是绘制P(K=k),而是绘制P(K>=k)并尝试拟合(注意如果P(K = k)是概率的概率,那么P(K> = k)的概率也是,但使用不同的指数 - 检查它。

答案 2 :(得分:0)

尝试使一条直线适合这些点是错误的,因为这些点在x轴上不是线性分布的。线的拟合函数将更加重视包含更多点的区域部分。

您应该像这样使用函数np.interp在x轴上重新分配观测值。

logk_interp = np.linspace(np.min(logk_array),np.max(logk_array),1000)
logPk_interp = np.interp(logk_interp, logk_array, logPk_array)
plt.plot(logk_array, logPk_array,".")

m, c = np.polyfit(logk_interp, logPk_interp, 1)
plt.plot(logk_interp, m*logk_interp + c, "-")