随机采样与图模型算法解析
1. 随机采样方法
随机采样在很多领域都有重要应用,这里介绍两种常见的随机采样方法:排他采样和基于拒绝的采样。
1.1 排他采样(Exclusive Sampling)
排他采样用于从长度为 $M$ 的给定序列 $x[]$ 中随机且无放回地提取 $m$ 个数字。其实现思路简单,每次从剩余的 $K$ 个元素中均匀随机采样一个元素,将其与序列 $x[]$ 的最后一个元素交换,然后将序列 $x[]$ 的有效大小减 1。以下是具体的算法实现:
Algorithm 25 exclusive_sampling()
Input: x, m
Output: v
1: K ← M
2: for all i in 0 to m - 1 do
3:
ξ ← RAND(0, 1)
4:
j ← ⌊Kξ⌋
5:
v[i] ← x[j]
6:
tmp ← x[j]
7:
x[j] ← x[K]
8:
x[K] ← tmp
9:
K ← K − 1
10: end for
该算法的时间复杂度为 $O(m)$,但缺点是会修改输入序列 $x[]$ 的顺序。若 $m$ 远小于 $M$,复制 $x[]$ 到临时向量的方法效率不高。
1.2 基于拒绝的排他采样(Exclusive Sampling with Rejection)
为避免修改输入序列,可采用基于拒绝的采样算法。该算法通过不断随机采样,若采样的数字已存在则拒绝并重新采样,直到得到 $m$ 个不同的数字。
Algorithm 26 exclusive_sampling_rejection()
1: for all i = 1 to m do
2:
ξ ← RAND(0, 1)
3:
j = ⌊Mξ⌋
4:
if j ∉ [seq1, ..., seqi−1] then
5:
seqi = j
6:
else
7:
go to 2:
8:
end if
9: end for
该算法在内存使用上很有效,时间效率取决于第 4 行的实现。若顺序检查,整个算法的时间复杂度为 $O(m^2)$($m \ll M$)。使用二叉搜索树可将检查新元素是否已采样的时间复杂度降为 $O(log M)$。
2. Erdős 和 Rényi 随机图模型采样
这里介绍两种 Erdős 和 Rényi(ER)随机图模型的采样方法,分别对应模型 A 和模型 B。
2.1 模型 A(GER_N,K)采样
模型 A 用于生成具有 $N$ 个节点和 $K$ 条边的随机图。一种简单方法是随机采样 $K$ 对节点 $(i, j)$,检查是否有环和重复边,若有则拒绝并重新采样。为提高效率,可将 $M = N(N - 1)/2$ 条可能的边唯一映射到 $[1, N(N - 1)/2]$ 的整数,将边采样转化为整数的排他采样。
以下是使用整数拒绝采样的算法:
Algorithm 27 ER_A()
Input: N, K
Output: G
1: t ← empty_tree()
2: n ← 0
3: while n < K do
4:
i ← ⌊RAND(0, 1)N⌋
5:
j ← ⌊RAND(0, 1)N⌋
6:
if i = j then
7:
goto 4
8:
end if
9:
i ← max(i, j)
10:
j ← min(i, j)
11:
k ← (i)(i - 1)/2 + j + 1
12:
if k ∉ t then
13:
insert(k, t)
14:
n ← n + 1
15:
end if
16: end while
17: dump_edges()
该算法的时间复杂度为 $O(K log K)$,内存存储需求为 $O(K)$。对于稀疏图($K$ 为 $O(N)$),该算法效率高;对于稠密图,拒绝率可能较高,可使用无拒绝的整数排他采样。
边的编号规则如下表所示:
| i\j | 0 | 1 | 2 | 3 | 4 | … |
| — | — | — | — | — | — | — |
| 1 | 1 | 2 | | | | |
| 2 | 3 | | | | | |
| 3 | 4 | 5 | 6 | | | |
| 4 | 7 | 8 | 9 | 10 | | |
| 5 | 11 | 12 | 13 | 14 | 15 | |
| … | … | … | … | … | … | … |
边 $(i, j)$ 对应的编号 $k$ 计算公式为:$k = \frac{i(i - 1)}{2} + j + 1$。
2.2 模型 B(GER_N,p)采样
模型 B 用于生成具有 $N$ 个节点,每对节点以概率 $p$ 相连的随机图。算法遍历所有可能的边,对于每条边,随机采样一个值 $\xi$,若 $\xi \leq p$,则添加该边。
Algorithm 28 ER_B()
Input: N, p
Output: K, i, j
1: K ← 0
2: for all k = 1 to N ∗ (N - 1)/2 do
3:
ξ ← RAND(0, 1)
4:
if ξ ≤ p then
5:
compute (¯i, ¯j) from k using Eqs. (A.25,A.26,A.27)
6:
i[K] ← ¯i, j[K] ← ¯j
7:
K ← K + 1
8:
end if
9: end for
该算法的时间复杂度为 $O(N^2)$,对于稀疏图($p \ll 1$),由于大量拒绝,效率较低。另一种方法是先从二项分布中采样整数 $K^*$,再使用模型 A 的算法生成图。
3. Watts - Strogatz 小世界模型
该模型用于构建小世界图,首先介绍创建 $(N, m)$ 环形图的方法,然后介绍采样 $(N, m, p)$ Watts - Strogatz(WS)小世界图的算法。
3.1 创建环形图
将 $N$ 个节点放置在一个圆上,按顺时针顺序编号。对于每个节点 $i$,创建其到后续 $m$ 个相邻节点的边。以下是创建环形图的算法:
Algorithm 29 create_circle()
Input: N, m
Output: R(N,m)
1: K ← 0
2: for i = 0 to N - 1 do
3:
for j = 1 to m do
4:
ℓ ← (i + j) mod(N)
5:
i[K] ← i; j[K] ← ℓ
6:
K ← K + 1
7:
i[K] ← ℓ; j[K] ← i
8:
K ← K + 1
9:
end for
10: end for
3.2 采样 WS 小世界图
在环形图的基础上,以概率 $p$ 对边进行重连。若重连后的边不存在,则替换原边。
Algorithm 30 ws()
Input: N, m, p
Output: WS(G, p)
1: create_circle(N,m)
2: for i = 0 to N - 1 do
3:
for j = 1 to m do
4:
ℓ ← (i + j) mod (N)
5:
ξ ← RAND(0,1)
6:
if ξ < p then
7:
ξ1 ← RAND(0,1)
8:
ℓ′ ← ⌊Nξ1⌋
9:
if (i, ℓ′) exists or ℓ′ = i or ℓ′ = ℓ then
10:
goto 7
11:
else
12:
replace (i, ℓ) with (i, ℓ′)
13:
end if
14:
end if
15:
end for
16: end for
该算法的时间复杂度为 $O(K + (C + R) \times pK)$,通过存储边到二叉树,可将 $C$ 和 $R$ 降为 $O(log K)$,时间复杂度主要为 $O(K log K)$。利用环形图的特殊结构,可将时间复杂度降为 $O(Nm^2)$。
以下是创建 WS 小世界图的流程图:
graph TD;
A[开始] --> B[创建环形图];
B --> C[遍历节点];
C --> D[遍历节点的 m 个后继节点];
D --> E{以概率 p 决定是否重连};
E -- 是 --> F[随机选择新节点 ℓ′];
F --> G{检查新边是否存在};
G -- 否 --> H[替换边];
G -- 是 --> D;
E -- 否 --> D;
D --> I{是否遍历完所有节点};
I -- 否 --> C;
I -- 是 --> J[结束];
4. 配置模型
配置模型用于采样具有指定度序列的随机图。首先为每个节点分配与其度相等数量的 stub(半条边),然后将 stub 配对形成图。
4.1 允许环和多重边的算法
该算法简单地连接 $K$ 对 stub,每个 stub 随机采样。
Algorithm 31 conf_model_multigraph()
Input: Degree sequence {k1, k2, ..., kN}
Output: configuration model multigraph with degree sequence {k1, k2, ..., kN}
1: S ← 0
2: for i = 1 to N do
3:
for j = 1 to ki do
4:
stubs[S] ← i
5:
S ← S + 1
6:
end for
7: end for
8: while S > 0 do
9:
ℓ1 ← ⌊S × RAND(0, 1)⌋
10:
S ← S - 1
11:
ℓ2 ← ⌊S × RAND(0, 1)⌋
12:
S ← S - 1
13:
if ℓ1 = ℓ2 then
14:
{reject the sample: it’s the same stub!!!}
15:
S ← S + 2
16:
goto line 8
17:
end if
18:
i1 ← stubs[ℓ1]
19:
i2 ← stubs[ℓ2]
20:
stubs[ℓ1] ← stubs[S + 1]
21:
stubs[ℓ2] ← stubs[S]
22:
create a link between node i1 and node i2
23: end while
该算法的时间复杂度为 $O(K)$,但不能保证生成的图没有环和多重边。
4.2 避免环和多重边的算法
该算法在连接 stub 时,检查是否会形成环或多重边,若会则拒绝并重新采样。
Algorithm 32 conf_model_pair_reject()
Input: Degree sequence {k1, k2, ..., kN}
Output: configuration model graph with degree sequence {k1, k2, ..., kN}
1: S ← 0
2: for i = 1 to N do
3:
for j = 1 to ki do
4:
stubs[S] ← i
5:
S ← S + 1
6:
end for
7: end for
8: while S > 0 do
9:
ℓ1 ← ⌊S × RAND(0, 1)⌋
10:
S ← S - 1
11:
ℓ2 ← ⌊S × RAND(0, 1)⌋
12:
S ← S - 1
13:
if ℓ1 = ℓ2 then
14:
{reject the sample - It’s the same stub!}
15:
S ← S + 2
16:
goto line 8
17:
end if
18:
if i1 ≠ i2 and (i1, i2) is not a link then
19:
create the link (i1, i2)
20:
stubs[ℓ1] ← stubs[S + 1]
21:
stubs[ℓ2] ← stubs[S]
22:
else
23:
{reject the pair to avoid multiple edges or loops}
24:
S ← S + 2
25:
goto line 8
26:
end if
27: end while
该算法的时间复杂度为 $O(K log K)$,但可能会进入无限循环。
4.3 改进的避免环和多重边的算法
该算法在多次连续拒绝后,重新从初始度序列开始尝试。
Algorithm 33 conf_model_pair_reject_check()
Input: Degree sequence {k1, k2, ..., kN}
Output: configuration model graph with degree sequence {k1, k2, ..., kN}
1: num_attempts ← 0, countreject ← 0
2: if num_attempts > max_attempts then
3:
print an error message
4:
exit
5: end if
6: S ← 0
7: for i = 1 to N do
8:
for j = 1 to ki do
9:
stubs[S] ← i
10:
S ← S + 1
11:
end for
12: end for
13: while S > 0 do
14:
ℓ1 ← ⌊S × RAND(0, 1)⌋
15:
S ← S - 1
16:
ℓ2 ← ⌊S × RAND(0, 1)⌋
17:
S ← S - 1
18:
if ℓ1 = ℓ2 then
19:
{reject the sample - It’s the same stub!}
20:
S ← S + 2
21:
goto line 13
22:
end if
23:
if i1 ≠ i2 and (i1, i2) is not a link then
24:
create the link (i1, i2)
25:
stubs[ℓ1] ← stubs[S + 1]
26:
stubs[ℓ2] ← stubs[S]
27:
countreject ← 0
28:
else
29:
{reject the pair to avoid multiple edges or loops}
30:
S ← S + 2
31:
countreject ← countreject + 1
32:
goto line 13
33:
end if
34:
if countreject > maxrejects then
35:
num_attempts ← num_attempts + 1
36:
goto line 1
37:
end if
38: end while
该算法每次尝试的时间复杂度为 $O(K log K)$,通过设置最大尝试次数避免无限循环。
4.4 检查度序列是否可压缩
可通过检查度序列是否可连续压缩来判断是否存在无环和多重边的图。以下是检查度序列是否可连续压缩的算法:
Algorithm 34 check_successively_compressible()
Input: degrees[]
Output: {TRUE | FALSE}
1: for i in 0 to N - 1 do
2:
sort_sequence_decreasing(degrees)
3:
if degrees[0] ≥ N - 1 - i then
4:
return FALSE
5:
end if
6:
k ← degrees[0]
7:
degrees[0] ← 0
8:
for j in 1 to k do
9:
degrees[j] ← degrees[j] - 1
10:
end for
11: end for
12: return TRUE
该算法的时间复杂度为 $O(N^2 log N)$,通常直接使用算法 33 尝试构建图更方便。若算法 33 失败,可再检查度序列是否可连续压缩。
相关程序可从 www.complex - networks.net 下载,包括实现算法 33 的 conf_model_deg、实现算法 31 的 conf_model_deg_nocheck 和检查度序列是否可压缩的 check_compressible。
综上所述,不同的随机采样和图模型算法各有优缺点,在实际应用中,需根据具体需求和数据特点选择合适的算法。例如,对于稀疏图和稠密图,应选择不同的 ER 随机图采样算法;对于配置模型,要根据是否允许环和多重边选择相应的算法。同时,可通过检查度序列的可压缩性来提前判断是否能生成无环和多重边的图。
随机采样与图模型算法解析
5. 算法复杂度对比与选择建议
为了更清晰地了解各种算法的性能特点,下面对上述介绍的算法进行复杂度对比,并给出选择建议。
| 算法名称 | 时间复杂度 | 空间复杂度 | 适用场景 | 优缺点 |
|---|---|---|---|---|
| exclusive_sampling() | $O(m)$ | 取决于输入序列 | 从短序列中进行少量无放回采样 | 简单高效,但会修改输入序列顺序 |
| exclusive_sampling_rejection() | 顺序检查:$O(m^2)$;二叉树检查:$O(m log M)$ | $O(m)$ | 避免修改输入序列的无放回采样 | 内存使用有效,顺序检查效率低,二叉树检查可提高效率 |
| ER_A() | $O(K log K)$ | $O(K)$ | 稀疏图采样($K$ 为 $O(N)$) | 对于稀疏图效率高,稠密图拒绝率可能高 |
| ER_B() | $O(N^2)$ | 取决于图的存储方式 | 每对节点有固定连接概率的图采样 | 简单直接,稀疏图效率低 |
| create_circle() | $O(Nm)$ | 取决于图的存储方式 | 创建环形图 | 简单直观,用于构建小世界图基础 |
| ws() | 二叉树存储:$O(K log K)$;利用环形图结构:$O(Nm^2)$ | 取决于图的存储方式 | 构建小世界图 | 可控制图的小世界特性,复杂度受存储和结构利用影响 |
| conf_model_multigraph() | $O(K)$ | $O(2K)$ | 允许环和多重边的图采样 | 简单快速,但不能保证图的质量 |
| conf_model_pair_reject() | $O(K log K)$ | $O(K)$ | 避免环和多重边的图采样 | 能保证图的质量,但可能进入无限循环 |
| conf_model_pair_reject_check() | $O(K log K)$ | $O(K)$ | 避免环和多重边的图采样,防止无限循环 | 可避免无限循环,多次尝试增加时间开销 |
| check_successively_compressible() | $O(N^2 log N)$ | 取决于排序算法 | 检查度序列是否可生成无环和多重边的图 | 可提前判断度序列可行性,但复杂度高 |
根据以上对比,选择算法时可参考以下建议:
-
随机采样
:若对输入序列顺序无要求且采样数量较少,优先选择
exclusive_sampling()
;若需避免修改输入序列,可使用
exclusive_sampling_rejection()
并结合二叉树检查。
-
ER 随机图模型
:对于稀疏图,使用
ER_A()
;对于每对节点连接概率固定的情况,使用
ER_B()
,但稀疏图时效率较低。
-
Watts - Strogatz 小世界模型
:若图规模较小或对时间复杂度要求不高,可使用二叉树存储边;若图规模较大,利用环形图的特殊结构可提高效率。
-
配置模型
:若允许环和多重边,使用
conf_model_multigraph()
;若需避免环和多重边,优先使用
conf_model_pair_reject_check()
,可避免无限循环。
6. 实际应用案例分析
以下通过几个实际应用案例,进一步说明这些算法在不同场景中的应用。
6.1 社交网络模拟
在社交网络模拟中,可使用 ER 随机图模型或 Watts - Strogatz 小世界模型来生成网络结构。
-
ER 随机图模型
:假设要模拟一个具有 $N = 1000$ 个节点,边数 $K = 2000$ 的社交网络,可使用
ER_A()算法。该算法能快速生成具有指定节点和边数的随机图,模拟社交网络中节点之间的随机连接。
# 示例代码调用 ER_A()
N = 1000
K = 2000
G = ER_A(N, K)
-
Watts - Strogatz 小世界模型
:若要模拟具有小世界特性的社交网络,即节点之间既有局部聚集性又有少量长距离连接,可使用
ws()算法。例如,设置 $N = 1000$,$m = 3$,$p = 0.1$。
# 示例代码调用 ws()
N = 1000
m = 3
p = 0.1
WS_G = ws(N, m, p)
6.2 电力网络建模
在电力网络建模中,配置模型可用于生成具有指定节点度序列的网络。假设已知电力网络中各节点的度序列为
{3, 3, 2, 2, 1, 1}
,可使用
conf_model_pair_reject_check()
算法生成无环和多重边的网络。
# 示例代码调用 conf_model_pair_reject_check()
degree_sequence = [3, 3, 2, 2, 1, 1]
G = conf_model_pair_reject_check(degree_sequence)
7. 算法优化思路与未来发展方向
虽然上述算法在各自的应用场景中具有一定的优势,但仍有优化的空间。以下是一些算法优化思路和未来发展方向。
7.1 算法优化思路
-
减少拒绝次数
:在
ER_A()和配置模型的算法中,拒绝采样会增加时间开销。可通过改进采样策略,如使用启发式算法,减少拒绝次数,提高算法效率。 -
并行计算
:对于大规模图的采样和构建,可利用并行计算技术,如多核处理器或分布式计算,加速算法执行。例如,在
ws()算法中,可并行处理不同节点的边重连操作。 - 数据结构优化 :选择更高效的数据结构存储图和采样结果,如使用哈希表替代二叉搜索树,可进一步提高查找和插入操作的效率。
7.2 未来发展方向
- 动态图模型 :现有的算法主要针对静态图,未来可研究动态图模型的采样和构建算法,以适应不断变化的网络结构,如社交网络中用户的加入和退出、电力网络中线路的故障和修复等。
- 结合机器学习 :将机器学习技术与图模型算法相结合,如使用深度学习模型预测节点的连接概率,可生成更符合实际情况的图。
- 跨领域应用 :将图模型算法应用到更多领域,如生物信息学、交通网络分析等,拓展算法的应用范围。
以下是算法优化和发展方向的流程图:
graph TD;
A[算法优化] --> B[减少拒绝次数];
A --> C[并行计算];
A --> D[数据结构优化];
E[未来发展] --> F[动态图模型];
E --> G[结合机器学习];
E --> H[跨领域应用];
8. 总结
本文详细介绍了多种随机采样和图模型算法,包括排他采样、ER 随机图模型、Watts - Strogatz 小世界模型和配置模型等。通过对算法的原理、复杂度分析和实际应用案例的介绍,我们了解到不同算法的优缺点和适用场景。在实际应用中,应根据具体需求和数据特点选择合适的算法,并可通过优化算法和探索新的发展方向,提高算法的效率和适用性。同时,相关程序可从 www.complex - networks.net 下载,方便开发者进行实践和应用。希望本文能为读者在随机采样和图模型算法的学习和应用中提供有益的参考。
超级会员免费看
727

被折叠的 条评论
为什么被折叠?



