{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Quickstart\n", " \n", "This tutorial provides a quick overview about the different tools available in `evomap`. \n", "\n", "In general, input data is expected in the form of either higher-dimensional feature vectors, or in the form of pairwise relationships. \n", "\n", "Given such data, `evomap` provides a flexible set of tools to process and manipulate the data, map it to lower-dimensional space, and to evaluate and explore the resultant maps.\n", "\n", "## Background\n", "\n", "**Last updated:** September 2023\n", "\n", "\n", "This quickstart guide is based on the following paper. *If you use this package or parts of its code, please cite our work*.\n", "\n", "**References**\n", "\n", "\n", "``` \n", "[1]Matthe, M., Ringel, D. M., Skiera, B. (2022), \"Mapping Market Structure Evolution\", Marketing Science, forthcoming.\n", "```\n", "\n", "\n", "Read the **full paper** here (open access): https://doi.org/10.1287/mksc.2022.1385\n", "\n", "**Contact:** For questions or feedback, please get in touch.\n", "\n", "## Module Overview\n", "\n", "`evomap` entails the following main modules:\n", "\n", "1. `evomap.preprocessing`: Tools for preprocessing input data.\n", "2. `evomap.mapping`: Tools for mapping input data to lower-dimensional space.\n", "3. `evomap.printer`: Tools for drawing and annotating maps.\n", "4. `evomap.metrics`: Tools for evaluating maps quantitatively.\n", "\n", "Besides, it includes a few additional module (such as `evomap.datasets`, which provides example datasets used for these tutorials). \n", "\n", "## Example Application\n", "\n", "For a high-level overview of how these modules work together, we generate a market structure map for the 'Text-Based Network Industry' (TNIC) data, provided by Hoberg & Philips. The original data is provided at https://hobergphillips.tuck.dartmouth.edu/. If you use these data, please cite their work." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Step 1: Loading the Relationship Data\n", "\n", "We use a smal subsample taken from these data. The sample is included in the `evomap.datasets` module. " ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "ExecuteTime": { "end_time": "2022-04-19T13:35:58.274407Z", "start_time": "2022-04-19T13:35:58.072923Z" } }, "outputs": [], "source": [ "from evomap.datasets import load_tnic_sample_small\n", "df_tnic_sample = load_tnic_sample_small()" ] }, { "cell_type": "code", "execution_count": 2, "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", " \n", " \n", " \n", " \n", " \n", " \n", "
yeargvkey1gvkey2scorename1name2sic1sic2size1size2
01998107816020.0274ABBOTT LABORATORIESAMGEN INC3845283674.21193736.866437
11999107816020.0352ABBOTT LABORATORIESAMGEN INC3845283687.85438448.541222
22000107816020.0348ABBOTT LABORATORIESAMGEN INC3845283670.09850893.428689
32001107816020.0218ABBOTT LABORATORIESAMGEN INC38452836110.29943034.410965
42002107816020.0366ABBOTT LABORATORIESAMGEN INC3845283640.14085342.840198
\n", "
" ], "text/plain": [ " year gvkey1 gvkey2 score name1 name2 sic1 sic2 \\\n", "0 1998 1078 1602 0.0274 ABBOTT LABORATORIES AMGEN INC 3845 2836 \n", "1 1999 1078 1602 0.0352 ABBOTT LABORATORIES AMGEN INC 3845 2836 \n", "2 2000 1078 1602 0.0348 ABBOTT LABORATORIES AMGEN INC 3845 2836 \n", "3 2001 1078 1602 0.0218 ABBOTT LABORATORIES AMGEN INC 3845 2836 \n", "4 2002 1078 1602 0.0366 ABBOTT LABORATORIES AMGEN INC 3845 2836 \n", "\n", " size1 size2 \n", "0 74.211937 36.866437 \n", "1 87.854384 48.541222 \n", "2 70.098508 93.428689 \n", "3 110.299430 34.410965 \n", "4 40.140853 42.840198 " ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_tnic_sample.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The data consists of a time-indexed *edgelist*. That is, each row corresponds to a firm-pair. The 'score' variable captures each pair's similarity." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To build a small subsample, we first select a handful of firms:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "firms = ['APPLE INC', 'AT&T INC', 'COMCAST CORP', 'HP INC',\n", " 'INTUIT INC', 'MICROSOFT CORP', 'ORACLE CORP', 'US CELLULAR CORP',\n", " 'WESTERN DIGITAL CORP']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We then collect these firms' pairwise relationships at a single point in time:" ] }, { "cell_type": "code", "execution_count": 4, "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", " \n", " \n", " \n", " \n", " \n", " \n", "
yeargvkey1gvkey2scorename1name2sic1sic2size1size2
47962000169056060.0314APPLE INCHP INC3663357060.079253190.637477
485220001690113990.0813APPLE INCWESTERN DIGITAL CORP3663357210.65273615.988003
488420001690121410.0930APPLE INCMICROSOFT CORP3663737244.120740619.890226
490420001690121420.0096APPLE INCORACLE CORP3663737033.60557679.457232
1064420003226143690.0143COMCAST CORPUS CELLULAR CORP4841481240.7330939.311580
\n", "
" ], "text/plain": [ " year gvkey1 gvkey2 score name1 name2 sic1 \\\n", "4796 2000 1690 5606 0.0314 APPLE INC HP INC 3663 \n", "4852 2000 1690 11399 0.0813 APPLE INC WESTERN DIGITAL CORP 3663 \n", "4884 2000 1690 12141 0.0930 APPLE INC MICROSOFT CORP 3663 \n", "4904 2000 1690 12142 0.0096 APPLE INC ORACLE CORP 3663 \n", "10644 2000 3226 14369 0.0143 COMCAST CORP US CELLULAR CORP 4841 \n", "\n", " sic2 size1 size2 \n", "4796 3570 60.079253 190.637477 \n", "4852 3572 10.652736 15.988003 \n", "4884 7372 44.120740 619.890226 \n", "4904 7370 33.605576 79.457232 \n", "10644 4812 40.733093 9.311580 " ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_tnic_sample = df_tnic_sample.query('year == 2000').query('name1 in @firms').query('name2 in @firms')\n", "df_tnic_sample.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To process these data via mapping methods, we first need to transform the edgeliste into square matrix form: " ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "from evomap.preprocessing import edgelist2matrix\n", "sim_mat, labels = edgelist2matrix(\n", " df_tnic_sample, score_var = 'score', id_var_i= 'name1', id_var_j= 'name2')" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "ExecuteTime": { "end_time": "2022-04-19T13:35:58.290333Z", "start_time": "2022-04-19T13:35:58.277368Z" } }, "outputs": [ { "data": { "text/plain": [ "array([[0. , 0. , 0. , 0.03, 0. , 0.09, 0.01, 0. , 0.08],\n", " [0. , 0. , 0. , 0. , 0. , 0. , 0. , 0.02, 0. ],\n", " [0. , 0. , 0. , 0. , 0. , 0. , 0. , 0.01, 0. ],\n", " [0.03, 0. , 0. , 0. , 0. , 0.06, 0.1 , 0. , 0.04],\n", " [0. , 0. , 0. , 0. , 0. , 0.04, 0. , 0. , 0. ],\n", " [0.09, 0. , 0. , 0.06, 0.04, 0. , 0.08, 0. , 0.06],\n", " [0.01, 0. , 0. , 0.1 , 0. , 0.08, 0. , 0. , 0.02],\n", " [0. , 0.02, 0.01, 0. , 0. , 0. , 0. , 0. , 0. ],\n", " [0.08, 0. , 0. , 0.04, 0. , 0.06, 0.02, 0. , 0. ]])" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sim_mat.round(2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As a result, we obtain a symmetric matrix of pairwise similarities. " ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Smallest matrix entry: 0.00 \n", " Largest matrix entry: 0.10\n", "Similarity between MICROSOFT CORP and ORACLE CORP: 0.08\n", "Similarity between APPLE INC and HP INC: 0.03\n" ] } ], "source": [ "import numpy as np \n", "print(\"Smallest matrix entry: {0:.2f} \\n Largest matrix entry: {1:.2f}\".format(np.min(sim_mat), np.max(sim_mat)))\n", "print(\"Similarity between {0} and {1}: {2:.2f}\".format(labels[5], labels[6], sim_mat[5,6]))\n", "print(\"Similarity between {0} and {1}: {2:.2f}\".format(labels[0], labels[3], sim_mat[0,3]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Step 2: Preprocessing" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Different mapping methods require different input data. Here, the input data connsists of *pairiwse similarities*. We will map them to 2D space via Classic Multidimensional Scaling (CMDS). CMDS, however, requires *pariwise distances*. Among other features, `evomap.preprocessing` provides various transformations between such different types of relationship data.\n", "\n", "One simple way to transform similarities to distances is by mirroring them: " ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "ExecuteTime": { "end_time": "2022-04-19T13:35:58.857814Z", "start_time": "2022-04-19T13:35:58.293331Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Smallest matrix entry: 0.00 \n", " Largest matrix entry: 1.00\n", "Distance between MICROSOFT CORP and ORACLE CORP: 0.92\n", "Distance between APPLE INC and HP INC: 0.97\n" ] } ], "source": [ "from evomap.preprocessing import sim2diss\n", "dist_mat = sim2diss(sim_mat, transformation= 'mirror')\n", "print(\"Smallest matrix entry: {0:.2f} \\n Largest matrix entry: {1:.2f}\".format(np.min(dist_mat), np.max(dist_mat)))\n", "print(\"Distance between {0} and {1}: {2:.2f}\".format(labels[5], labels[6], dist_mat[5,6]))\n", "print(\"Distance between {0} and {1}: {2:.2f}\".format(labels[0], labels[3], dist_mat[0,3]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Step 3: Mapping relationship data to lower-dimensional space\n", "\n", "With all input data in the right format, you can map it to lower-dimensional space. \n", "To do so, `evomap.mapping` provides implementations of multiple different mapping methods. \n", "\n", "Here, we apply (Classic) Multidimensional Scaling (aka. Principal Coordinate Analysis):" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "ExecuteTime": { "end_time": "2022-04-19T13:36:01.109794Z", "start_time": "2022-04-19T13:35:58.860808Z" } }, "outputs": [], "source": [ "from evomap.mapping import CMDS\n", "model = CMDS(n_dims = 2).fit(dist_mat)\n", "map_coords = model.Y_" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The resultant model output is a 2D array of shape (n_samples, 2) containing the map coordinates." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(9, 2)" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "map_coords.shape" ] }, { "cell_type": "markdown", "metadata": { "ExecuteTime": { "end_time": "2022-04-19T13:26:04.581553Z", "start_time": "2022-04-19T13:26:04.560608Z" } }, "source": [ "### Step 4: Draw the map\n", "\n", "To visualize the estimated map coordinates, `evomap.printer` provides several functions (such as ```draw_map()```), which can create highly customizable maps." ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "ExecuteTime": { "end_time": "2022-04-19T13:36:01.561589Z", "start_time": "2022-04-19T13:36:01.110792Z" } }, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjcAAAIzCAYAAAD8uTi4AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAA9hAAAPYQGoP6dpAABQoUlEQVR4nO3dd1xW9f//8SdD0BQQKYxL1EvFvRfuNBemOXGkWblHammammWpuBVnVoaalabgSBzoB1fuzIVWWlaKezQQnIBwfn/44/p6dYGCWdnxcb/dzu0W7/frvM/7XJfJ03Pe57qcDMMwBAAAYBLO//YEAAAAHibCDQAAMBXCDQAAMBXCDQAAMBXCDQAAMBXCDQAAMBXCDQAAMBXXB90xNTVV58+fl4eHh5ycnB7mnAAAAOwYhqGrV6/KYrHI2fne12YeONycP39e+fPnf9DdAQAAsuzMmTPy9/e/Z80DhxsPDw/bQTw9PR90GAAAgPtKSEhQ/vz5bfnjXh443KTdivL09CTcAACAf0RmlsKwoBgAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAAJgK4QYAcE/h4eGyWCxasmSJXfvAgQNlsVhsm7+/v8qXL6933nlH165dkyTt3r3brsZisSggIECdOnXSgQMHbGNZLBbt3r073eOnN0baFhgYmOG87x4zNDRUBQsW1I8//uhQFxgYqPDwcLu2TZs2qW3btipevLjKlCmjbt266fjx45l7wfCvI9wAAO5p1apVslqtWrZsmUNfixYtFBMTo5iYGB04cEAfffSR1q1bp5EjR9rVpdXExMQoOjpanp6e6ty5sxISEjI9j7vHSNvWr1+f6f2Tk5P11ltv3bdu3rx56t27txo2bKh169YpIiJCOXLkUKtWrXTixIlMHw//HsINACBDv/32m3bu3Kk33nhDe/fu1enTp+36s2fPLl9fX/n6+ipv3ryqUaOGunfv7hA60mp8fX1VuHBhjRkzRvHx8RlerUnP3WOkbT4+Ppne/+mnn9b+/fvTDWlpTp06pZCQEE2ePFl9+vRRQECASpUqpdmzZ8tqtSo0NDTTx8O/h3ADAMjQmjVr5OnpqTZt2ihv3rz3DAZpXFxclC1btnvWuLq6StJ96x6mQoUKqVu3bgoJCcnwitGqVauUJ08etW7d2q7d2dlZM2fO1LBhw/6JqeIvItwAADIUGRmphg0bytnZWUFBQVq+fLkMw0i3NjU1Vd99950WLlyooKCgDMeMi4vTmDFjlCdPHlWtWvXvmnq6hgwZIldXV40fPz7d/qNHj6pcuXJydnb89Vi0aFEVKFDg754iHgLCDQBAkpSSkqKff/5Zp06dkmEYOn/+vPbt26cmTZpIkpo2bapTp07pm2++se2zcuVKBQQEKCAgQIUKFdJzzz2nUqVKOay5SaspXLiwSpcurW+++UYfffSRPD09Mz2/tDHu3mbNmpWlc8yVK5dGjx6tRYsW6dChQw798fHx8vDwyNKYePS4/tsTAAD8++bNm6eQkBDbmpqKFSuqdu3acnd3V7169SRJNWrUkJeXlyIiIlStWjVJUuPGjfXOO+9IunOr6cknn1T27Nkdxt+0aZMkycnJSZ6envL29s7yHNPGuFvu3LmzPE7z5s21ZMkSDR8+XFFRUXZ93t7eio+Pz/KYeLQQbgDgMTdnzhz1799fHTt21Mcff6xr165p5syZev/995UnTx4VK1bMVpuSkqK1a9dq3Lhxku5cCbFarfc9RmZq/okx0owfP17PPvusPv30U7v2cuXKae7cuTIMQ05OTnZ9q1ev1tatWzV9+vSHNg/8PQg3APAYu3XrlkaNGqXu3btr3rx5tvYyZcqobNmyeuqpp/Tll1/a2o8fP64+ffpk6RHsR5HValX//v01efJkuxDTvHlzTZw4UatWrbJbVJySkqK5c+fK39//35gusohwAwCPsQMHDui3335T37597drXrl0rHx8f/fDDDypYsKBy5MghSSpRooSmTZumiIgI5c2b96HOJSYmRomJiXZt1atXt/335cuX093vySefTHcB8P0MGDBAK1asUGxsrK3N399fgwcP1htvvKFff/1VjRo10pUrVzRr1iydPHlSc+bMyfJx8M8j3AAAHERGRqpSpUoOa1Ik6ZVXXtHIkSNVq1Yt+fn5PbRjjh071qHt7s/BqVChQrr7HThw4IHm4ebmpgkTJqhjx4527a+99posFovmz5+vqVOnKnv27AoMDNSaNWse6q0x/H2cjIye6buPhIQEeXl5KT4+Pkur3QEAj47ExET5+/urZcuWdrelkpOTVbNmTXl6emrz5s3/4gyBO7KSO7hyAwCPMXd3d40ePVr9+vXT9evX1aVLF127dk0zZszQ4cOHCTb4TyLcAMBj7tVXX5W7u7tCQkK0dOlSSVLlypW1YcMG1alT51+eHZB13JYCAEi680RQbGys3NzclD9//n97OoAdbksBALLMxcVFRYoU+benAfxlfP0CAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINAAAwFcINADymXnrpJQ0aNMiubdWqVbJYLAoNDbVrnzFjhho2bChJCg4OlsViSXcLDw+37bN9+3a1aNFChQsXVvHixfXiiy/qyJEjtv6MxrBYLAoMDMz0sUJDQx36ChcurAYNGigqKsp2vNDQUBUsWFA//vijw2sRGBhoN/e7/Xn8ggULqnr16poyZYqSk5Ntdbt375bFYnHYf8mSJWrWrJmKFSumokWLqnXr1tq4caNdTXBwsO01DwwMvOdrk+b06dOyWCwaMGBAunMODg5O93wysmnTJrVt21bFixdXmTJl1K1bNx0/ftyhbvv27Wrbtq0CAgJUsmRJdezYUXv27Lnna5bRexIeHm5Xky9fPhUrVkw9e/bUzz//nKX5341wAwCPqWrVqikmJsaubdeuXcqbN6927dpl137gwAHVrFnT9nOfPn0UExPjsLVs2VKSdOTI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h4erXbt2ypcvnypUqKAff/xRv//+u2bMmKEqVar821MEHhpuSwHAY+T8+fP65JNP9MMPPyhfvnzq0qWLw8JU4FGUldxBuAEAAI881twAAIDHFuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAACYCuEGAPDIsFgsslgsOnfunEPfZ599JovFotDQUEnS7t27ZbFY7GpSU1M1b948NWjQQIULF1bVqlX1zjvv6MqVK7aa0NBQ23HStsKFC6tBgwaKiopyOG5kZKSaNWumwoULq2zZsurRo4eOHj3qULdq1So1btxYVqtVpUqVUu/evRUbG/tA4w0cONBhjmnb7du3M+yzWCwKDAzM8PU9fvy4+vTpo3Llyqlo0aJq3ry5Nm/e7FB38uRJ9e3bV6VLl1aRIkUUFBSkpUuX2tWkvf53bwULFlRgYKDtPZKkM2fOONQVKlRILVu2TPfYDwPhBvgbBAcH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HTt2VM2aNRUQEKARI0aobNmy8vT01Keffqrq1avbbk1dvnxZ165d09dff62YmBjFxMRo27Zteumll3T9+nXt2bMnw9d43bp1atu2rUqXLq0VK1ZozZo1KlmypIKDg1WlShWFh4crISFBX331lVq2bKn8+fNrypQpcnd3V82aNfXqq68qb968Wrx4se0qjZ+fn2JiYrR//36VLl1awcHBat68ud566y1bME0TExOj9evXy9vbWy+//LI8PT3VuXNnPssGAP4/wo3JhIeHa+jQoapdu7by58+v2rVra9KkSdq4caMuXbqkyMhINWzYUM7OzgoKCtLy5cs1Z84cnTp1SitWrFCdOnXk4uKigwcPqnfv3tq+fbu2b98u6c6C2Bw5cujmzZuaM2eOZs2apX379um9995Tr169VKxYMUlSQECAvLy89PPPP2v79u06d+6ctm/fruDgYGXLlk3PP/98unOvVq2aDMNQ5cqV1bVrV40ZM8YuILm7u6tTp06aMmWKDMNQnjx5tGfPHr344otycXGxBbiYmBh16tRJ+/btU+vWrVWmTBnFxMSoa9euOnHihA4cOKAGDRrIyclJr732mo4fP67ExESdOXNGu3fvVsGCBW23z/7s6tWrevPNNzVw4EANGzZMJUuWVNGiRTVq1Cg1bNhQx44dk6+vr+3W3AsvvKDq1atr9OjRatq0qaZPn673339fO3bsUMmSJdWmTRsdOnRIKSkpio2N1aBBg5SYmKhZs2bpnXfekdVqtd2KS+Pr66v69eurc+fO+vzzz9W/f3/Fx8c7fPgfADyuCDcm4+zsrJ07dyo1NVW//vqrNm3apNTUVG3ZskW3bt3Svn37bE8hNW3aVKdOndKCBQscHl9OSkpSkSJF7B5fPnPmjJyd7/yRuXjxonr16qW5c+dq8ODBeu+992z7urq6atCgQfL09NTw4cNVu3ZtDR8+XA0aNFDRokUzXMuStoC4evXqGjp0qJycnHThwgW7mkmTJqlmzZoyDENt2rRRv379VKhQIX355Zfy9vZWdHS0kpOTFRQUpK+++sr2KPiyZcsUFBQkX19fRUREyMPDQ3ny5FGBAgU0YMAA1a5dW4MGDVKVKlVUo0YNhytLaTZu3Khr167Z1rXc7b333tO0adO0fPly+fr66uzZs1qyZIkmTpyoTp066YMPPpCTk5OaNm2qokWL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", "text/plain": [ "
" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from evomap.printer import draw_map\n", "draw_map(X = map_coords,\n", " label = labels,\n", " fig_size= (7,7))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Step 5: Evaluating maps\n", "\n", "Finally, `evomap.metrics` provides typically used metrics to evaluate the resultant maps' goodness-of-fit (such as the hitrate of nearest neighbor recovery):" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hitrate of 3-nearest neighbor recovery (adjusted or random agreement): 0.63\n" ] } ], "source": [ "from evomap.metrics import hitrate_score \n", "score = hitrate_score(\n", " D = dist_mat, X = map_coords, n_neighbors = 3, input_format = 'dissimilarity')\n", "\n", "print(\"Hitrate of 3-nearest neighbor recovery (adjusted or random agreement): {0:.2f}\".format(score))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Naturally, `evomap` becomes more useful when moving beyond such a very simple application. \n", "\n", "For such more complex examples, check out the further examples. " ] } ], "metadata": { "interpreter": { "hash": "87ffa25eb3bb30b413c256579b892ccdc10cf1c52e8cd490d95c13bdebb280f2" }, "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.9.17" }, "mystnb": { "execution_timeout": -1 }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": false }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "window_display": false } }, "nbformat": 4, "nbformat_minor": 4 }