
用户关系已经拉成边表了结果下一步卡住了。SQL具备查出 、、score的功能, sql能够实现进行绘图。一旦面临执行“相似用户召回、异常团伙识别以及以及为社区划分并执行判定”的任务, 就会察觉到仅仅依靠图是无法达成目标的。必须要将图转化成向量, 或者直接转化为社群标签。这时候可以看一眼 。它并非是那个具有典型性的空手道俱乐部数据集, 反而是一个图挖掘库。官方所给出的定位相当直接明白: 属于一种凭借相关基础而创建的无监督机器学习扩展范畴图书馆, 主要从事像是去实施图嵌入操作, 开展社区发现工作, 进行图挖掘这类具体事务。其应用程序编程接口也较为统一规整, 基本上就是把信息之类的内容 fit 进去, 然后从中以某种模式或方式取出来。我对这种库一般不先看论文先看能不能接住业务里的边表。比如说吧, 用户相互之间存在着共同下单的情况, 还有着共同设备, 并且有着共同地址, 此前前面的规则已经实施过一轮过滤了, 如今打算把那些关系较为亲近的用户给找出来。边表大致就是存在着类似这样的情况:raw_edges [ (u_1001, u_1002, 3), (u_1001, u_1088, 1), (u_1002, u_1090, 2), (u_2001, u_2003, 4), (u_2003, u_2011, 2), ]这里面, 我要是第一眼瞅见它, 不会直接就给送去。它针对 图, 存在着这样一个要求: 节点最好得是从 0 开始的接连不断的整数。在这个地方呢, 可是特别容易挖坑, 业务当中的用户 ID 基本上通通都是字符串 , 要是直接把这些塞进去, 那后续的行号就很难去对应了。官方文档也清清楚楚地提到, 节点索引倘若要从 0 开始, 并且还得连续。我一般先写一个很薄的转换层import networkx as nx defbuild_graph(edge_rows): user_ids set for left, right, _ in edge_rows: if left ! right: user_ids.add(left) user_ids.add(right) user_to_idx {u: i for i, u in enumerate(sorted(user_ids))} idx_to_user {i: u for u, i in user_to_idx.items} graph nx.Graph graph.add_nodes_from(idx_to_user.keys) for left, right, score in edge_rows: if left right: continue graph.add_edge(user_to_idx[left], user_to_idx[right], weightscore) return graph, user_to_idx, idx_to_user留意了, 在所保留的这儿, 可别期望着任一算法都会切实把这个权重当作回事。图挖掘库最为惧怕的便是“自认为它运用了”这种情况。于真正上线之前, 或者去查看源码, 或者选取几条边来开展对照实验, 切勿凭借感觉。去先跑一回。它适配用于当作节点向量 , 后续连接相似度、聚类以及分类器均是没错的。from karateclub import DeepWalk from sklearn.metrics.pairwise import cosine_similarity graph, user_to_idx, idx_to_user build_graph(raw_edges) model DeepWalk( dimensions32, walk_number20, walk_length40, workers1, seed2026 ) model.fit(graph) vectors model.get_embedding defsimilar_users(user_id, topn5): idx user_to_idx[user_id] scores cosine_similarity(vectors[idx:idx 1], vectors)[0] candidates for other_idx, score in enumerate(scores): if other_idx idx: continue candidates.append((idx_to_user[other_idx], float(score))) return sorted(candidates, keylambda x: x[1], reverseTrue)[:topn] print(similar_users(u_1001, topn3))这段代码, 真正具备有用之处的地方, 并非是其有多高级, 而是它将“图上的邻近关系”这种情况, 转变成为了能够进行排序的向量分数。以前写推荐召回很多人会先做一堆规则共同设备 10 共同地址 8 共同收货人 5 共同 IP 2这般规则并非不可运用, 然而问题在于, 越书写便越显得如同祖传下来的 if - else 一般。增添一项新关系, 就得去调试一连串权重。图嵌入所具备的益处在于, 它能够将多跳关系共同融合进来。A 与 B 并未直接存在连边, 不过它们周边的邻居极为相似, 向量之间的距离或许也会很近的。当然别把它当神仙。我一般会先看三件事首先, 关于孤立节点的数量情况如何。其次, 孤立节点因为不存在上下文关联, 所以据此计算得出的向量其价值是非常低的。第二, 最大连通分量所占的比例。要是图被分割成许多小块碎片, 那么其呈现出的效果通常而言不会显得很不错。第三, 存在这样一个问题, 节点编号是否存在正确与错误之分呢。这个问题显得较为低级然而却真的极易出现, 特别是在将结果写回到数据库之时。排查代码可以这么写definspect_graph(graph): components sorted(nx.connected_components(graph), keylen, reverseTrue) largest len(components[0]) if components else0 print({ nodes: graph.number_of_nodes, edges: graph.number_of_edges, components: len(components), largest_component: largest, isolated_nodes: len(list(nx.isolates(graph))) }) inspect_graph(graph)倘若你并非意在寻觅相似节点, 而是打算径直将用户划分成若干圈子, 那便能够更换社区发现算法。from karateclub import LabelPropagation cluster LabelPropagation(seed2026) cluster.fit(graph) memberships cluster.get_memberships user_groups {} for idx, group_id in memberships.items: user_groups.setdefault(group_id, []).append(idx_to_user[idx]) for group_id, users in user_groups.items: print(group_id, users)这个结果更适合给运营、风控、审核系统看。例如, 有一组用户, 他们都共同使用过设备, 还共用过地址, 并且处于相同的支付环境。规则系统之中, 仅仅命中了其中的两个。社区发现之后, 有可能会把整团都拖出来。在此处, 我将会非常谨慎, 不会直接将其用作封禁的依据, 至多先进行线索召回。图算法计算出来的结果是“关系可疑”, 并非“事实成立”。安装也简单pip install karateclub然而, 这个库并非是那种每日都会进行更新的新型玩意儿。在PyPI之上, 当下所展示的最新版本为1.3,有着3, 发布的时间是2022年10月22日。因此, 环境不要过于激进, 当NumPy版本过新时, 碰到安装或兼容问题, 不要先去怀疑业务代码。要先单独创建一个虚拟环境, 将依赖锁定【句号为提问保留】。python -m venv .venv_graph source .venv_graph/bin/activate pip install karateclub scikit-learn pandas我更愿意把 放在离线任务里用。比如说, 每天凌晨的时候, 从订单库当中抽取边表, 从设备库当中抽取边表, 从登录日志里抽取边表, 接着进行构图, 随后进行跑, 之后把相似用户TopN写回到一张结果表, 或者把社区编号写回到一张结果表。线上接口仅仅查询结果, 并不在请求链路里现场跑图算法。这才是比较稳的用法。它具备强大之处, 在于凭借极少的代码将图挖掘算法接入工程它存在别扭之处, 同样显著, 那便是输入图格式必须规整, 节点编号需要妥善处理, 大图性能得靠自身进行压测, 而且结果不能够未经解释就径直进入风控决策。可要是你手上已然存有大量关系数据, 却依旧借助SQL一次次地进行join操作去探寻“谁与谁相似”, 那么这是值得去尝试一番的。先别上来就搞复杂模型。首先进行边表的洗净操作, 接着要确保节点映射的正确性, 随后运行实施一个 , 查看相似结果是否符合正常表述 , 若能顺利通过这一关卡 , 才可以再来谈论后续的优化事宜。