| 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, | |
| } |