关于karateclub中graph2vec/GL2vec的节点特征格式、报错解决及替代工具的技术咨询
karateclub中graph2vec/GL2vec的节点特征格式、报错解决及替代工具技术咨询
嘿,我来帮你拆解并解决这些问题:
一、karateclub里graph2vec/GL2vec的节点特征要求
这两个模型的核心是靠Weisfeiler-Lehman(WL)子树哈希生成图的特征表示,所以节点特征/标签得满足两个关键要求:
- 必须是数值类型(整数或浮点数),绝对不能用字符串!你代码里的
label="A"这种字符串标签会直接导致WL扩展无法生成有效的子结构签名,得把它转成数值(比如A→0、B→1),或者直接用自定义的数值特征当标签。 - 模型默认会用节点的度作为初始标签,如果你想用上自己定义的节点特征,要么把特征值赋值给节点的
label属性,要么提前把特征编码成数值型标签(目前karateclub的这两个模型只支持基于label或度的初始特征输入)
举个修改后的节点添加示例:
# 把字符串标签转成数值,同时保留自定义特征 G.add_node(0, label=0, feature=[0.5]) G.add_node(1, label=1, feature=[1.2]) G.add_node(2, label=2, feature=[0.8]) # 或者直接用自定义特征当label G.add_node(0, label=0.5) G.add_node(1, label=1.2) G.add_node(2, label=0.8)
二、解决"RuntimeError: you must first build vocabulary before training the model"报错
这个报错跟节点特征关系不大,核心问题是你只传了单个图给model.fit()!graph2vec是为批量图嵌入设计的,它需要从多个不同的图里收集子结构特征来构建词汇表,单个图的样本量根本不够生成有效的词汇表,自然会报错。
解决起来很简单:多传几个图就行,比如复制现有图、或者创建几个小的不同图:
# 示例:创建两个不同的图传入 G1 = G # 你的原始图 G2 = nx.DiGraph() G2.add_node(0, label=0.3) G2.add_node(1, label=0.7) G2.add_edge(0, 1) graphs = [G1, G2] model = kc.graph_embedding.Graph2Vec() model.fit(graphs) embeddings = model.get_embedding() print(embeddings)
要是你只需要单个图的嵌入,graph2vec其实不是最优选择,不如用节点嵌入模型(比如Node2Vec)再把节点嵌入聚合起来得到图嵌入。
三、适合有向带属性图的替代工具(无需划分训练/测试集)
如果你要处理带节点/边属性的有向NetworkX图,又不想划分训练测试集,推荐这几个简单易用的工具:
1. PyTorch Geometric(PyG)
PyG虽然稍重,但灵活性拉满,支持有向图和属性图,不需要手动划分数据集就能生成图嵌入:
import torch from torch_geometric.data import Data from torch_geometric.nn import GCNConv, global_add_pool from torch_geometric.utils import from_networkx # 把NetworkX图转成PyG格式 data = from_networkx(G) # 定义简单的图嵌入模型 class GraphEmbed(torch.nn.Module): def __init__(self, in_channels, hidden_channels): super().__init__() self.conv = GCNConv(in_channels, hidden_channels) def forward(self, x, edge_index, batch=None): x = self.conv(x, edge_index) x = global_add_pool(x, batch) # 把节点嵌入聚合成图嵌入 return x model = GraphEmbed(in_channels=1, hidden_channels=16) embedding = model(data.x, data.edge_index) print(embedding.detach().numpy())
2. Stellargraph + GraphSAGE
Stellargraph的API很友好,专门支持有向图和属性图,不用划分训练集就能生成嵌入:
import stellargraph as sg from stellargraph.mapper import GraphSAGENodeGenerator from stellargraph.layer import GraphSAGE, MeanAggregator from tensorflow.keras import layers, Model import tensorflow as tf # 转成Stellargraph格式 sg_graph = sg.StellarDiGraph(G, node_features="feature") # 初始化GraphSAGE生成器 generator = GraphSAGENodeGenerator(sg_graph, batch_size=32, num_samples=[10,5]) # 定义GraphSAGE模型 graphsage = GraphSAGE(layer_sizes=[16,16], generator=generator, aggregator=MeanAggregator()) x_inp, x_out = graphsage.in_out_tensors() # 添加聚合层得到图嵌入 graph_embedding = layers.Lambda(lambda x: tf.reduce_mean(x, axis=0))(x_out) model = Model(inputs=x_inp, outputs=graph_embedding) # 生成嵌入 embedding = model.predict(generator.flow(sg_graph.nodes())) print(embedding)
3. Node2Vec(手动聚合图嵌入)
如果你想要最简单的方案,Node2Vec可以生成节点嵌入,之后用均值、求和等方式手动聚合成图嵌入,还支持有向图:
from node2vec import Node2Vec import numpy as np # 训练Node2Vec节点嵌入 node2vec = Node2Vec(G, dimensions=16, directed=True) model = node2vec.fit(window=10) # 聚合节点嵌入为图嵌入(这里用均值) graph_embedding = np.mean([model.wv[str(node)] for node in G.nodes()], axis=0) print(graph_embedding)
备注:内容来源于stack exchange,提问作者Arindam Ghosh
相关产品推荐
相关产品推荐

