import networkx as nx def build_graph(candidate_pairs): g = nx.Graph() for a, b in candidate_pairs: g.add_edge(a, b) return g def pair_graph_features(g, a, b): degree_map = dict(g.degree()) degree_sum = float(degree_map.get(a, 0) + degree_map.get(b, 0)) common = len(list(nx.common_neighbors(g, a, b))) if a in g and b in g else 0 na = set(g.neighbors(a)) if a in g else set() nb = set(g.neighbors(b)) if b in g else set() union = len(na | nb) inter = len(na & nb) jaccard = float(inter / union) if union else 0.0 nodes = set([a, b]) | na | nb sub = g.subgraph(nodes) possible = max(1, len(nodes) * (len(nodes) - 1) / 2) density = float(sub.number_of_edges() / possible) return { "graph_degree_sum": degree_sum, "graph_common_neighbors": float(common), "graph_jaccard": jaccard, "graph_local_density": density, }