极大连通子图算法(极大连通子图和极小连通子图的定义及讲解)

deer332025-07-10技术文章23

一、数据读取或生成数据

我们这里直接用Faker生成需要的数据,和大家业务中遇到的数据类型类,用faker库,构建一个数据集,如果没有,需要提前安装 pip install Faker。

"""
Description: 极大连通子图算法
Author: 《小伍哥聊风控》
Created: 2025-05-24
Version: 1.0
License: MIT
"""
# 加载所需要的包
import pandas as pd
from   faker import Faker
fake = Faker(locale='zh_CN')


# 我们构建三个关系,4个节点的异构图
uid   = ['uid_'+str(fake.random_int(10000, 10012)) for i in range(0,12)]
ip    = ['ip_'+fake.ipv4() for i in range(0,4)]*3
uid1  = ['uid_'+str(fake.random_int(10000, 10100)) for i in range(0,100)]
email = ['em_'+fake.email() for i in range(0,50)]*2
phone = ['ph_'+fake.phone_number() for i in range(0,100)]*1


# 构建用户和IP的关系
df1 = pd.DataFrame({'sr':uid,'ds':ip})
# 构建用户和邮箱关系
df2 = pd.DataFrame({'sr':uid1,'ds':email })
# 构建邮箱和手机绑定关系
df3 = pd.DataFrame({'sr':email,'ds':phone})
df2

二、数据集初探

对于比较小的数据集,可以整体进行可视化,初步探索下大概的连通情况。对于数据量超过500左右的,对数据集整体的可视化就没有意义了。一方面是点太多看不清楚,另一方面是渲染需要的内存比较大,单机很难跑出来。需要进行社群划分后,对每个社群单独进行可视化。两种不同的布局两种不同的效果。kamada_kawai_layout和spring_layout都给大家画一个模板

# 加载需要的库
import networkx as nx
import matplotlib.pyplot as plt


# 数据结构转换,分别对df1,df2,df3进行可视化
da = df2.values
G  = nx.Graph()
for num in range(len(da)):
    G.add_edge(str(da[num,0]),str(da[num,1]))


# 颜色设置,4种颜色随机
colors = ['r','b','y','c']*80
colors = colors[0:len(G.nodes())]


#布局为-kamada_kawai_layout
plt.figure(figsize=(3,3),dpi=600)
nx.draw_networkx(G,
                 pos = nx.kamada_kawai_layout(G),
                 node_color = colors,
                 node_size=15,
                 font_size=2,
                 alpha=1,
                 width=0.1
                 )
#plt.title("kamada_kawai_layout")
plt.axis('off')
plt.show()
#布局为- spring_layout
plt.figure(figsize=(4,4),dpi=500)
nx.draw_networkx(G,
                 pos = nx.spring_layout(G),
                 node_color = colors,
                 node_size=15,
                 font_size=2,
                 alpha=1.0,
                 width=0.1
                 )
plt.axis('off')
#plt.title("spring_layout")
plt.show()

三、数据构图

我们这里是数据构图,需要对原始的数据,处理成我们能被图算法使用的数据,三个关系表、四个类型的节点

  • 数据合并
  • :对于有多个关系类型的数据,需要对多个数据进行合并,因为图数据,只需要两列,因此我们堆叠就行。
  • 数据聚合
  • :为了避免重复,最好做个聚合,也就是对关系对进行去重
#三种关系堆叠合并
df = pd.concat([df1,df2,df3])


# 对数据进行聚合
df = df.groupby(['sr','ds']).agg({'ds': ['count']}).reset_index()
df.columns = ['sr','ds','count']
df.head()

四、算法实现代码

算法实现其实非常简单,就一小段代码

# 极大连通子图算法比较多,我们nx.connected_components即可实现
com = list(nx.connected_components(G))


# 打印看看什么格式的,可以看到得到的结果为列表-字典格式
print(com)

五、团伙结果整理

对于挖掘好的数据,整理成常规的数据表格形式,方便后续使用

# 将 列表-集合 整理成数据 表格形式
df_com  = pd.DataFrame()
for i in range(0, len(com)):
    d = pd.DataFrame({'group_id': [i] * len(com[i]), 'object_id': list(com[i])})
    df_com = pd.concat([df_com,d])


# 查看数据结果
df_com

六、拆分不同的节点类型

我们这里是一个有多个类型的节点的数据,业务里面为了治理方便,经常需要把各个类型的节点拆分出来。

#拆分出来团伙中对象的类型
df_com['type']      = df_com['object_id'].apply(lambda x:x.split('_')[0])
df_com['object_id'] = df_com['object_id'].apply(lambda x:x.split('_')[1])


#整理下格式
df_com = df_com[['group_id','type','object_id']]


#查看团伙的细节
df_com


七、团伙对象个数统计

这一步是为了看团伙的大小,然后针对不同的大小去分析,如果过大,就需要调整我们的参数。

# 统计每个团伙人数 并降序
df_cnt = df_com.groupby('group_id').count().sort_values(by='object_id', ascending=False).reset_index()
df_cnt = df_cnt[['group_id','object_id']]
df_cnt.columns = ['group_id','object_cnt']
df_cnt

八、单个团伙提取

提取单个团伙,可以根据我们的团伙ID

# 找一个团伙看看里面的细节
df_com[df_com['group_id']==0]

九、单个团伙可视化

业务中,我们的数据量都是非常巨大的,没办法对整个数据集进行可视化,那只能对单个团伙进行可视化,需要把每个团伙对应的表和节点提取出来。

#提取某一个群组进行可视化,根据每个社群的节点,去找边。
i = 2
edges = []
for k,v in zip(df['sr'].tolist(),df['ds'].tolist()):
    if k in com[i] or v in com[i]:
        edges.append((k,v))


#转换成图结构,可以从元组列表直接构建图
G_i = nx.Graph(edges)


#节点大小设置,与度关联
node_size = [G_i.degree(i)**1.2*50 for i in G_i.nodes()]


#不同节点不同颜色
#['#43CD80','DeepPink','orange','#008B8B','purple','#63B8FF','#BC8F8F','#3CB371','b','orange','y','c','#838B8B','purple','olive','#A0CBE2','#4EEE94']*10
colors_dic = {'uid':'#FF4500','ip':'#008000','em':'#43CD80','ph':'#63B8FF'}
node_color = [ colors_dic[i.split('_')[0]] for i in G_i.nodes()]


#设置显示图片大小
plt.figure(figsize=(4,3),dpi=600)


## 图像显示中文的问题
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False


#可以替换两种不同的布局看看效果 kamada_kawai_layout spring_layout
nx.draw_networkx(G_i,
                 pos = nx.kamada_kawai_layout(G_i),
                 node_color = node_color,
                 edge_color = '#BC8F8F',
                 #with_labels=False,
                     #node_color="white",
                 edgecolors= "black",
                 font_size = 4,
                 node_size = node_size,
                 alpha = 0.99,
                 width = 0.2
                 )
plt.axis('off')
plt.show()