{
"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",
"
year
\n",
"
gvkey1
\n",
"
gvkey2
\n",
"
score
\n",
"
name1
\n",
"
name2
\n",
"
sic1
\n",
"
sic2
\n",
"
size1
\n",
"
size2
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
1998
\n",
"
1078
\n",
"
1602
\n",
"
0.0274
\n",
"
ABBOTT LABORATORIES
\n",
"
AMGEN INC
\n",
"
3845
\n",
"
2836
\n",
"
74.211937
\n",
"
36.866437
\n",
"
\n",
"
\n",
"
1
\n",
"
1999
\n",
"
1078
\n",
"
1602
\n",
"
0.0352
\n",
"
ABBOTT LABORATORIES
\n",
"
AMGEN INC
\n",
"
3845
\n",
"
2836
\n",
"
87.854384
\n",
"
48.541222
\n",
"
\n",
"
\n",
"
2
\n",
"
2000
\n",
"
1078
\n",
"
1602
\n",
"
0.0348
\n",
"
ABBOTT LABORATORIES
\n",
"
AMGEN INC
\n",
"
3845
\n",
"
2836
\n",
"
70.098508
\n",
"
93.428689
\n",
"
\n",
"
\n",
"
3
\n",
"
2001
\n",
"
1078
\n",
"
1602
\n",
"
0.0218
\n",
"
ABBOTT LABORATORIES
\n",
"
AMGEN INC
\n",
"
3845
\n",
"
2836
\n",
"
110.299430
\n",
"
34.410965
\n",
"
\n",
"
\n",
"
4
\n",
"
2002
\n",
"
1078
\n",
"
1602
\n",
"
0.0366
\n",
"
ABBOTT LABORATORIES
\n",
"
AMGEN INC
\n",
"
3845
\n",
"
2836
\n",
"
40.140853
\n",
"
42.840198
\n",
"
\n",
" \n",
"
\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",
"
year
\n",
"
gvkey1
\n",
"
gvkey2
\n",
"
score
\n",
"
name1
\n",
"
name2
\n",
"
sic1
\n",
"
sic2
\n",
"
size1
\n",
"
size2
\n",
"
\n",
" \n",
" \n",
"
\n",
"
4796
\n",
"
2000
\n",
"
1690
\n",
"
5606
\n",
"
0.0314
\n",
"
APPLE INC
\n",
"
HP INC
\n",
"
3663
\n",
"
3570
\n",
"
60.079253
\n",
"
190.637477
\n",
"
\n",
"
\n",
"
4852
\n",
"
2000
\n",
"
1690
\n",
"
11399
\n",
"
0.0813
\n",
"
APPLE INC
\n",
"
WESTERN DIGITAL CORP
\n",
"
3663
\n",
"
3572
\n",
"
10.652736
\n",
"
15.988003
\n",
"
\n",
"
\n",
"
4884
\n",
"
2000
\n",
"
1690
\n",
"
12141
\n",
"
0.0930
\n",
"
APPLE INC
\n",
"
MICROSOFT CORP
\n",
"
3663
\n",
"
7372
\n",
"
44.120740
\n",
"
619.890226
\n",
"
\n",
"
\n",
"
4904
\n",
"
2000
\n",
"
1690
\n",
"
12142
\n",
"
0.0096
\n",
"
APPLE INC
\n",
"
ORACLE CORP
\n",
"
3663
\n",
"
7370
\n",
"
33.605576
\n",
"
79.457232
\n",
"
\n",
"
\n",
"
10644
\n",
"
2000
\n",
"
3226
\n",
"
14369
\n",
"
0.0143
\n",
"
COMCAST CORP
\n",
"
US CELLULAR CORP
\n",
"
4841
\n",
"
4812
\n",
"
40.733093
\n",
"
9.311580
\n",
"
\n",
" \n",
"
\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
}