{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# [NTDS'18] tutorial 2: build a graph from features\n", "[ntds'18]: https://github.com/mdeff/ntds_2018\n", "\n", "[Benjamin Ricaud](https://people.epfl.ch/benjamin.ricaud), [EPFL LTS2](https://lts2.epfl.ch), with contributions from [Michaël Defferrard](http://deff.ch) and [Effrosyni Simou](https://lts4.epfl.ch/simou).\n", "\n", "* Dataset: [Iris](https://archive.ics.uci.edu/ml/datasets/Iris)\n", "* Tools: [pandas](https://pandas.pydata.org), [numpy](http://www.numpy.org), [scipy](https://www.scipy.org), [matplotlib](https://matplotlib.org), [networkx](https://networkx.github.io), [gephi](https://gephi.org/)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Tools" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The below line is a [magic command](https://ipython.readthedocs.io/en/stable/interactive/magics.html) that allows plots to appear in the notebook." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The first thing is always to import the packages we'll use." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "import numpy as np\n", "from scipy.spatial.distance import pdist, squareform\n", "from matplotlib import pyplot as plt\n", "import networkx as nx" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Tutorials on pandas can be found at:\n", "* \n", "* \n", "\n", "Tutorials on numpy can be found at:\n", "* \n", "* \n", "* \n", "\n", "A tutorial on networkx can be found at:\n", "* " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Import and explore the data\n", "\n", "We will play with the famous Iris dataset. This dataset can be found in many places on the net and was first released at . For example it is stored on [Kaggle](https://www.kaggle.com/uciml/iris/), with many demos and Jupyter notebooks you can test (have a look at the \"kernels\" tab).\n", "\n", "![Iris Par Za — Travail personnel, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=144395](figures/iris_germanica.jpg)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
IdSepalLengthCmSepalWidthCmPetalLengthCmPetalWidthCmSpecies
015.13.51.40.2Iris-setosa
124.93.01.40.2Iris-setosa
234.73.21.30.2Iris-setosa
344.63.11.50.2Iris-setosa
455.03.61.40.2Iris-setosa
\n", "
" ], "text/plain": [ " Id SepalLengthCm SepalWidthCm PetalLengthCm PetalWidthCm Species\n", "0 1 5.1 3.5 1.4 0.2 Iris-setosa\n", "1 2 4.9 3.0 1.4 0.2 Iris-setosa\n", "2 3 4.7 3.2 1.3 0.2 Iris-setosa\n", "3 4 4.6 3.1 1.5 0.2 Iris-setosa\n", "4 5 5.0 3.6 1.4 0.2 Iris-setosa" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "iris = pd.read_csv('data/iris.csv')\n", "iris.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The description of the entries is given here:\n", "https://www.kaggle.com/uciml/iris/home" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array(['Iris-setosa', 'Iris-versicolor', 'Iris-virginica'], dtype=object)" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "iris['Species'].unique()" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
IdSepalLengthCmSepalWidthCmPetalLengthCmPetalWidthCm
count150.000000150.000000150.000000150.000000150.000000
mean75.5000005.8433333.0540003.7586671.198667
std43.4453680.8280660.4335941.7644200.763161
min1.0000004.3000002.0000001.0000000.100000
25%38.2500005.1000002.8000001.6000000.300000
50%75.5000005.8000003.0000004.3500001.300000
75%112.7500006.4000003.3000005.1000001.800000
max150.0000007.9000004.4000006.9000002.500000
\n", "
" ], "text/plain": [ " Id SepalLengthCm SepalWidthCm PetalLengthCm PetalWidthCm\n", "count 150.000000 150.000000 150.000000 150.000000 150.000000\n", "mean 75.500000 5.843333 3.054000 3.758667 1.198667\n", "std 43.445368 0.828066 0.433594 1.764420 0.763161\n", "min 1.000000 4.300000 2.000000 1.000000 0.100000\n", "25% 38.250000 5.100000 2.800000 1.600000 0.300000\n", "50% 75.500000 5.800000 3.000000 4.350000 1.300000\n", "75% 112.750000 6.400000 3.300000 5.100000 1.800000\n", "max 150.000000 7.900000 4.400000 6.900000 2.500000" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "iris.describe()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Build a graph from the features\n", "\n", "We are going to build a graph from this data. The idea is to represent iris samples (rows of the table) as nodes, with connections depending on their physical similarity.\n", "\n", "The main question is how to define the notion of similarity between the flowers. For that, we need to introduce a measure of similarity. It should use the properties of the flowers and provide a positive real value for each pair of samples. The value should be larger for more similar samples.\n", "\n", "Let us separate the data into two parts: physical properties and labels." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "features = iris.loc[:, ['SepalLengthCm', 'SepalWidthCm', 'PetalLengthCm', 'PetalWidthCm']]\n", "species = iris.loc[:, 'Species']" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
SepalLengthCmSepalWidthCmPetalLengthCmPetalWidthCm
05.13.51.40.2
14.93.01.40.2
24.73.21.30.2
34.63.11.50.2
45.03.61.40.2
\n", "
" ], "text/plain": [ " SepalLengthCm SepalWidthCm PetalLengthCm PetalWidthCm\n", "0 5.1 3.5 1.4 0.2\n", "1 4.9 3.0 1.4 0.2\n", "2 4.7 3.2 1.3 0.2\n", "3 4.6 3.1 1.5 0.2\n", "4 5.0 3.6 1.4 0.2" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "features.head()" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0 Iris-setosa\n", "1 Iris-setosa\n", "2 Iris-setosa\n", "3 Iris-setosa\n", "4 Iris-setosa\n", "Name: Species, dtype: object" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "species.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Similarity, distance and edge weight" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can define many similarity measures. One of the most intuitive and perhaps the easiest to program relies on the notion of distance. If a distance between samples is defined, we can compute the weight accordingly: if the distance is short, which means the nodes are similar, we want a strong edge (large weight)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Different distances\n", "The cosine distance is a good candidate for high-dimensional data. It is defined as follows:\n", "$$d(u,v) = 1 - \\frac{u \\cdot v} {\\|u\\|_2 \\|v\\|_2},$$\n", "where $u$ and $v$ are two feature vectors.\n", " \n", "The distance is proportional to the angle formed by the two vectors (0 if colinear, 1 if orthogonal, 2 if opposed direction).\n", "\n", "Alternatives are the [$p$-norms](https://en.wikipedia.org/wiki/Norm_%28mathematics%29#p-norm) (or $\\ell_p$-norms), defined as\n", "$$d(u,v) = \\|u - v\\|_p,$$\n", "of which the Euclidean distance is a special case with $p=2$." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `pdist` function from `scipy` computes the pairwise distance. By default it is the Euclidian distance. `features.values` is a numpy array extracted from the Pandas dataframe. Very handy." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "#from scipy.spatial.distance import pdist, squareform\n", "pdist?" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "distances = pdist(features.values, metric='euclidean')\n", "# other metrics: 'cosine', 'cityblock', 'minkowski'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now that we have a distance, we can compute the weights." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Distance to weights\n", "A common function used to turn distances into edge weights is the Gaussian function:\n", "$$\\mathbf{W}(u,v) = \\exp \\left( \\frac{-d^2(u, v)}{\\sigma^2} \\right),$$\n", "where $\\sigma$ is the parameter which controls the width of the Gaussian.\n", " \n", "The function giving the weights should be positive and monotonically decreasing with respect to the distance. It should take its maximum value when the distance is zero, and tend to zero when the distance increases. Note that distances are non-negative by definition. So any funtion $f : \\mathbb{R}^+ \\rightarrow [0,C]$ that verifies $f(0)=C$ and $\\lim_{x \\rightarrow +\\infty}f(x)=0$ and is *strictly* decreasing should be adapted. The choice of the function depends on the data.\n", "\n", "Some examples:\n", "* A simple linear function $\\mathbf{W}(u,v) = \\frac{d_{max} - d(u, v)}{d_{max} - d_{min}}$. As the cosine distance is bounded by $[0,2]$, a suitable linear function for it would be $\\mathbf{W}(u,v) = 1 - d(u,v)/2$.\n", "* A triangular kernel: a straight line between the points $(0,1)$ and $(t_0,0)$, and equal to 0 after this point.\n", "* The logistic kernel $\\left(e^{d(u,v)} + 2 + e^{-d(u,v)} \\right)^{-1}$.\n", "* An inverse function $(\\epsilon+d(u,v))^{-n}$, with $n \\in \\mathbb{N}^{+*}$ and $\\epsilon \\in \\mathbb{R}^+$.\n", "* You can find some more [here](https://en.wikipedia.org/wiki/Kernel_%28statistics%29).\n", " " ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "# Let us use the Gaussian function\n", "kernel_width = distances.mean()\n", "weights = np.exp(-distances**2 / kernel_width**2)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "# Turn the list of weights into a matrix.\n", "adjacency = squareform(weights)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sometimes, you may need to compute additional features before processing them with some machine learning or some other data processing step. With Pandas, it is as simple as that:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
SepalLengthCmSepalWidthCmPetalLengthCmPetalWidthCmSepalLengthSquared
05.13.51.40.226.01
14.93.01.40.224.01
24.73.21.30.222.09
34.63.11.50.221.16
45.03.61.40.225.00
\n", "
" ], "text/plain": [ " SepalLengthCm SepalWidthCm PetalLengthCm PetalWidthCm \\\n", "0 5.1 3.5 1.4 0.2 \n", "1 4.9 3.0 1.4 0.2 \n", "2 4.7 3.2 1.3 0.2 \n", "3 4.6 3.1 1.5 0.2 \n", "4 5.0 3.6 1.4 0.2 \n", "\n", " SepalLengthSquared \n", "0 26.01 \n", "1 24.01 \n", "2 22.09 \n", "3 21.16 \n", "4 25.00 " ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Compute a new column using the existing ones.\n", "features['SepalLengthSquared'] = features['SepalLengthCm']**2\n", "features.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Coming back to the weight matrix, we have obtained a full matrix but we may not need all the connections (reducing the number of connections saves some space and computations!). We can sparsify the graph by removing the values (edges) below some fixed threshold. Let us see what kind of threshold we could use:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYAAAAEICAYAAABWJCMKAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4wLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvqOYd8AAAFcpJREFUeJzt3X+0nVV95/H3RxAdBxRsAmIIBG2cGl0julLUZafShcOPaMWOVWFVDZSZaAuOrcwP/NGB0VqxHXXVGaqDQxagFaStlqi0FFFBR1GCVeTHOKYYIQZJEEQUaw3znT/Ojh7Cvbnn3nvuvbns92uts87z7Gc/z7P3uTfnc/d+nnOSqkKS1J9HLHQDJEkLwwCQpE4ZAJLUKQNAkjplAEhSpwwASeqUAaCxS/L+JH8wpmMdmuSHSfZq659N8m/Hcex2vL9JsnZcx5vGef8wyV1JvjuH5/hhkieNWLeS/OJctUV7JgNA05Jkc5IfJ7kvyfeTfCHJa5P87Hepql5bVW8b8Vgv2F2dqrqtqvatqgfG0Pazk3xol+MfX1UXzvbY02zHcuAMYFVVPWGuztNet1tne5wkJyf5/DjapD2LAaCZ+PWq2g84DDgH+M/A+eM+SZK9x33MPcRhwPeqattCN0R9MwA0Y1V1b1VtAF4BrE3ydIAkFyT5w7a8JMkn2mjh7iSfS/KIJB8EDgU+3qYq/lOSFW0q4tQktwGfHiobDoMnJ/lyknuTXJbk8e1cRyXZMtzGnaOMJMcBbwJe0c73tbb9Z1NKrV1vSfLtJNuSXJTkcW3bznasTXJbm75582SvTZLHtf23t+O9pR3/BcCVwBNbOy6YYN+rk7y0Lf9KO++atv6CJF8dqvvbSW5Jck+SK5IcNrTtZ9M6SX4hyceT/CDJdW0Kate/6l+Q5JvtWOdm4KnA+4HntvZ+vx1vTZKb20jwO0n+w2SvhfZcBoBmraq+DGwB/tUEm89o25YCBzF4E66qehVwG4PRxL5V9cdD+zwfeCpw7CSnfDXw28ATgR3Ae0do498CfwR8pJ3vGRNUO7k9fg14ErAv8D92qfMrwL8Ajgb+S3uDnMh/Bx7XjvP81uZTqupTwPHA1taOkyfY92rgqLb8q8Ct7Rg7168GSPISBq/nv2Hw+n4OuHiS9pwL/Ah4ArC2PXb1IuCXgWcALweOrapbgNcCX2zt3b/VPR94TRsJPh349CTn1R7MANC4bAUeP0H5T4GDgcOq6qdV9bma+guozq6qH1XVjyfZ/sGqurGqfgT8AfDynReJZ+m3gHdX1a1V9UPgjcCJu4w+/mtV/biqvgZ8jcGb5YO0trwCeGNV3VdVm4F3Aa8asR1X8+A3/HcMrT+/bQd4DfCOqrqlqnYwCLgjhkcBQ+15KXBWVd1fVTcDE133OKeqvl9VtwGfAY7YTRt/CqxK8tiquqeqvjJi37QHMQA0LsuAuyco/xNgE/B3SW5NcuYIx7p9Gtu/DTwSWDJSK3fvie14w8fem8HIZafhu3buZzBK2NUSYJ8JjrVsxHZ8EXhKkoMYvAlfBCxPsgQ4Erim1TsM+NM2vfZ9Bq9/JjjP0taP4ddtotd4lL7t9FJgDfDtNmX13JF6pj2KAaBZS/LLDN50HnKnSPsL+IyqehLw68Abkhy9c/Mkh5xqhLB8aPlQBn+N3sVgiuMxQ+3ai8Gb36jH3crgTXX42DuAO6fYb1d3tTbteqzvjLJzVd0PXA+8Hrixqv4J+ALwBuAfququVvV2BtMw+w89/llVfWGXQ25v/ThkqGw5o3vI61ZV11XVCcCBwF8Dl07jeNpDGACasSSPTfIi4BLgQ1X19QnqvCjJLyYJ8APggfaAwRvrSPep7+KVSVYleQzwVuAv222i/xd4dJIXJnkk8BbgUUP73QmsyNAtq7u4GPj9JIcn2ZefXzPYMZ3GtbZcCrw9yX5tSuYNwId2v+eDXA2czs+nez67yzoMLs6+McnT4GcXnl82SXs+Cpyd5DFJfonBNYlR3QkckmSfdp59kvxWksdV1U/5+c9Vi4wBoJn4eJL7GPwF+mbg3cApk9RdCXwK+CGDqY0/q6rPtm3vAN7SpjCmcxfJB4ELGExZPBr49zC4Kwn4XeB/Mfhr+0cMLkDv9Bft+XtJJpqzXt+OfQ3wLeAfgddNo13DXtfOfyuDkdGH2/FHdTWwHz+f7tl1nar6GPBO4JIkPwBuZHCBeSKnM7go/V0GfbwY+MmIbfk0cBPw3SQ7Rx+vAja3874WeOWIx9IeJP6HMFJ/krwTeEJVzfunoLXncAQgdSDJLyX5l+3e/iOBU4GPLXS7tLAerp+0lPRg+zGY9nkisI3BbamXLWiLtOCcApKkTjkFJEmd2qOngJYsWVIrVqxY6GZI0qJy/fXX31VVS6eqt0cHwIoVK9i4ceNCN0OSFpUk3566llNAktQtA0CSOmUASFKnDABJ6pQBIEmdMgAkqVMGgCR1ygCQpE4ZAJLUqT36k8CzteLMTy7IeTef88IFOa8kTYcjAEnqlAEgSZ0yACSpUwaAJHXKAJCkThkAktQpA0CSOmUASFKnDABJ6pQBIEmdMgAkqVMGgCR1ygCQpE4ZAJLUKQNAkjplAEhSpwwASeqUASBJnTIAJKlTBoAkdWrKAEiyPMlnktyS5KYkr2/lZyf5TpKvtseaoX3emGRTkm8kOXao/LhWtinJmXPTJUnSKPYeoc4O4Iyq+kqS/YDrk1zZtr2nqv7bcOUkq4ATgacBTwQ+leQpbfO5wL8GtgDXJdlQVTePoyOSpOmZMgCq6g7gjrZ8X5JbgGW72eUE4JKq+gnwrSSbgCPbtk1VdStAkktaXQNAkhbAtK4BJFkBPBP4Uis6PckNSdYnOaCVLQNuH9ptSyubrHzXc6xLsjHJxu3bt0+neZKkaRg5AJLsC/wV8HtV9QPgfcCTgSMYjBDetbPqBLvXbsofXFB1XlWtrqrVS5cuHbV5kqRpGuUaAEkeyeDN/8+r6qMAVXXn0PYPAJ9oq1uA5UO7HwJsbcuTlUuS5tkodwEFOB+4parePVR+8FC13wBubMsbgBOTPCrJ4cBK4MvAdcDKJIcn2YfBheIN4+mGJGm6RhkBPA94FfD1JF9tZW8CTkpyBINpnM3AawCq6qYklzK4uLsDOK2qHgBIcjpwBbAXsL6qbhpjXyRJ0zDKXUCfZ+L5+8t3s8/bgbdPUH757vaTJM0fPwksSZ0yACSpUwaAJHXKAJCkThkAktQpA0CSOmUASFKnDABJ6pQBIEmdMgAkqVMGgCR1ygCQpE4ZAJLUKQNAkjplAEhSpwwASeqUASBJnTIAJKlTBoAkdcoAkKROGQCS1CkDQJI6ZQBIUqcMAEnqlAEgSZ0yACSpUwaAJHXKAJCkTk0ZAEmWJ/lMkluS3JTk9a388UmuTPLN9nxAK0+S9ybZlOSGJM8aOtbaVv+bSdbOXbckSVMZZQSwAzijqp4KPAc4Lckq4EzgqqpaCVzV1gGOB1a2xzrgfTAIDOAs4NnAkcBZO0NDkjT/pgyAqrqjqr7Slu8DbgGWAScAF7ZqFwIvacsnABfVwLXA/kkOBo4Frqyqu6vqHuBK4Lix9kaSNLK9p1M5yQrgmcCXgIOq6g4YhESSA1u1ZcDtQ7ttaWWTle96jnUMRg4ceuih02meJI3dijM/uSDn3XzOC+f8HCNfBE6yL/BXwO9V1Q92V3WCstpN+YMLqs6rqtVVtXrp0qWjNk+SNE0jBUCSRzJ48//zqvpoK76zTe3Qnre18i3A8qHdDwG27qZckrQARrkLKMD5wC1V9e6hTRuAnXfyrAUuGyp/dbsb6DnAvW2q6ArgmCQHtIu/x7QySdICGOUawPOAVwFfT/LVVvYm4Bzg0iSnArcBL2vbLgfWAJuA+4FTAKrq7iRvA65r9d5aVXePpReSpGmbMgCq6vNMPH8PcPQE9Qs4bZJjrQfWT6eBkqS54SeBJalTBoAkdcoAkKROGQCS1CkDQJI6ZQBIUqcMAEnqlAEgSZ0yACSpUwaAJHXKAJCkThkAktQpA0CSOmUASFKnDABJ6pQBIEmdMgAkqVMGgCR1ygCQpE4ZAJLUKQNAkjplAEhSpwwASeqUASBJnTIAJKlTBoAkdcoAkKROTRkASdYn2ZbkxqGys5N8J8lX22PN0LY3JtmU5BtJjh0qP66VbUpy5vi7IkmajlFGABcAx01Q/p6qOqI9LgdIsgo4EXha2+fPkuyVZC/gXOB4YBVwUqsrSVoge09VoaquSbJixOOdAFxSVT8BvpVkE3Bk27apqm4FSHJJq3vztFssSRqL2VwDOD3JDW2K6IBWtgy4fajOllY2WflDJFmXZGOSjdu3b59F8yRJuzPTAHgf8GTgCOAO4F2tPBPUrd2UP7Sw6ryqWl1Vq5cuXTrD5kmSpjLlFNBEqurOnctJPgB8oq1uAZYPVT0E2NqWJyuXJC2AGY0Akhw8tPobwM47hDYAJyZ5VJLDgZXAl4HrgJVJDk+yD4MLxRtm3mxJ0mxNOQJIcjFwFLAkyRbgLOCoJEcwmMbZDLwGoKpuSnIpg4u7O4DTquqBdpzTgSuAvYD1VXXT2HsjSRrZKHcBnTRB8fm7qf924O0TlF8OXD6t1kmS5oyfBJakThkAktQpA0CSOmUASFKnDABJ6pQBIEmdMgAkqVMz+ioISZpPK8785EI34WHJEYAkdcoAkKROGQCS1CkDQJI6ZQBIUqe8C2gOLOQdC5vPeeGCnVvS4uIIQJI6ZQBIUqcMAEnqlAEgSZ0yACSpUwaAJHXKAJCkThkAktQpA0CSOmUASFKnDABJ6pQBIEmdMgAkqVMGgCR1asoASLI+ybYkNw6VPT7JlUm+2Z4PaOVJ8t4km5LckORZQ/usbfW/mWTt3HRHkjSqUUYAFwDH7VJ2JnBVVa0ErmrrAMcDK9tjHfA+GAQGcBbwbOBI4KydoSFJWhhTBkBVXQPcvUvxCcCFbflC4CVD5RfVwLXA/kkOBo4Frqyqu6vqHuBKHhoqkqR5NNNrAAdV1R0A7fnAVr4MuH2o3pZWNln5QyRZl2Rjko3bt2+fYfMkSVMZ90XgTFBWuyl/aGHVeVW1uqpWL126dKyNkyT93EwD4M42tUN73tbKtwDLh+odAmzdTbkkaYHMNAA2ADvv5FkLXDZU/up2N9BzgHvbFNEVwDFJDmgXf49pZZKkBbL3VBWSXAwcBSxJsoXB3TznAJcmORW4DXhZq345sAbYBNwPnAJQVXcneRtwXav31qra9cKyJGkeTRkAVXXSJJuOnqBuAadNcpz1wPpptU6SNGf8JLAkdWrKEYAk7bTizE8udBM0Ro4AJKlTBoAkdcoAkKROGQCS1CkDQJI65V1ADzMLdZfG5nNeuCDnlTRzjgAkqVMGgCR1ygCQpE4ZAJLUKQNAkjplAEhSpwwASeqUASBJnTIAJKlTBoAkdcoAkKROGQCS1CkDQJI6ZQBIUqcMAEnqlAEgSZ0yACSpU/6PYBoL/ycyafFxBCBJnZrVCCDJZuA+4AFgR1WtTvJ44CPACmAz8PKquidJgD8F1gD3AydX1Vdmc36pRws12tLDzzhGAL9WVUdU1eq2fiZwVVWtBK5q6wDHAyvbYx3wvjGcW5I0Q3MxBXQCcGFbvhB4yVD5RTVwLbB/koPn4PySpBHMNgAK+Lsk1ydZ18oOqqo7ANrzga18GXD70L5bWtmDJFmXZGOSjdu3b59l8yRJk5ntXUDPq6qtSQ4Erkzyf3ZTNxOU1UMKqs4DzgNYvXr1Q7ZLksZjViOAqtranrcBHwOOBO7cObXTnre16luA5UO7HwJsnc35JUkzN+MRQJJ/Djyiqu5ry8cAbwU2AGuBc9rzZW2XDcDpSS4Bng3cu3OqSJop74iRZm42U0AHAR8b3N3J3sCHq+pvk1wHXJrkVOA24GWt/uUMbgHdxOA20FNmcW5J0izNOACq6lbgGROUfw84eoLyAk6b6fkkSePlJ4ElqVMGgCR1ygCQpE4ZAJLUKQNAkjplAEhSpwwASeqUASBJnTIAJKlTBoAkdcoAkKROGQCS1CkDQJI6ZQBIUqcMAEnqlAEgSZ0yACSpUwaAJHXKAJCkThkAktQpA0CSOmUASFKnDABJ6pQBIEmdMgAkqVMGgCR1ygCQpE4ZAJLUqXkPgCTHJflGkk1Jzpzv80uSBuY1AJLsBZwLHA+sAk5Ksmo+2yBJGpjvEcCRwKaqurWq/gm4BDhhntsgSQL2nufzLQNuH1rfAjx7uEKSdcC6tvrDJN+YxfmWAHfNYv/Fprf+gn3uRXd9zjtn1efDRqk03wGQCcrqQStV5wHnjeVkycaqWj2OYy0GvfUX7HMv7PPcmO8poC3A8qH1Q4Ct89wGSRLzHwDXASuTHJ5kH+BEYMM8t0GSxDxPAVXVjiSnA1cAewHrq+qmOTzlWKaSFpHe+gv2uRf2eQ6kqqauJUl62PGTwJLUKQNAkjq16ANgqq+WSPKoJB9p27+UZMX8t3K8RujzG5LcnOSGJFclGeme4D3ZqF8hkuQ3k1SSRX/L4Ch9TvLy9rO+KcmH57uN4zbC7/ahST6T5O/b7/eahWjnuCRZn2Rbkhsn2Z4k722vxw1JnjXWBlTVon0wuJD8D8CTgH2ArwGrdqnzu8D72/KJwEcWut3z0OdfAx7Tln+nhz63evsB1wDXAqsXut3z8HNeCfw9cEBbP3Ch2z0PfT4P+J22vArYvNDtnmWffxV4FnDjJNvXAH/D4DNUzwG+NM7zL/YRwChfLXECcGFb/kvg6CQTfSBtsZiyz1X1maq6v61ey+DzFovZqF8h8jbgj4F/nM/GzZFR+vzvgHOr6h6Aqto2z20ct1H6XMBj2/LjWOSfI6qqa4C7d1PlBOCiGrgW2D/JweM6/2IPgIm+WmLZZHWqagdwL/AL89K6uTFKn4edyuAviMVsyj4neSawvKo+MZ8Nm0Oj/JyfAjwlyf9Ocm2S4+atdXNjlD6fDbwyyRbgcuB189O0BTPdf+/TMt9fBTFuU361xIh1FpOR+5PklcBq4Plz2qK5t9s+J3kE8B7g5Plq0DwY5ee8N4NpoKMYjPI+l+TpVfX9OW7bXBmlzycBF1TVu5I8F/hg6/P/m/vmLYg5ff9a7COAUb5a4md1kuzNYNi4uyHXnm6kr9NI8gLgzcCLq+on89S2uTJVn/cDng58NslmBnOlGxb5heBRf7cvq6qfVtW3gG8wCITFapQ+nwpcClBVXwQezeCL4h6u5vTrcxZ7AIzy1RIbgLVt+TeBT1e7urJITdnnNh3yPxm8+S/2eWGYos9VdW9VLamqFVW1gsF1jxdX1caFae5YjPK7/dcMLviTZAmDKaFb57WV4zVKn28DjgZI8lQGAbB9Xls5vzYAr253Az0HuLeq7hjXwRf1FFBN8tUSSd4KbKyqDcD5DIaJmxj85X/iwrV49kbs858A+wJ/0a5331ZVL16wRs/SiH1+WBmxz1cAxyS5GXgA+I9V9b2Fa/XsjNjnM4APJPl9BlMhJy/mP+iSXMxgCm9Ju65xFvBIgKp6P4PrHGuATcD9wCljPf8ifu0kSbOw2KeAJEkzZABIUqcMAEnqlAEgSZ0yACSpUwaAJHXKAJCkTv1/HEtQwvaQS64AAAAASUVORK5CYII=\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.hist(weights)\n", "plt.title('Distribution of weights')\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "# Let us choose a threshold of 0.6.\n", "# Too high, we will have disconnected components\n", "# Too low, the graph will have too many connections\n", "adjacency[adjacency < 0.6] = 0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Remark: The distances presented here do not work well for categorical data." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Graph visualization\n", "\n", "To conclude, let us visualize the graph. We will use the python module networkx." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "# A simple command to create the graph from the adjacency matrix.\n", "graph = nx.from_numpy_array(adjacency)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let us try some direct visualizations using networkx." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/home/michael/.conda/envs/ntds_2018/lib/python3.6/site-packages/networkx/drawing/nx_pylab.py:611: MatplotlibDeprecationWarning: isinstance(..., numbers.Number)\n", " if cb.is_numlike(alpha):\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "nx.draw_spectral(graph)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Oh! It seems to be separated in 3 parts! Are they related to the 3 different species of iris?\n", "\n", "Let us try another [layout algorithm](https://en.wikipedia.org/wiki/Graph_drawing#Layout_methods), where the edges are modeled as springs." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/home/michael/.conda/envs/ntds_2018/lib/python3.6/site-packages/networkx/drawing/nx_pylab.py:611: MatplotlibDeprecationWarning: isinstance(..., numbers.Number)\n", " if cb.is_numlike(alpha):\n" ] }, { "data": { "image/png": "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VcimbTZT6jG/zUqzBoXIztatW+nh4cFly5ZlOSs4MTGRkyZNYpUqVbhr164c7/OXX35hjRo1+Pzzz/P27duZHnPp0iX27t2b1apV4/r163NdtvHChQt88cUXqVar+f777zM2NjZXt0tPo9Fw9erVbNq0KWvUqMHFixf/V2DDFtfs2ttnfL1xcjKNsBWDS1sSuulZ6JruFJiu2zZt2pSenp5ZBmy5cuUyfG4qbHB5UF6bv79pVGHoUNP3XHq+wkq0Wi3feustVqtWjcePH8/yuL/++osBAQEcOnQoo6Ojs73Pmzdvsk+fPgwICOCvv/6a6TH379/n+PHjqVaruXDhQmo0mlyd75kzZ/j888/T09OTCxYsYFxcXK5ul97t27f59ttv08PDg127duXOnTszD/x81CywSrOzI0ePznbP9OJAQjc9C85eViqVdHJyYpkyZcyBamdnR39//yxD2OZKPVqipb4TlfW8ooiFhYWxdevW7NGjR5ZBmpyczBkzZtDLyyvHNboajYYffvgh3d3d+dFHH2U6lJyYmGg+5s033+SDBw9yda4nTpxgr1696O3tzU8//TTjBvS5YDQauX//fvbr149ubm584403eOXKlZxvmBq8xX2o2QZKz0roZqYA63TT7wrk4ODApUuX0t3dnalDx9MVCq4D+PPjgJ3r7PxEUYyfrf2La61WTK65iNJhz5499PLy4oIFC7Ic0j19+jTr16/Pvn375riD0O7du1mzZk3269ePt27dyvB1vV7Pb775hlWqVOGgQYN4/fr1XJ3n4cOH2aVLF/r6+nLZsmW57hGn9ejRI65YsYL16tVj3bp1uXz58jwtPyJpGprt39/0BtnZ+cm/3eIyy9kGSs9K6GamgBWpmgHmWcup7ZWGDbkFpl5w+uu1qeUft8A0a3mjUmn9X15rNgleUYj0ej3nzp3LypUrZ1nbWKvV8v3336eHhwfXrVuXbeWnW7dusV+/fqxRo0am13mNRiN37drF+vXrs127djx27FiO52g0Grlv3z527NiR/v7+XLVqVbZlJ7Ny5coVvvnmm3Rzc2Pfvn25b9++PFWxylRkZOZDuN27W78nLD1dG5bP2suvKZXm4WRnZ2fa29vneaOD/6EUXNPNTfAWg0kPomSJiIjgM888w44dOzI8PDzTY/755x82a9aMXbp0YVhYWJb3lZyczI8+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K5mcnJzleZ04cYLDhw9nxYoV+corr/DMmTOWe9Ki1JHQtZJ3332XvXr1ol6vZ506dVjf05MG2SQhd02pJNNcqxO27++//2bNmjU5fvx48wQkg8HApUuX0t3dnUuXLn1i1nJERARHjRrFKlWqmK/rGgwGrl27llWrVmW/fv14+fLlJx7DaDTy119/ZZs2bRgQEMDVq1dn2VNNTk7munXr2KJFC/r5+XHhwoV88OBB4X0DRKkhoWslKSkprF+/Pjds2MCoqChOVKmohywbylWzszMtG+rXj8zD7i2iePrmm2+oVqu5YcMG8+du3brFTp06sVWrVk+Ep16v55dffkkPDw++9dZb5olOv//+O5s0acJWrVrxzz//fOL+jUYjf/75Z7Zo0YJ169blhg0bMr2uS5qKX7zzzjv08vLiM888w59++inLY4XIDwldKzpx4gQ9PT0Z9/HH1Eud5rw3G93EWpgkJiZy5MiRrFu3rnmWsdFo5Ndff23ePi9t4B09epRNmzZl+/btef78eZKmiVXdunVjjRo1+OOPPz5xrddgMPB///sfGzduzEaNGnHz5s2Z1jc2Go08ePAgBw4cSFdXV7722mtPzHoWwpIkdK3si5deoibdul1peWwSvDbn8uXLbNCgAYcNG2aeKXz37l12796dTZo04blz58zHRkZG8pVXXqG3tzfXr19Po9HIu3fv8pVXXjHXX067P65er+fGjRtZr149BgUF8eeff850GU9iYiL/7//+j40aNWKtWrW4dOnSHJcICVFQErpWpu/dm/p8ho0RoAGg/vG/Vg8/awev1GS2CZs2baJarebKlStpNBppNBq5ceNGenp6cs6cOeYA1ev1XLFiBT08PPjmm2/y4cOHjI+P57vvvks3NzdOnz79iZKPWq2Wq1evZkBAANu0acNff/0107C9fv06p06dSnd3d/bs2ZN79uyRHX5EkZHQtaaICNO1yQKETfprwOk/1mbyuRLZpCZzsZeSksJJkyaxevXqPHXqFElTL3bAgAGsU6cOQ9K8aTp+/DibN2/Otm3b8uzZs9TpdFyxYgUrVarE4cOHP1FaMTk5mStXrqS/vz87derE/fv3Zwhbg8HAPXv2sFevXnR3d+eUKVN4/fr1onniQqQhoWtNn3xS4NDNqhkeB+4dlKJesNRkLrZu3brFFi1asG/fvube6bZt21ip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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "nx.draw_spring(graph)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Save the graph to disk in the `gexf` format, readable by gephi and other tools that manipulate graphs. You may now explore the graph using gephi and compare the visualizations." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "nx.write_gexf(graph,'iris.gexf')" ] } ], "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.7.0" } }, "nbformat": 4, "nbformat_minor": 2 }