lvlv神奇的算法简介

参考知乎: https://zhuanlan.*/p/556291759

1. 社区发现简介

1.1 社区是什么

        用户以及相互作用关系构成了一个大的关系网络,在网络中会存在一些紧密连接的区域,可以被看成一个社区(这些区域(节点集)通常有自己的属性),社区内部连接紧密,而社区之间连接则相对稀疏(内紧外松)。“社群检测”等同于“给节点分组”。

1.2 社区发现的目标和意图

        社区发现(community detection),也叫团伙挖掘,是风控工作中的核心算法。其目的是在图中找到一些“潜在的有特定关系的组织”,即探测网络中较为紧密的【块cluster】或是【社团】。

     在风控中,很多有目的的团伙聚集在一起,有明显的社群关系。哪个块是高风险,哪个块是高价值,非常值得挖掘。在团伙挖掘的过程中,介质的质量、边的构建思路、以及业务的抽象能力,比什么算法都重要,盲目的在质量不高的数据上,啥算法都没用。

节点间存在连接的抽象本质 - 逻辑拓朴结构: 

        社区的节点间是存在(网络)拓朴连接结构的。注意不能将其和欧式空间或者P空间中的点向量集合空间混为一谈。在社区结构中,节点之间没有什么空间位置的概念。相对的,节点间存在的是一种逻辑拓朴结构,即存在一种共有关系。存在共有关系的节点在逻辑上会聚集为一个社区,而社区之间不存在或者存在很弱的共有关系,则呈现分离的逻辑拓朴结构。

      即使是欧式距离很近的向量点,也不一定就代表这它们之间存在拓朴连接关系,只能说在一定的度量下,这两个节点很相近。注意不要用空间结构的概念来试图理解社区结构,社区中的节点只是因为逻辑上的共有关系而聚集在一起而已,彼此之间的位置也没有实际意义。

一些实际的例子:

1. 假如节点代表消费者:节点间的连接代表了它们共同购买了一批书籍,权重代表共同购买的书籍数,连接越紧密,代表社群的爱好越相近;

2. 假如节点代表消费者:节点间的连接代表了它们共同领取一批优惠券,权重代表共同领取的优惠券的数量,该社群可能是一个羊毛党社群。

3. 假如节点代表商家:节点间的连接代表了它们共同商品标题,权重代表共同标题商品的数量,该社群可能是一个店群商家,不断换点进行欺诈。共同的地点、设备、轨迹、时间、证件等等,都可以作为这种逻辑关系的存在,作为一个网络,进行社区挖掘,达到业务目的。

1.3 什么时候可以使用社区发现算法

        需要先确定要解决的业务场景中,是否存在明显的聚集规律,节点(可以是抽象的)之间形成一定的族群结构,而不是呈现无规律的随机分散。另外这种聚集的结构是“有意义的”,即这种聚集本身可以翻译为一定的业务层面的表现。但很多时候,业务场景中的数据集之间的共有关系并不是表现的很明显,即节点之间或多或少都存在一些共有关系,这样直接进行社区发现效果肯定是不好的,就没必要进行社区发现挖掘。所以在进行社区发现之前,一定要进行数据降噪

      理想情况下,降噪后得到的数据集已经是社区完全内聚,社区间完全零连接,这样 louvain 只要一轮运行就直接得到结果。一般情况下,降噪只要能 cutoff 90%以上的噪音,通过几轮迭代基本就能完成整体的社区发现过程。

1.4 社区划分的直观思路

        同一团内的节点连接更紧密(即具有更大的 density),社区划分有很多不同的算法,如Fast Unfolding (Louvian) 只是其中一种,另外密度评估方法也只是其中一种思想。从算法的思想上看,个人倾向于认为社区发现算法比较适合发现一种"抽象泛共现模式",如:

1. 两个用户拥有共同的介质;

2. 两个用户昵称采用共同的起名方式;(如名字加数字,同样的前缀,都是四字成语等)

3. 用户拥有相同的行为,比如做过同样的操作;

4. 用户拥有共同的控制人;

5. 两个用户发布的内容拥有相似的词频数据;

5. 两个用户拥有相同的运动轨迹 ...

        社区发现的落地效果,很大程度上取决于对业务拓扑逻辑的抽象水平 和 数据降噪的结果,而不取决于发现的算法。并且不同场景,采用的社区发现算法不一样。很多常识在规模面前也不管用,甚至引起认知谬误,因此社区发现算法的结果不可能完美,必须结合业务实际情况进行调节和控制,再应用,不然很难达到预期效果,甚至搞出很多问题。

2. 相关概念

2.1 模块度

        “社群检测”等同于 给节点分组,而模块度(Modularity) 是一种常用的衡量节点分组质量的标准,模块度越高说明所检测到的社团越符合“内紧外松”的特征,分组质量越好。通常计算一个网络的模块度,需要构造一个具有相同节点度分布的随机网络作为参照。一个好的划分结果其表现形式是:在社区内部的节点相似度较高,而在社区外部节点的相似度较低。

      模块度用来衡量一个社区网络划分情况的好坏,取值:[-0.5,1),其物理含义是:在社区内实际的边数(节点的连边数)与随机情况下的边数之差。如果差距比较大,说明社团内部密集程度显著高于随机情况,社团划分的质量较好。如果节点组中的连边数量超过了随机分配时所得到的期望连边数量,模块度为正数。没有超过,则为负数。

      一般模块度取值在0.3~0.7之间就认为有明显的社区结构出现了,

Aij 是节点i 和节点j 之间边的权重,网络不是带权图时,所有边的权重可以看做是1;

ki 表示所有与节点i 相连的边的权重之和(度数);

ci表示节点i 所属的社区,i与j属于同一社区则为1;

m=\frac{1}{2}\sum_{ij}^{}A_{ij} 表示所有边的权重之和(边的数目);

\frac{k_{j}}{2m}  表示节点j 连接到任意一个节点的概率;

现在节点i 有ki 的度数,因此在随机情况下节点i 与j 的边为 k_{i}\frac{k_{j}}{2m}

      可简单理解为:固定节点数,给定图有多少条边,与用同样多节点,随机生成图拥有的边,相减,差越大说明给定图越紧密。模块度简化如下:

        其中Σin 表示社区c内的边的权重之和,Σtot 表示与社区c内的节点相连的边的权重之和。上面的公式还可以进一步简化为:

        这样模块度也可以理解为:

1. 权重图: 社区内部边的权重减去所有与社区节点相连的边的权重和;

2. 无权图:社区内部边的度数减去社区内节点的总度数。

        基于模块度的社区发现算法,都是以最大化模块度Q为目标。(模块度越大,挖掘的社区内部连接越紧密,效果越好)。

2.1.1 模块度最大化算法

       模块度最大值法(Modularity maximization)是一种经典的社团检测方法,其目标是从网络所有可能的节点分组中,找到使得模块度最大的分组方式。由于穷举所有可能的分组十分困难,所以实际的算法都采用近似优化方法。

      如 Mark Newman 提出了模块度最大化的贪婪算法 Fast NewMan (FN)。贪婪算法的原理是找出每个局部最优值,最终将局部最优值整合成整体的近似最优值。

2.1.2 怎么表示一个随机图

        一个好的社区一定是内部的连接要比随机连接情况下的连接更紧密。说到随机,那自然需要一个零模型(图模型),这里选择的是配置模型(configuration model),为了保证与原图有相同的度分布。类似与在介绍 motifs 时运用的模型,不同的是,这里允许有重边(multi edge)的 multigraph。

2.2 权重度

1. 节点权重度

        指与某个点有关(以该点为端点)的所有边的权重和,包括该点的邻边(连接至其它点)以及该点的自环边(连接至该点自身)。如下图,红色节点权重度为 1 + 0.5 + 3 + 1.5 = 6(有三条邻边和一条自环边)。

2. 社区权重度

        指一个社区内所有节点的权重度之和。

1 号社区权重度 = 红色节点的权重度 + 绿点权重度 + 蓝点权重度 + 黄点权重度  

                           = 6 + 2.7 +2.8 +3 = 14.5

3. 社区内部权重度

        仅考虑两个端点均在该社区内的边

1 号社区内部权重度 = 1 号社区权重度 - 该社区和其它社区之间的边的权重

                                   = 14.5 - (1.7 + 0.3 + 2) = 10.5

        注意: 社区内部权重度并不是两个端点均在社区内的边的权重和,而是这些边当中的非自环边的权重和的二倍再加上自环边的权重和 (自环的权重仅计算1次)。

1 号社区内部权重度 = (1 + 0.5 + 3) * 2 + 1.5 = 10.5

4. 全图权重度

        指图中所有节点的权重度的和。如果将全图划分为多个社区,由于图中每个点属于并且仅属于一个社区,全图权重度也等于这些社区的权重度的和。

全图权重度 = 1 号社区权重度 + 2号社区权重度为 + 3 号社区权重度为 

                    = 14.5 + 5.9 + 14.3 = 34.7

        如果将全图看成一个社区,那么全图权重度也可以理解为该社区的内部权重度。

全图权重度 =  (1 + 0.5 + 3 + 1.7 + 0.7 * 3 + 0.3 + 2 + 1 * 6) * 2 + 1.5 = 34.7

2.3 社区压缩

        Louvain 在图数据分析算法中虽然比较复杂的,但别具意义。社区压缩是将每个社区内的所有节点一个聚合点来表示,该社区的内部权重度即为此聚合点的自环边的权重,每两个社区间的边的权重和即为相应两个聚合点之间边的权重。

        对I、II、III三个社区进行压缩,

I 号社区压缩后的自环边的权重为该社区的内部权重,即 10.5;

II 号社区压缩后自环边的权重为 0.7 * 3 * 2 = 4.2,

III 号社区压缩后自环边的权重为 1 * 6 * 2 = 12。

        同时,I 号与 II号社区之间的边压缩后权重为 1.7,与 III 号社区之间的边压缩后权重为 0.3 + 2 = 2.3。

为什么要进行社区压缩?

1. 计算效率更高:进行社区压缩,在不改变局部权重度及全图权重度的前提下,通过最大限度减少图的点、边数量来提高后续(迭代)的计算速度;

2. 实现层级化的社区划分: 社区内的点在压缩后将作为一个整体进行模块度优化的计算,不再拆分,从而实现了层级化(迭代化)的社区划分效果。

2.4 算法结果处理

        经过 Louvain 计算后的社区,是一个多层次的结构,通常如下:

       那么选取哪个层次的社区结构呢。可以将手肘法作为辅助工具,当模块化指数Q或社区数量随着迭代次数增加出现明显拐点时,选取对应层次的社区结构就比较合理啦,比如下面这样的:

 3. 算法流程

        在社区发现算法中Louvain与infomap深受喜爱,思想:不择手段把图的模块化指数Q搞大。Louvain也就是个贪心算法

3.1 两步迭代设计

step1:节点合并

        将图中每个节点都看作一个独立社区,对每个节点i,依次尝试把节点i 分配到其每个邻居节点所在的社区,计算分配前后的模块度变化ΔQ ,并记录ΔQ 最大的那个邻居节点,如果 ΔQ >0,则把节点i 分配ΔQ 最大的那个邻居节点所在的社区,否则保持不变;

      算法扫描数据中的所有节点,针对每个节点遍历该节点的所有邻居节点,衡量把该节点加入其邻居节点所在的社区所带来的模块度的收益。并选择对应最大收益的邻居节点,加入其所在的社区。这一过程化重复进行直到每一个节点的社区归属都不在发生变化。

step2:社区聚合

        对上述形成的社区进行折叠,把每个社区折叠成一个单点,社区内节点之间的边的权重和转化为新节点的自环边的权重,社区间的边权重和转化为新节点间的边权重;重复step1 直到整个图的模块度不再发生变化(所有节点的所属社区不再变化),或算法已经达到了目标(比如最大的ΔQ小于某个值)。

3.2 时间复杂度

       该算法的最大优势就是速度很快,步骤1 的每次迭代的时间复杂度为O(N),N为输入数据中的边的数量。步骤2 的时间复杂度为O(M + N), M为本轮迭代中点的个数。louvain 基于贪心算法实现,实际数据中的平均复杂度为 O(nlog(n)),当每一轮迭代中节点数量降低一半时,能达到平均复杂度。

3.3 模块度增量计算

        该算法能够产生层次性的社区结构,其中计算耗时较多的是最底一层的社区划分,节点按社区压缩后,将大大缩小边和节点数目,并且计算节点i 分配到其邻居j 时,模块度的变化只与节点i、j的社区有关,与其他社区无关,因此计算很快(即只需要计算这个局部ΔQ(不用每次都重新计算全局的ΔQ))。把节点i 分配到邻居节点j 所在的社区c时模块度变化ΔQ为:

        这里好像是ΔQ少了把节点i 从其原来社区删除这一步?进一步化简:

        step2 不同节点的访问顺序会对分群结果有一定影响,但效果差距不大,只是会在一定程度上影响算法的时间效率,有论文指出按度数从大到小的顺序处理速度最快。

1. 初始时将网络中的每个节点都看成独立的小社团;

2. 考虑所有相连社团两两合并的情况,计算每种合并带来的模块度的增量;

3. 基于贪婪原则,选取使模块度增长最大的两个社团,将它们合并成一个社团;

4. 如此循环迭代,随着迭代的进行,模块度不断变化,其最大值时对应最优社团划分。

        后来Vincent Blondel等人运用模块度最大值法原理,提出了Louvain算法,大大降低了算法的时间复杂度。该算法十分适合社会网络等超大规模网络的社团检测,也成为应用最广的算法之一。

4. 算法应用

        Louvain 是基于模块度计算的社区识别算法,是以最大化模块度为目标的一种对顶点进行聚类的迭代过程。主要用于社交网虚假账号识别、消费群体划分及商品推荐、银行卡伪冒和欺诈团伙识别、银行理财产品、保险产品推荐、企业集团及家族企业识别等领域。

安装Louvain:pip3 install python-louvain

1. 自带图

import pandas as pd
import matplotlib.pyplot as plt
import networkx as nx
from community import community_louvain

G = nx.karate_club_graph()  # 空手道俱乐部
node_size = [G.degree(i)**1*20 for i in G.nodes()]  # 节点大小设置、度关联
communities = community_louvain.best_partition(G)
com_df = pd.DataFrame({'cid': communities.values(), 'uid': communities.keys()})  # 格式整理
# 统计每个团伙人数 并降序
df_com.groupby('cid').count().sort_values(by='uid', ascending=False)
print(com_df.head(100))
colors = ['DeepPink', 'orange', 'DarkCyan', '#A0CBE2', '#3CB371', 'b', 'orange',
          'y', 'c', '#838B8B', 'purple', 'olive', '#A0CBE2', '#4EEE94']*500
colors = [colors[i] for i in communities.values()]
plt.figure(figsize=(4, 3), dpi=500)
nx.draw_networkx(G, pos=nx.spring_layout(G),
                 node_color=colors, edge_color='#2E8B57', font_color='black',
                 node_size=node_size, font_size=5,
                 alpha=0.9, width=0.1, font_weight=0.9)
plt.axis('off')
plt.show()

如下:

2. 自定义图

import community
from community import community_louvain
G = nx.Graph()  # 创建一个无向图
# 添加节点(用户)
for i in range(1, 11):
    G.add_node(i)
# 添加边(连接关系)
G.add_edge(1, 2)
G.add_edge(1, 3)
G.add_edge(1, 4)
G.add_edge(2, 3)
G.add_edge(2, 4)
G.add_edge(3, 4)
G.add_edge(5, 6)
G.add_edge(5, 7)
G.add_edge(6, 7)
G.add_edge(8, 9)
G.add_edge(8, 10)
G.add_edge(9, 10)

# communities = community.best_partition(G)
communities = community_louvain.best_partition(G)
# {1: 2, 2: 2, 3: 2, 4: 2, 5: 1, 6: 1, 7: 1, 8: 0, 9: 0, 10: 0}  # 节点编号:社区编号
com_cnt = float(len(set(communities.values())))
# 绘制社区结构图
pos = nx.spring_layout(G)
for com_id in set(communities.values()):
    list_nodes = [nodes for nodes in communities.keys() if communities[nodes] == com_id]
    nx.draw_networkx_nodes(G, pos, list_nodes, node_size=20, node_color=f'C{com_id}')
nx.draw_networkx_edges(G, pos, alpha=0.5)
plt.show()

如下:

<think>嗯,用户遇到了npm install时报错找不到模块'node:path'的问题,需要我来帮忙解决。首先,我应该先回顾一下类似的问题,比如之前看到的引用内容。根据引用[1]和[2],这个问题通常与Node.js版本过低有关。例如,用户可能正在使用较旧的Node版本,而模块需要更高版本的支持。比如,'node:path'在Node.js v16或更高版本中才被支持,所以如果用户的Node版本是v10或者v12,就会出现这个问题。 接下来,我需要检查用户当前的Node.js和npm版本。用户可以通过运行node -v和npm -v来查看。假设用户使用的是Node v10.19.0,这显然太低了。根据引用[1]中的解决方案,可能需要升级Node.js到v14或更高版本,或者根据项目需求调整到v16,如引用[2]提到的v16.16.0。 另外,引用[1]中还提到npm版本过高的问题,如果用户手动链接了不同版本的npm,可能会导致路径错误。这时候需要检查npm的路径是否正确,可能需要重新链接到正确的版本。例如,删除/usr/local/bin/npm的链接,然后指向正确的npm路径,比如/usr/bin/npm。 同时,引用[2]和[3]建议在升级Node.js后,删除node_modules和package-lock.json(或pnpm-lock.yaml,如果是pnpm用户),然后重新安装依赖。这样可以避免旧缓存文件导致的问题。 用户可能需要使用nvm来管理多个Node.js版本,这样可以轻松切换版本而不会影响系统全局的设置。安装nvm后,安装所需的Node版本,然后重新运行npm install。 另外,如果用户的环境变量有问题,比如PATH设置错误,也可能导致找不到模块。需要检查PATH是否包含正确的Node.js和npm路径。此外,权限问题也可能引发安装错误,尤其是在Linux系统下,可能需要使用sudo或者调整目录权限。 总结一下,解决步骤应该是:确认Node.js和npm版本是否兼容,升级Node.js到合适版本,清理项目依赖缓存,重新安装依赖,检查路径和权限问题。如果用户按照这些步骤操作,应该能够解决问题。最后,生成相关问题帮助用户进一步了解可能遇到的类似问题,比如其他模块找不到的情况或者如何管理Node版本。</think>### 解决方案:`npm install`报错`Error: Cannot find module 'node:path'` #### 问题原因分析 1. **Node.js版本过低** - `node:path`是Node.js v16及以上版本引入的核心模块语法[^2]。若当前Node.js版本低于v16(如v10、v12),系统无法识别`node:`协议,导致模块路径解析失败。 - 示例:若`node -v`显示`v10.19.0`,则需升级Node.js。 2. **npm版本与Node.js不兼容** - 高版本npm可能与低版本Node.js存在兼容性问题。例如,使用npm v11.1.0时,若Node.js版本过低(如v10),运行命令会因依赖冲突报错[^1]。 3. **项目依赖环境不匹配** - 项目可能明确要求特定Node.js版本(如`v16.16.0`),而当前环境未满足[^2]。 --- #### 逐步解决方法 ##### 1. **升级Node.js版本** - **使用Node版本管理工具(推荐)** 通过`nvm`(Node Version Manager)管理多版本,避免全局覆盖: ```bash # 安装nvm curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash # 安装指定Node版本(如v16.16.0) nvm install 16.16.0 # 切换版本 nvm use 16.16.0 ``` - **直接下载安装包** 从[Node.js官网](https://nodejs.org/)下载LTS版本(如v18.x)。 ##### 2. **修复npm链接(若手动安装导致路径错误)** 若之前通过手动链接指定npm版本(如`/usr/local/bin/npm`指向错误路径): ```bash # 删除错误链接 sudo rm /usr/local/bin/npm # 重新链接到系统npm(假设正确路径为/usr/bin/npm) sudo ln -s /usr/bin/npm /usr/local/bin/npm ``` ##### 3. **清理项目依赖并重装** 升级Node.js后,需清理旧依赖: ```bash # 删除node_modules和锁定文件 rm -rf node_modules package-lock.json pnpm-lock.yaml # 重新安装依赖 npm install # 或使用pnpm install ``` ##### 4. **验证环境** - 检查版本是否匹配: ```bash node -v # 应≥v16.16.0 npm -v # 推荐≥v8.x ``` --- #### 其他注意事项 - **权限问题**:在Linux/macOS中,若使用`sudo`安装全局包,可能导致权限冲突。建议使用`nvm`或调整目录权限。 - **环境变量**:确保`PATH`包含Node.js的安装路径(如`~/.nvm/versions/node/v16.16.0/bin`)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值