{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Group Centrality Tutorial" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This notebook covers the group centrality algorithms implemented in NetworKit. Group centrality measures the relative importance of a group of nodes within a graph. \n", "\n", "The documentation of NetworKit group centrality algorithms is available in the [centrality](https://networkit.github.io/dev-docs/python_api/centrality.html) module." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "import networkit as nk" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "# Read graph\n", "G = nk.readGraph(\"../input/karate.graph\", nk.Format.METIS)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Group Betweenness" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Group betweenness measures the importance of a group $S$ as the fraction of shortest paths connecting pairs of non-group members that pass through $S$.\n", "\n", "The constructor [ApproxGroupBetweenness(G, groupSize, epsilon)](https://networkit.github.io/dev-docs/python_api/centrality.html?highlight=approxgr#networkit.centrality.ApproxGroupBetweenness) expects as inputs an undirected graph, the desired group size `groupSize`, and the accuracy of the approximation `epsilon`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "# Initalize algorithm\n", "btwn = nk.centrality.ApproxGroupBetweenness(G, 10, 0.1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "# Run \n", "btwn.run()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "After running the algorithm, we can extract some information about the group betweenness centrality, e.g. the group with the highest approximate betweenness centrality score. " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "# Group with highest approximate betweenness centrality\n", "btwn.groupMaxBetweenness()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One may also have a group of nodes and be interested in the group's betweeness centrality score. The function [scoreOfGroup(group, normalized=False)]() returns the betweenness centrality score of the list of nodes in `group`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "# Create an arbitrary group of nodes\n", "group = [7, 8, 11, 20]\n", "\n", "# Get betweenness centrality score of group\n", "btwn.scoreOfGroup(group)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Group Closeness" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "GroupCloseness measures the importance of a group $S$ as the inverse of the sum of the distances from all the nodes outside $S$ to their nearest node in $S$.\n", "\n", "In NetworKit, GroupCloseness implements an heuristic greedy algorithm to compute a group of nodes with high group closeness centrality. The algorithm was introduced in \"[Scaling up Group Closeness Maximization](https://arxiv.org/abs/1710.01144)\" Bergamini et al., ALENEX 2018.\n", "\n", "The constructor [GroupCloseness(G, k=1, H=0)](https://networkit.github.io/dev-docs/python_api/centrality.html?highlight=group#networkit.centrality.GroupCloseness) expects an unweighted graph and the desired group size `k`. If `H > 0`, all BFSs will explore the graph up to distance `H`. This can speed up the algorithm, at the cost of a lower solution quality." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Initalize algorithm\n", "close = nk.centrality.GroupCloseness(G, 10)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Run\n", "close.run()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[groupMaxCloseness()](https://networkit.github.io/dev-docs/python_api/centrality.html?highlight=groupma#networkit.centrality.GroupCloseness.groupMaxCloseness) returns the group of `k` nodes computed by the algorithm." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Computed group of nodes\n", "close.groupMaxCloseness()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[scoreOfGroup(group)](https://networkit.github.io/dev-docs/python_api/centrality.html?highlight=scoreof#networkit.centrality.GroupCloseness.scoreOfGroup) takes a group of nodes as input, and returns the group's closeness centrality score. The score is returned as a value between 0 and 1: a score of 1 indicates maximum group closeness centrality." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create an arbitrary group of nodes\n", "group = [7, 8, 11, 20]\n", "\n", "# Get closeness centrality score of group\n", "close.scoreOfGroup(group)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Local Search for Group Closeness\n", "\n", "A faster local search algorithm for group closeness is the Grow-Shrink algorithm introduced in [Local Search for Group Closeness Maximization on Big Graphs](https://ieeexplore.ieee.org/document/9006206), Angriman et al., IEEE BigData 2019.\n", "\n", "The algorithm starts from an arbitrary group of vertices and performs local improvements until a local optimum is reached. You need to pass as input a graph and an initial set of nodes. Further, you can specify whether or not to use the extended version of the algorithm (use the `extended` parameter) and how many insertions/removals to perform at each iteration (`insertion` parameter). See the paper for further details about those parameters." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def closenessOfGroup(group):\n", " distances = []\n", " nk.traversal.Traversal.BFSfrom(G, group, lambda u, dist: distances.append(dist))\n", " return 1. / sum(distances)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create a random group of vertices\n", "k, group = 5, set()\n", "while (len(group) < k):\n", " group.add(nk.graphtools.randomNode(G))\n", "\n", "print(\"Initial group\", list(group), \"has score {:.3f}\".format(closenessOfGroup(group)))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "gs = nk.centrality.GroupClosenessGrowShrink(G, group).run()\n", "group = gs.groupMaxCloseness()\n", "print(\"Final group\", group, \"has score {:.3f}\".format(closenessOfGroup(group)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The LS-Restrict algorithm for group closeness only allows swaps between vertices in the group and their neighbors outside. Because it considers less candidates for a swap it is faster than Grow-Shrink, but might yield results with lower quality." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create a random group of vertices\n", "k, group = 5, set()\n", "while (len(group) < k):\n", " group.add(nk.graphtools.randomNode(G))\n", "\n", "print(\"Initial group\", list(group), \"has score {:.3f}\".format(closenessOfGroup(group)))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "gs = nk.centrality.GroupClosenessLocalSwaps(G, group).run()\n", "group = gs.groupMaxCloseness()\n", "print(\"Final group\", group, \"has score {:.3f}\".format(closenessOfGroup(group)))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create a random group of vertices\n", "k, group = 5, set()\n", "while (len(group) < k):\n", " group.add(nk.graphtools.randomNode(G))\n", "\n", "print(\"Initial group\", list(group), \"has score {:.3f}\".format(close.scoreOfGroup(group)))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "gs = nk.centrality.GroupClosenessLocalSearch(G, group).run()\n", "group = gs.groupMaxCloseness()\n", "print(\"Final group\", group, \"has score {:.3f}\".format(close.scoreOfGroup(group)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`GroupClosenessLocalSearch` evaluates all possible single-swaps between vertices in the group and the vertices outside. Its time complexity is $O(k \\cdot (n - k))$, compared to the aforementioned algorithms for group closeness it is slower, but it yields groups with higher group closeness score." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Group Harmonic Closeness\n", "\n", "Group Harmonic Closeness interprets the importance of a group $S$ as the harmonic sum of the distances from the nodes outside $S$ to their nearest node in $S$.\n", "\n", "In NetworKit, GroupHarmonicCloseness implements an heuristic approximation algorithm for group harmonic closeness centrality. The algorithm was introduced in \"[Group-Harmonic and Group-Closeness Maximization – Approximation and Engineering](https://epubs.siam.org/doi/10.1137/1.9781611976472.12)\" Angriman et al., ALENEX 2021." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create a random group of vertices\n", "k, group = 5, set()\n", "while (len(group) < k):\n", " group.add(nk.graphtools.randomNode(G))\n", "\n", "print(\"Initial group\", list(group), \"has score {:.3f}\".format(close.scoreOfGroup(group)))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "hClose = nk.centrality.GroupHarmonicCloseness(G, 10).run()\n", "hClose.groupMaxHarmonicCloseness()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Group Degree" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Group Degree measures the importance of a group of nodes $S$ as the number of non group members that can be reached from $S$ in one hop. The algorithm implemented in NetworKit is a greedy algorithm that find an approximation of the group with the highest group degree centrality.\n", "\n", "The constructor [GroupDegree(G, k = 1, countGroupNodes = True)](https://networkit.github.io/dev-docs/python_api/centrality.html?highlight=groupdegree#networkit.centrality.GroupDegree) expects a graph, the desired group size `k`, and a boolean `countGroupNodes` stating if nodes inside the group should be counted in the centrality score. By default, the nodes are included in the centrality score.\n", "Note that, in order to have a fixed $(1 - 1/e)$ approximation guarantee, `countGroupNodes` must be set to `False`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "# Initalize algorithm\n", "degree = nk.centrality.GroupDegree(G, 10)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Run\n", "degree.run()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[groupMaxDegree()](https://networkit.github.io/dev-docs/python_api/centrality.html?highlight=groupma#networkit.centrality.GroupDegree.groupMaxDegree) returns the group of `k` nodes computed by the algorithm." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Group with high degree centrality\n", "degree.groupMaxDegree()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[scoreOfGroup(group)](https://networkit.github.io/dev-docs/python_api/centrality.html?highlight=scoreof#networkit.centrality.GroupDegree.scoreOfGroup) takes a group of nodes as input parameter, and returns the group's degree centrality score." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create an arbitrary group of nodes\n", "group = [7, 8, 11, 20]\n", "\n", "# Get degree centrality score of group\n", "degree.scoreOfGroup(group)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.0" } }, "nbformat": 4, "nbformat_minor": 2 }