{
"cells": [
{
"cell_type": "markdown",
"id": "284c313a-e684-4b96-b12b-2c669f12a87b",
"metadata": {},
"source": [
"# Demo: Snekmer Model/Cluster\n",
"\n",
"In this notebook, we will demonstrate how to apply Snekmer toward the analysis of protein sequences."
]
},
{
"cell_type": "markdown",
"id": "7319a320",
"metadata": {},
"source": [
"## Getting Started\n",
"\n",
"### Workflow\n",
"\n",
"Snekmer proceeds through a defined workflow executed as individual steps on Snakemake. Two operation modes are available: `model` (supervised machine learning) and `cluster` (unsupervised clustering). The user should select the mode that best suits their individual use case.\n",
"\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"id": "e180e9fb",
"metadata": {},
"source": [
"### Notes on Using Snekmer\n",
"\n",
"Snekmer assumes that the user will primarily process input files using the command line. For more detailed instructions, refer to the [documentation](https://snekmer.readthedocs.io/en/latest/getting_started/cli.html).\n",
"\n",
"The basic process for running Snekmer is as follows:\n",
"\n",
"1. Verify that your file directory structure is correct and that the top-level directory contains a **config.yaml** file.\n",
" - A template configuration file is included in the Snekmer code repository [here](https://github.com/PNNL-CompBio/Snekmer/blob/main/resources/config.yaml).\n",
"2. Modify **config.yaml** as needed.\n",
"3. Use the command line to navigate to the directory containing both the **config.yaml** file and **_input_** directory.\n",
"4. Run `snekmer cluster`, `snekmer model`, or `snekmer search`.\n",
"\n",
"Depending on the selected operation mode, output files will vary.\n",
"\n",
"The process detailed above is handled by the included [tutorial](https://snekmer.readthedocs.io/en/latest/tutorial/index.html). We will use this demo to break down the process followed by the tutorial and understand the output files created in the process."
]
},
{
"cell_type": "markdown",
"id": "2a5fe0b3-a906-4b4b-9e86-00724bb34746",
"metadata": {},
"source": [
"## Running Snekmer\n",
"\n",
"First, install Snekmer using the instructions in the [user installation guide](https://snekmer.readthedocs.io/en/latest/getting_started/install.html).\n",
"\n",
"To ensure that the tutorial runs correctly, activate the conda environment containing your Snekmer installation and run the notebook from the environment.\n",
"\n",
"Next, run the [Snekmer tutorial](https://snekmer.readthedocs.io/en/latest/tutorial/index.html). This runs all three Snekmer modes on the demo example files and produces all output files. The tutorial uses the included default configuration parameters to guide the analysis, but the user can modify these parameters if a different configuration set is desired. The tutorial command line instructions are copied below:\n",
"\n",
"```bash\n",
" conda activate snekmer\n",
" cd resources/model_cluster_search_demo\n",
" ./run_demo.py\n",
"```\n",
" "
]
},
{
"cell_type": "markdown",
"id": "bc3992e2-8c23-49ac-856e-89a2810867ea",
"metadata": {},
"source": [
"Finally, we will initialize some parameters and parse filenames for this demo notebook."
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "24ab6fcc-374d-4e85-b654-43b6bfae7025",
"metadata": {},
"outputs": [],
"source": [
"# imports\n",
"import glob\n",
"import os\n",
"import yaml\n",
"from itertools import product\n",
"\n",
"import numpy as np\n",
"import pandas as pd\n",
"import matplotlib.pyplot as plt\n",
"import seaborn as sns"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "06acdf21",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Loaded config from ../config.yaml\n",
"{'k': 8, 'alphabet': 2, 'input_dir': 'input', 'input_file_exts': ['fasta', 'fna', 'faa', 'fa'], 'input_file_regex': '.*', 'nested_output': False, 'score': {'scaler': True, 'scaler_kwargs': {'n': 0.25}, 'labels': 'None', 'lname': 'None'}, 'cluster': {'method': 'agglomerative-jaccard', 'params': {'n_clusters': 'None', 'linkage': 'average', 'distance_threshold': 0.92, 'compute_full_tree': True}, 'cluster_plots': False, 'min_rep': None, 'max_rep': None, 'save_matrix': False, 'dist_thresh': 100}, 'model': {'cv': 5, 'random_state': 'None'}, 'model_dir': 'output/model/', 'basis_dir': 'output/example-model/', 'score_dir': 'output/scoring/', 'motif': {'n': 2000}, 'learn_apply': {'save_apply_associations': False, 'fragmentation': False, 'version': 'absolute', 'frag_length': 50, 'min_length': 50, 'location': 'random', 'seed': 999, 'conf_weight_modifier': 20, 'selection': 'top_hit', 'threshold': 'Median', 'weight_top': 0.7, 'weight_distance': 0.3, 'apply_output': 'snekmer_results.csv'}}\n",
"Input files: ['TIGR03149.faa', 'nirS.faa', 'nxrA.faa']\n",
"Families: ['TIGR03149', 'nirS', 'nxrA']\n"
]
}
],
"source": [
"# --- Paths (relative to resources/tutorial/snekmer_demo.ipynb) ---\n",
"BASE = os.path.join(\"..\", \"model_cluster_search_demo\")\n",
"IN_DIR = os.path.join(BASE, \"input\")\n",
"OUT_DIR = os.path.join(BASE, \"output\")\n",
"\n",
"# --- Load config ---\n",
"with open(os.path.join(\"..\", \"config.yaml\"), \"r\") as f:\n",
" config = yaml.safe_load(f)\n",
"print(\"Loaded config from ../config.yaml\")\n",
"print(config)\n",
"\n",
"# --- Discover input families from input/*.fa* ---\n",
"in_files = sorted(glob.glob(os.path.join(IN_DIR, \"*.fa*\")))\n",
"filenames = [os.path.splitext(f)[0] for f in in_files] # strip only last ext\n",
"families = sorted([os.path.basename(os.path.splitext(f)[0]) for f in in_files])\n",
"\n",
"print(\"Input files:\", [os.path.basename(f) for f in in_files])\n",
"print(\"Families:\", families)"
]
},
{
"cell_type": "markdown",
"id": "9a92b722-8834-4c06-81e1-b3f4c512aca2",
"metadata": {},
"source": [
"## Snekmer Cluster Mode\n",
"\n",
"Results and output files from Snekmer's clustering mode can be found in the **cluster** directory.\n",
"\n",
"Overall results are contained within **snekmer.csv**. To see the results, load and parse the file:"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "a7d55546-398b-4f58-8267-119b15e3b19b",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
filename
\n",
"
sequence_id
\n",
"
sequence_length
\n",
"
background
\n",
"
cluster
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
nxrA
\n",
"
WP_012964344.1
\n",
"
1154
\n",
"
False
\n",
"
0
\n",
"
\n",
"
\n",
"
1
\n",
"
nxrA
\n",
"
WP_013249767.1
\n",
"
1147
\n",
"
False
\n",
"
0
\n",
"
\n",
"
\n",
"
2
\n",
"
nxrA
\n",
"
WP_080885705.1
\n",
"
1148
\n",
"
False
\n",
"
0
\n",
"
\n",
"
\n",
"
3
\n",
"
nxrA
\n",
"
WP_013249749.1
\n",
"
1146
\n",
"
False
\n",
"
0
\n",
"
\n",
"
\n",
"
4
\n",
"
nxrA
\n",
"
WP_053381689.1
\n",
"
1145
\n",
"
False
\n",
"
0
\n",
"
\n",
"
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
\n",
"
\n",
"
96
\n",
"
nirS
\n",
"
WP_011805163.1
\n",
"
574
\n",
"
False
\n",
"
2
\n",
"
\n",
"
\n",
"
97
\n",
"
nirS
\n",
"
WP_012250943.1
\n",
"
560
\n",
"
False
\n",
"
2
\n",
"
\n",
"
\n",
"
98
\n",
"
nirS
\n",
"
WP_013518994.1
\n",
"
574
\n",
"
False
\n",
"
2
\n",
"
\n",
"
\n",
"
99
\n",
"
nirS
\n",
"
WP_014426879.1
\n",
"
582
\n",
"
False
\n",
"
2
\n",
"
\n",
"
\n",
"
100
\n",
"
nirS
\n",
"
WP_085938646.1
\n",
"
559
\n",
"
False
\n",
"
2
\n",
"
\n",
" \n",
"
\n",
"
101 rows × 5 columns
\n",
"
"
],
"text/plain": [
" filename sequence_id sequence_length background cluster\n",
"0 nxrA WP_012964344.1 1154 False 0\n",
"1 nxrA WP_013249767.1 1147 False 0\n",
"2 nxrA WP_080885705.1 1148 False 0\n",
"3 nxrA WP_013249749.1 1146 False 0\n",
"4 nxrA WP_053381689.1 1145 False 0\n",
".. ... ... ... ... ...\n",
"96 nirS WP_011805163.1 574 False 2\n",
"97 nirS WP_012250943.1 560 False 2\n",
"98 nirS WP_013518994.1 574 False 2\n",
"99 nirS WP_014426879.1 582 False 2\n",
"100 nirS WP_085938646.1 559 False 2\n",
"\n",
"[101 rows x 5 columns]"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Cluster results\n",
"cluster_csv = os.path.join(OUT_DIR, \"cluster\", \"snekmer.csv\")\n",
"results = pd.read_csv(cluster_csv).sort_values(by=\"cluster\").reset_index(drop=True)\n",
"results[\"cluster\"] = results[\"cluster\"].astype(str)\n",
"results\n"
]
},
{
"cell_type": "markdown",
"id": "418d059f-4118-43c7-97ea-6d51a651c5a5",
"metadata": {},
"source": [
"As seen above, the results table summarizes the input sequences as well as the cluster assignment determined by Snekmer. In the above table, each row corresponds to an individual sequence, and the columns summarize various aspects per sequence:\n",
"\n",
"| **Column Name** | **Description** |\n",
"|-----------------|--------------------------------------------------------------------------------------------------------------------------------|\n",
"| filename | Name of file containing given sequence |\n",
"| sequence_id | Sequence ID, as taken from FASTA file |\n",
"| sequence_length | Length of sequence (i.e. number of characters long the sequence is) |\n",
"| background | True if sequence has been labeled as a background sequence; False otherwise |\n",
"| cluster | Numerical cluster assignment, given as an integer between 0 and *n*, where *n* is the number of clusters determined by Snekmer |"
]
},
{
"cell_type": "markdown",
"id": "d9422bc5-bd2c-4876-8f5c-86f2e68c120e",
"metadata": {},
"source": [
"Recall that the demo files consist of 3 sets of sequences previously annotated to 3 individual protein families. To view the cluster assignments given by the Snekmer clusters (see `cluster` column), we can generate a summary plot of how cluster assignments are distributed across sequences of known annotation."
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "48ee5ea0-4b4d-4f13-9714-2664f58c4d2a",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA0sAAAKmCAYAAACc6QWeAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjcsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvTLEjVAAAAAlwSFlzAAAXEgAAFxIBZ5/SUgAAZzRJREFUeJzt3Qm8zGX///GP/di3EAmlCCXRYkkkSUlJ2nVHWpTuiPZSilKUaLuTRMudiopUFCktRLgRIilE7rKWfT3/x/u6/9/5zTnnmjmLc87MnPN6Ph7zmHNm/c53Zr7zfX+v6/pcBZKTk5MNAAAAAJBCwZT/AgAAAAAISwAAAAAQAS1LAAAAAOBBWAIAAAAAD8ISAAAAAHgQlgAAAADAg7AEAAAAAB6EJQAAAADwICwBAAAAgAdhCQAAAAA8CEsAAAAA4EFYAgAAAAAPwhIAAAAAeBCWAAAAAMCDsARks27dulmBAgXcOXLOgAED3Hpu3bo1qzmP4zsFxM93Lj99H/X7oteq35vcNnbsWPfctWrVyvXnRkqEJcSt5ORkGz9+vF1yySVWs2ZNK168uJUqVcpq165tZ555pvXt29c++OAD+/vvv2O9qDgMev+ee+4569ixo3ufS5Ys6d7r6tWr2wUXXGDDhg2z//73v3G/jidOnOh+UHWeiP71r3+5H2adWrRoEevFQRxYuHCh+0wPHz481osS94Id24ycVq9eHevFTejgwgEy5LbCuf6MQAZs27bNOnXqZDNnzgxdVrhwYStRooStXbvWfvnlF/v222/tmWeesTFjxuSLI1x50ejRo+2uu+6yrVu3hi5TUCpWrJitX7/enaZMmWIPPPCAPfjgg+48Xikkvfbaa3bddde5z24ivheBWbNm2YoVK6xu3boWD6pWreqWRefI3bD0yCOPuIMYffr0YdVn0BFHHGGFChWKeH206+IF3zng/9CyhLj0j3/8wwUl/aj069fPfvrpJ9u7d69t3rzZdu/ebYsWLbInn3zSTj755FgvKrJIweeGG25wQalevXouaPzxxx+2a9cuF5Z1/umnn1rXrl1t//79rpUROUPfp/nz51v58uXtmmuuSROeYm3w4MG2fPlydw7Eu++//961hkc6HX300Rbv+M4B/4ewhLizcuVKmzx5svt70KBB9tRTT9nxxx9vBQsWDLUwNWzY0O6++2535POKK66I8RIjs9555x17/PHH3d+XX365/ec//3EBuXLlyilamNq1a2dvvPGGe58bNGjAis4hQTDSd+nGG290f7/++ut24MAB1jkAIF8jLCHuaMc4cPHFF6d7e+1Up6YBkerbrH7k+/bts6FDh7pWKI2HKVu2rLVp08amTp2a7mOrq59aNtQNJSkpyd339NNPd61aO3bsyMKrM/vss8+sdOnSoQGywQ6p+rGH92lfs2aN23GtUaOGe26N1VJXtJ07d4Yea8mSJW75dKRSt1GoVMBUS0w0enx1q1EA0TgwdW884YQTrHfv3q6bY0YGm37xxReuu5m6a6gFMKNdIfV+qOud1K9f37UoqdtdNCeeeKILTdk5KDe9AhEKdOeff75VqVLFihQpYuXKlXPr96KLLrIXXnjB9uzZ42735ZdfusfR6xCdpx6joNukpvfupptuco+p9a/3QQcB1OK2adOmDC3ze++95wKlQqYOJmRlELJabP/973+7v9WF8KyzznLvsVr5Pv7446j3VSuvDmY0a9bMtUppPVWqVMm9r3osLV9q+ry//PLL7jWou5LuU7FiRdfNTmHN16KV3oByjW9Ud1wth75b+p6eccYZ7nl0XbT7H+62Ivw9Vsu3xlLqu6rtkrYbt912m23cuDF0e32vb7nlFjvmmGPcd1bfb7Web9++Peq61mPo+3/KKae45dJ9jz32WOvRo4ctXbrUe5/gs6mT/Pzzz3b99de77YW+cxoXqG2Murv6Xlf37t1Dy5z6M536s6ZW4M6dO7vHLFq0qJUpU8Ytnz6f+oxs2bLFMkrrX8+hdRnNjBkz3O302U+93cro9zdWDh06ZJ9//rndfvvt1rRp09B603ehVatW9tJLL0XcjufGb0Vmizioh4C2Y7rPu+++G/W2/fv3d7fT50Pfz5z266+/ut/s9u3bW506ddx3W9tbbaf0OxjpNy81bR+eeOIJt53WY2ibd+6557qu4unJyvYecSQZiDPvvvuutp7u9Nlnn2XpMWrWrOnu/9xzzyWfccYZ7u8iRYoklypVKvTYBQoUSB49erT3/gcPHky+/fbbQ7fVSfctVKhQ6P+6desmr169Os19r7vuOne9zlN744033HLo+nvuuSfFdb/++mvosd97773kcuXKub/LlCmT4nlbtmyZvG/fvuSPPvoouUSJEu6ysmXLutcT3OaKK66I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iv/vvPNO69+/vzsFNDZIfEEpCCwaR6Gj3Wrx0QD0aBo0aOC9fNWqVVa7du10lzm86h3jNpCfqNtpgLAEAADiXcKOsD7rrLPsjTfecAFl165drvXosccec918HnroIVfMIbBjxw53rm5AkQQtPEH3OAAAAAD5W8K2LD366KMp/lcXvPvvv99OPfVUO++882zAgAF20003uTLh2W3p0qWZanECAAAAkHgStmUpEs2fpMCkiltz5sxxlwXzMKkFKpKdO3e68/S64AEAAADIH/JcWJKgNPiGDRvceVDwYd26dRGDksKVShkTlgAAAADk2bCkQg3h45Dq1q1rxYoVs40bN9r69evT3H7BggXuvGHDhpafqBJZtJMm6Y0XmnjYVzlNl2VkUuKsWr16dY4/R6TXlt26devmnufLL7/M8ecCAADICxJ2zFIkCkRff/11ipLgGrfUpk0bmzJlio0fP9769OmT4j4TJkxw5x07drT86LrrrvNefsIJJ+T6sgAAAADxIiHD0qxZs9xcLQo34aWI1QrQtWtX163uoosuSlEqvG/fvi4sqdR4hw4dQl31Zs+ebSNHjnSlw3v06GH50dixYy3eff7557Z///5YLwYAAADykYQMSz/99JN1797djjzySNd6pKCzZs0amz9/vu3Zs8dVpRs1alSK+7Rt29Z69+7tSoo3atTIzj33XDcx7LRp09x8L2PGjHGPg/iUkfmrAAAAAMvvY5bOOOMMu+WWW6xatWr2/fff27vvvmtLlixxIejpp592l1WuXDnN/YYPH+5CUb169VxIUquSQtRXX31lnTp1islrSQTq1njbbbe5MV0qgqFujeqid++997rCGKlpTIzGxmiMjFoA1WKnYKsxZGeeeaZrGQy89NJL7nH1mEcffbQr+X7o0KEsj+tRl0rd7uqrr454G5WU1230WchuKioyZMgQa9WqlR111FFWtGhR99o7d+7sPpfRKLQrzNevX9+SkpLc/W+//XbvOg5uP27cONfFVO+L7qPPttZhtMqPAAAAyJgCydrjQrYI5lmKNA9TQGFAk+gGxScKFoxNZg3CR3ofgaZNm9qiRYtcqFGgUeudimIoGOg1f/fdd6Hy7EFYOvvss11XSIXYgwcPusdQN0mVc9fkwHPnzrWXX37ZtQDqtloHM2fOdJMCa74sTTCcOiyp9TD1suo11KxZ0z22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AAAAAPAo7LsQsaUJVXft2pVQb0OJEiWsQIECsV4MAAAAINsQluKQglKpUqUskezYscNKliwZ68UAAAAAsg3d8IAoNmzYYIULF3atZtdffz3rCgAAIB+hZSnOXTz0IytcrLjFowN7d9ukuy60vOytt96ygwcPur/fe+89e/HFFy0pKSnWiwUAAIBcQFiKcwpK8RqW8oM33njDnVetWtW1Mk2aNMmuuOKKWC8WAAAAcgHd8IAIlixZYosWLbKjjz7aBg8enCI8AQAAIO8jLCFurF692o0Nat26te3evdvuvfdeq1mzphUrVsyOO+44e/LJJ12lwMA999zjbn/55ZeneaxNmzZZtWrVrFChQvbNN9+ELu/WrZu7z5dffmmffvqpnX322VauXDl32bZt21I8RhCMrr76arv00ktdxT/dZ+PGjTm6HgAAABAfCEuIO/v27bN27drZqFGj7NRTT3WBZv369S489e/fP3S7gQMH2imnnGLjx4+31157LcVj3Hjjja7b3H333WdnnnmmdyzS+eefbzt37nTnp512WorS54cOHbJ///vf7u+uXbu66oSdOnWyAwcO2Ntvv52jrx8AAADxgbCEuDN79mzXIvTrr7+6ogpTp061r7/+2l32zDPPuDLlUrRoURdoihcvbv/85z/d7UUha+LEiS4ADRgwwPscus24ceNs7ty5ofOyZcuGrv/iiy9cQDv55JPtxBNPDIUmoSseAABA/kBYQtwpWLCgjRw50sqUKRO6TC1MagHSHFTz5s0LXV6vXj176qmnbPv27XbNNdfYjz/+aHfccYfrMvfmm2+6st8+HTp0iFqoIQhEQUCSc8891ypXrmzff/+9rVixIpteLQAAAOIVYQlxR+OU6tatm+byOnXquHN1rwt36623uvCjFqmmTZu6rnVqgQpu73PRRRdFvE7jpd5//30X2jReKaDgddVVV7m/aV0CAADI+whLiDvVq1f3Xl66dGl3vnfv3jTXjR492s1/9Pfff7sWqJtuuinqc9SoUSPiderCp5aqNm3auCIR4YKWJnX/Cy82AQAAgLyHeZYQd9Sik1kffvih7dmzx/2tLnIa16SiDJFEm1g2aDXS4/iKQ6gQhCr3qcpey5YtM72sAAAASAyEJSS8lStXhsYptW/f3nWhu/322+3VV1/N9GP9+eefNm3aNPf3b7/95k7RQhVh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0urVqyNeV6RIETv66KOtVatWds8991j9+vWz86kBAAAAIH7DkuZTAgAAAIC8ICYFHgAAAADA8ntYUlEHnQAAAADA8ntY+uSTT+y8886zUqVK2RFHHOFO+rt9+/buOgAAAADId2HpjjvusI4dO9q0adNs165dVqZMGStbtqz7+7PPPnPX9e3bN7ufFgAAAADiNyy98847NmLECKtUqZI9++yzoS54W7ZssW3bttlzzz1nlStXdrd59913s/OpAQAAACB+w9KLL75oSUlJ9tVXX9ltt93mWpQCamHq1auXzZw504oVK+ZuCwAAAAD5IiwtWrTI2rRpY3Xq1Il4G12n2yxcuDA7nxoAAAAA4jcs7du3z0qWLJnu7XQb3RYAAAAA8kVYql27tutmt3Pnzoi3UaEH3Ua3BQAAAIB8EZYuv/xy+/PPP61Tp062cuXKNNevWrXKOnfubBs3brQrrrgiO58aAAAAALJV4ex8sDvvvNMmTZpkn3/+udWvX98aN25stWrVctetWbPG5s+fbwcPHrRTTz3V+vXrl51PDQAAAADxG5aKFy9uX375pd1333326quv2vfff+9O4ddff/31NnjwYPc3AAAAAOSLsCSlSpVy8yk9+eSTriXp999/d5dXq1bNmjRpYiVKlMjupwQAAACA+AtLM2bMsHXr1rmudep6F1AoatmyZYrbLlu2zObNm2dHH320nX322Yf71AAAAAAQn2Hpt99+sw4dOrjwo1ak9Oh2l1xyiQtXKgCh1iYAAAAAyHPV8F555RU3X9KQIUOsdOnS6d5etxk6dKjt3r3bRo8efThPDQAAAADxG5amTZtmlSpVcqXCM+qiiy6yKlWq2JQpUw7nqQEAAAAgfsPS8uXL7bTTTsv0/TS+acWKFYfz1AAAAAAQv2Fp586dVrZs2UzfT/fZsWPH4Tw1AAAAAMRvWCpfvrz98ccfmb6f7qP7AgAAAECeDEsqFf7dd9+5gg0ZtWvXLps9e3aKMuMAAAAAkKfC0oUXXui64g0aNCjD99FtFa46dux4OE8NAAAAAPEblnr27Okq2z3xxBMuBB06dCjibXXdwIED3W11n5tvvvlwnhoAAAAA4ndS2hIlSth7771nbdu2tYcffthGjRpll112mTVu3NiVFJeNGzfaggULbPz48W4y2qSkJHcf3RcAAAAA8mRYkubNm9usWbPs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BMSBtWvXunNV4PIJLl+zZk2uLhcAAPFgxIgR7rx9+/aMJ0SuIiwBcSAoh1qiRAnv9SqdKqoGBABAfvLJJ5/Y6NGjXavSwIEDY704yGcISwAAAIhLqoDXtWtXV2hl6NChobFLQG4hLAFxoFSpUqEJ+Xx27tzpzkuXLp2rywUAQKxoQnZ1u9u6dav17dvXevfuzZuBXEdYAuJAjRo13Pm6deu81weX16xZM1eXCwCAWNiyZYu1a9fOjdXt3r27PfXUU7wRiAnCEhAHgm4FmmPJJ7i8YcOGubpcAADEYhzv+eef7yam7dy5s40aNcoKFCjAG4GYICwBcaBFixZWtmxZW7VqlS1cuDDN9RMmTHDnHTt2jMHSAQCQOzSP0sUXX2xz58618847z8aNG2eFChVi9SNmCEtAHNBM5Lfddpv7u1evXqExSjJs2DA3v1KrVq2sSZMmMVxKAAByzsGDB+2qq66yGTNmWMuWLe399993v49ALBVIVnkRADG3Z88ea926tc2ZM8eqVq3qfijUV1v/V6pUyb777js79thjY72YQJ718ccfpyhLrCPb+ok844wzQpf179/fOnToEKMlBPL+XEp9+vRxf19yySVWpkwZ7+00fumII47I5aVDflU41gsA4H+SkpLsiy++sMGDB9tbb71lEydOdLOUd+vWze3ARZqwFkD22Lhxozs4kVr4ZboNgJyhqneBDz74IOLtBgwYQFhCrqFlCQAAAAA8GLMEAAAAAB6EJQAAAADwICwBAAAAgAdhCQAAAAA8CEsAAAAA4EFYAgAAAAAPwhIAAAAAeBCWAAAAAMCDsAQAAAAAHoQlAAAAAPAgLAEAAACAB2EJAAAAADwISwCAuLRz504bNmyYnX322ValShUrWrSolS9f3po1a2YPPfSQrV27NnTbAQMGWIECBWzs2LExXWYAQN5CWAIAxJ1Zs2bZcccdZ/369bO5c+faiSeeaF26dLHmzZvbqlWrbODAgVanTh2bPn16TJezdevWLqStXr06pssBAMgZhXPocQEAyJKFCxfaOeecY3v27LF77rnH+vfvbyVLlgxdf+jQIZs4caLdfffdtm7dOtYyACDHEJYAAHEjOTnZrr32WheU1LXu4YcfTnObggULWufOnV2g+u2332KynACA/IFueACAuDF16lRbsmSJVa9e3R544IGoty1btqzrnhdNrVq1XDc5ny+//NJd161btxSX79u3z1588UU77bTTrGLFilaiRAn3OBdeeKG9/fbb7jbqdqf7zpw50/1/zDHHuP+DU+oAOG7cOGvTpo0bc5WUlGT16tVzYXDXrl1Ru/a99dZb1rRpUytdurSVK1cu6msFAGQ/WpYAAHHj448/dueXXXaZFS4cm5+oa665xiZMmOACSsuWLa1MmTK2fv16++abb2zHjh125ZVXWqlSpey6665z4e6PP/6wSy+91F2WmroMdu3a1YUlXX/qqae6wDRv3jx75JFHbMqUKS60FS9ePM19Bw8ebK+88oq1aNHCBTVa0QAg9xGWAABxNV5JGjduHJPn//XXX11Qqlmzps2fP9+1LAXUNfA///mP+/uII45wlffUCqSw9NRTT7nWp9SefvppF5R0O50feeSRodarW2+91UaPHu1C0xNPPJHmvq+//rrNmDHDWrVqlaOvGQAQGd3wAABxY/Pmze68UqVKMXn+jRs3uvNTTjklRVASdZ9T2fKMOnDggA0ZMsQVp1D3vSAoicqgP/fcc+6yl19+2bVApdajRw+CEgDEGGEJAID/74QTTnDhRt0Bhw4dar///nuW182CBQts06ZNrty55olKTV3vmjRpYlu3brWVK1emuf6iiy7ifQGAGCMsAQDiRtCaE7Tw5DaNTxo1apQVK1bMlSY/6qijrG7dutazZ0/79ttvM/VYwdxL06ZNS1H8IfwUjNFSqEqtRo0a2fSqAABZxZglAEDcaNSokQslapVRYYSc5Ov6JldddZW1bdvWJk2aZJ999pmreDdy5Eh36tu3rxuHlJnH1+S6KtIQTeouf0G3PwBAbBGWAABxo0OHDvbCCy/Y+PHj3Xifw62Ip7FBoip2qavVRasupzFTN9xwgzup9Penn35qV1xxhQ0bNsyuv/56a9CgQbrPrfLnQdc+FYMAACQeuuEBAOJG+/btXRBZt26dPfbYY1Fv+/fff9vSpUuj3qZq1aru/KeffkpznbrHZYS6y2m5FOQk/DmDMKZiDqlpnibNBaWWqS1btmTouQAA8YWwBACIGwomb775puuCpklb77vvPtu5c2eK26il58MPP3RzFn3//fdRHy8ou605iw4ePBi6XGW8dUpNpcHff/99V9o7nMLOnDlz3N9HH3106PJq1aq58xUrVqR5rGDc0/bt261z5872yy+/pLmN5m964403or4GAEDs0A0PABB345amT5/uJnrV/EPPPvusK9mtinJ//fWXm9BVcxspUIUHF59evXrZSy+95OZOql+/vjVs2NBVnluyZIn17t3bnnnmmRS3X7NmjXtetQgpjKm097Zt2+yrr75yoadjx44pyoerYt1rr71mV199tbVr187dTzSZrNx77722fPlyF4jq1avnSpIfc8wxLowpYC1btswt07XXXpsj6xIAcHgISwCAuKOCCD///LMrqjB58mRbvHixK7GtcUdBdTqNJwrGBUWigKWgc9ddd7nucGrJUbnuoEJd6rDUtGlTGzRokJsMVmHm66+/tvLly7tAo3mPUhedUIuRHkMV9LSce/fuTRGWChYs6CaX7dKli5tPSS1hKl6hx1TQ03JpLBQAID4VSFZ/BgAAAABACoxZAgAAAAAPwhIAAAAAeBCWAAAAAMCDsAQAAAAAHoQlAAAAAPAgLAEAAACAB2EJAAAAADwISwAAAADgQVgCAAAAAA/CEgAAAAB4EJYAAAAAwIOwBAAAAAAehCUAAAAA8CAsAQAAAIAHYQkAAAAAPAhLAAAAAOBBWAIAAAAAS+v/AYAr9ZPyhi95AAAAAElFTkSuQmCC",
"text/plain": [
"
"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig, ax = plt.subplots(dpi=150)\n",
"g = sns.histplot(x=\"cluster\", hue=\"filename\", multiple=\"stack\", data=results, ax=ax)\n",
"\n",
"ax.set_xlabel(\"Cluster\")\n",
"ax.set_title(\"Snekmer Cluster Assignments vs. Family Label\")\n",
"g.legend_.set_title(\"Family Label\")"
]
},
{
"cell_type": "markdown",
"id": "26aabae1-7c4f-492c-a783-b8b93c36150f",
"metadata": {},
"source": [
"In this case, the true family labels are well-resolved by Snekmer's clustering algorithm. This result arises from the relative separation between sequences in each of these 3 families in terms of their amino acid recoding (AAR)-kmer profile. This will not always be the case for a given set of input sequences."
]
},
{
"cell_type": "markdown",
"id": "dad14a7c-f33e-4e6a-bb19-305f6a1ec0b3",
"metadata": {},
"source": [
"## Snekmer Model Mode\n",
"\n",
"We also train a kmer-based scoring model for the family of interest based on the prevalence of kmers in each family. The scoring model is then used to develop in-family vs. out-of-family classification models. Snekmer scoring output files can be found in the **score** directory, and model output files can be found in the **model** directory."
]
},
{
"cell_type": "markdown",
"id": "5448f151-eecf-4472-8b1a-b272ccebfdba",
"metadata": {},
"source": [
"### Kmer Probability Scores for Family Assignment\n",
"\n",
"For simplicity, below we will highlight one particular family chosen at random and display the kmer probability scores for assignment into the example family. However, Snekmer generates individual scoring models for each family, so feel free to explore the other family probability scores in the same manner."
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "8e1643c1",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"example family:\t nirS\n"
]
},
{
"data": {
"text/html": [
"
"
],
"text/plain": [
" filename sequence_id label nirS_score\n",
"0 nxrA WP_013249767.1 nxrA 0.026201\n",
"1 nxrA WP_080885705.1 nxrA 0.025791\n",
"2 nxrA WP_013249749.1 nxrA 0.035076\n",
"3 nxrA WP_053381689.1 nxrA 0.013643\n",
"4 nxrA WP_080885591.1 nxrA 0.027045\n",
"5 nxrA WP_053381686.1 nxrA 0.011141\n",
"6 nxrA WP_053378142.1 nxrA 0.012402\n",
"7 nxrA WP_053381277.1 nxrA 0.018167\n",
"8 nxrA WP_080886776.1 nxrA 0.041373\n",
"9 nxrA WP_053381280.1 nxrA 0.012130"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# first 10 probability scores for out-of-family kmers\n",
"seq_scores[seq_scores[\"label\"] != example_family].head(10)"
]
},
{
"cell_type": "markdown",
"id": "1b678e7d-a6d6-435d-8d57-337a5a6adf95",
"metadata": {},
"source": [
"Column descriptions are as follows:\n",
"\n",
"| **Column Name** | **Description** |\n",
"|-----------------|--------------------------------------------------------------------------------------------------------------------------------|\n",
"| filename | Name of file containing given sequence |\n",
"| sequence_id | Sequence ID, as taken from FASTA file |\n",
"| label | Label (i.e., family assignment) of the given sequence |\n",
"| \\\\_score | Score for the assignment of the sequence into the given family. M inimum possible score is -1; maximum possible score is 1.0. |"
]
},
{
"cell_type": "markdown",
"id": "4a5a0eba-fcd0-47b0-b30a-e32d778f60b6",
"metadata": {},
"source": [
"Perhaps unsurprisingly, the kmer probability scores for assignment into the example family differ significantly for sequences that are in-family vs. out-of-family.\n",
"\n",
"To better illustrate this point, we can generate boxplots of the probability score distributions per family."
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "125b0907-bc71-49c9-8897-9b5273bc6cde",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"image/png": "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AACAZBtF9uGHH7YjsPbo0cO8//77droSjSIr69evt9OTfPfdd6ZYsWLmoYceStRmAQAAAADJFmDWr1/ffPrpp+aGG26w82HOmTMn3XINVqupPxR8al0AAAAAQHJJWIApF1xwgVmzZo353//+Z2bNmmU2b95sXz/ppJNMmzZtzNVXX21rMAEAAAAAySehAaYogOzWrZt9AAAAAABSR8IG+QEAAAAApLaEBZgff/yxOf30081XX30Vcp3p06fbdSZOnJiozQIAAAAAkq2J7MiRI+1osWeffXbIddQPc926dWbEiBGmc+fOido0AKQ0DaJ28ODBnN4NBPD+Jvw+uVORIkVMWlpaTu8GACSVhAWYS5cuNY0bNzaFCxcOuY6WNWnSxCxZsiRRmwWAlKfgpV27dil/HHIzClVzpy+++MIULVo0p3cDAJJKwprIbt261Y4Wm5nKlSvbdQEAAAAAySVhNZilS5c2GzZsyHS9jRs3mhIlSiRqswAAj1fP+csUzu/jmAAhHDqWZnp8W5rjAwC5PcA844wzzNSpU81PP/1kGjZsGHQdLfv+++/NRRddlKjNAgA8FFwWyc8hAUKjAAYA8kQT2bvuusscO3bMdOrUyYwbNy7Dcr2mZcePH7frAgAAAACSS8JqMNu3b2/69u1rXnjhBXPNNdfYJrO1atWyy9asWWP++usvO9Jhr169zCWXXJKozQIAAAAAkq0GU55//nnz3//+15x66qlm165dZuHChfahv+vVq2feffddM2zYsERuEgAAAACQbDWYTteuXe1jy5YtdkAfqVatmh09FgAAAACQvBIeYDoKKAkqAQAAACB1ZFmAKarB1CTG27dvN1WqVDEdOnQw5cuXz8pNAgAAAADyWoC5dOlS8+abb5ozzzzT3HTTTRmWq6/l/fffb44ePep/rVixYmb48OHm2muvjX2PAQAAAADJNciPph1RgFmuXLkMy7766ivTr18/c+TIEVtzecUVV5hGjRqZffv22WB05cqV8e43AAAAACBZajBnzZplSpYsaacnCfTkk0/a57POOstMmzbNFC1a1P4/ePBg+3jllVfMq6++Gs9+AwCCOHSMwwKEwzUCALk0wFy3bp1p0aKFKVAg/Uf8/fff5ttvvzVpaWnmqaee8geX8tBDD9laz5kzZ8a31wCAoHp8W4YjAwAA8l4T2a1bt5oTTzwxw+sLFiwwx44dM2XKlLE1mF4KRps0aWLWr18f62YBAAAAAMlWg6kayh07dmR4/YcffrDPzZs3t+sEKlu2bLqBfwAAifPqObtM4fwcUSBcE1lq+gEgFwaYJ598sg0mDxw4kK4ZrKYlUWAZWHuZWc0nACB+Ci6LEGACAIC81kRWg/uoBrNnz57m0KFD9rWPPvrIzJgxw/7dpUuXDO/x+Xxm0aJFplq1avHsMwAAAAAgmWow77nnHjNy5EgzatQoM3r0aDui7K5du+yySy65xDRs2DDDe7788kuzc+dO06ZNm/j2GgAQ1KFj6prg4+gAYa8RAECuCzArVapk57u88cYbzbJly2zgKO3atbNBZzDPP/+8fx0AQOL1+LY0hxUAAOS9AFM0IuyPP/5ofvvtN7Nt2zZTtWrVsM1fn3vuOdtM9h//+Ec8mwUAAAAA5EJpPkV8yHINGjSwz8uXL+doA0goJeMHDx7kqOYy+k06d+5s/544caIpUqRITu8SAug3CTbiPQDEo0GK5/vjqsEEAOQ8ZZC9o3kjdwYy/EYAgFQQ8yiyAAAAAAB4EWACAAAAABKCABMAAAAAkBAEmAAAAACAhCDABAAAAAAkBAEmAAAAACD3TVOyd+9es2HDBrNnzx6TL18+U6ZMGVOrVi37NwAAAAAgucUdYG7cuNEMGzbMTiK9du3aDMs179fZZ59tbrvtNnPFFVfEuzkAAAAAQC4VV9XiqFGjTN26dW2AuWbNGuPz+fyP/Pnzm/Lly5tDhw6ZadOmmauuuspcdNFF5q+//krc3gMAAAAA8n6AOXPmTHPLLbeYggULmgceeMB8+eWXZtGiRWb8+PGmY8eO5ujRo6ZPnz5m3759ZsaMGbb28quvvrJBppYBAAAAAJJLzE1kn3nmGRtcqnayZcuW/tebNGliLr/8ctO7d28zcOBA06lTJ3POOefYx6OPPmqGDBliXn31VbscAAAAAJA8Yq7BnD9/vg0svcGlV79+/czx48fNuHHj/K898sgjplKlSub999+PdbMAAAAAgGQLMPfv329KlSoVcvkJJ5xgn7du3ep/Tf0yW7VqZVatWhXrZgEAAAAAyRZgavqROXPmmJ07dwZdrlFlpUqVKuleT0tLszWbAAAAAIDkEnOAee2115odO3aYDh06mHnz5vlf16ixb731lunVq5cNJjt37pzufZrKJDDoBAAAAACk8CA//fv3t7WUCxYsMK1btzaFCxe2TWa3bdvmn6pEQWajRo3SzZm5ePFi061bt0TtPwAAAAAgr9dgFi1a1E4/0qNHD/v3wYMHzZ9//mmbv2ognxdffNHOj+lVpEgR8/XXX5vBgwcnYt8BAAAAAMlQgynFixc3L7/8shk6dKhZuXKlnfOyQoUK5pRTTgm6vpa1bds2nk0CAAAAAJIxwHQ0H6a3KSwAAAAAIPUkJMAM58cffzR//fWXOeecc7J6UwCAPE7999XlIhl4v0eyfCfX3UWD+AEAkCMBZu/evc2sWbPM0aNHs3pTAIA8ToFYu3btTLIJHFE9L/viiy/s2AsAACR0kJ9oS6SzwoEDB8wjjzxi6tata0tUTzrpJNO9e3fz+++/R/U5NWvWtKWxoR4///xzluw/AAAAACSTmGswCxUqFNF6x44dy7C+gjbNlxlvKff5559v5s6daypXrmxLh9etW2dGjhxpJk+ebF+vVatWVJ950003BX1d068AALKeCgtVQ4bc/RsBAJDwAFNNXhUoRlo7megmskOGDLFBZKtWrcy0adNMiRIl7Osa0VZzdKomU9OoRGPUqFEJ3UcAQHR0X6H5JQAAKdhEtl69evb59ttvN7t27bLzXwZ7aFoSZRgCX4/H4cOHzSuvvGL/fvXVV/3BpfTr18+OaDtz5kyzcOHCuLYDAAAAAMiGAHPp0qVm4MCBtklq/fr1zYcffmiyy+zZs83u3btN7dq1TdOmTTMsv/LKK+3zpEmTsm2fAAAAACDV5Ytn7stBgwaZxYsX20Cva9euduS/1atXm6ym4FZOP/30oMvd65oiJRrPPfecueOOO+zIt2+99ZbZtm1bAvYWAAAAAFJD3NOUqPZS05C88cYb5oEHHjANGza0zwMGDLBBaFbYsGGDfa5atWrQ5e719evXR/W59913X7r/+/bta15++WXbnzNSDRo0CPq6Am8F4gAAAACQrBI2TYlq/lauXGk6dOhgHn30UdO4cWPzzTffmKywd+9e+1ysWLGgy4sXL26f9+zZE9HnXXbZZebjjz+2Aen+/fvNsmXLbF9OjXR76623mokTJyZw7wEAAAAgOcVdg+lVqVIlM378eBuQ9ezZ01x44YV5Yjjzl156KUMt5PPPP28HMrrtttvM/fffH/Ek2cuXL4+qZhMAAAAAkkXCajC9FIypNvOuu+4yFStWNNWrV0/o57tRY1XbGMy+ffvsc8mSJePazi233GL3f9WqVXaOTQAAAABANgeYLghU/8W1a9faRyK5gHXTpk1Bl7vXa9SoEdd28uXL5+83uWXLlrg+CwAAAACSXZYFmFlJ/Ttl0aJFQZe71zUfZrw0x6e3XycAAAAAIJcEmEuWLDHffvttXJ9x1llnmVKlStmRWfV5gcaNG2efL7300ri2o/6Uah6rwYTUHxMAAAAAkIsCzDvvvNOcf/75cX1GoUKF7CBC0qNHD3+fSxk6dKid/7Jt27amWbNm/tdfeeUVGyRqChWvKVOmmK+//jrDNvQZV111lfH5fHYkWW0TAAAAAJBNo8hGSkFbvB5++GEzffp0M2fOHFOnTh3Tpk0bO83IvHnzTIUKFcyIESPSrb99+3ZbGxnYl3L+/Plm8ODBtr+mmt6qtnLNmjW2me3Ro0fNueeea55++um49xcAAAAAkl2e7IMpmv5E82wOHDjQBoUTJkywAWa3bt1scFirVq2IPqddu3ame/fu5oQTTjCzZ8+2zWt/++03c/bZZ5vhw4fbILZo0aJZ/n0AAAAAIK9L88VYnRhpABdo8+bN5siRI+bYsWMmlbh5MEPNkwkAAAAg72uQ4vn+mJvIal7ItLS0mJq76n0AAAAAgOQSc4BZvnx5s2PHDrNixQpTpkyZiN6jYPSSSy4xixcvjnWzAAAAAIBkCzDPOOMMM3XqVLNp06aopvAoWLBgrJsEAAAAACTjID8KMFUjuWDBgsTuEQAAAAAgtWowNX2HpvXYvXt3VO/TnJLt27ePdbMAAAAAgGQbRRbRSfXRpAAAAIBU0CDF8/15dh5MAAAAAEDuQoAJAAAAAMgbAabmy9RAQNu3b8/qTQEAAAAA8mqAqQF+7rvvPtO8eXPTunVr8+STT5pDhw7ZZUuWLDFNmzY1tWvXNi1btjSVKlUyXbp0MX/++Wei9h0AAAAAkAyjyO7fv9+0adPGdl514wTNmzfPLFq0yLz55pumQ4cOttayfv36pnz58mbx4sXm008/NWvXrjU//PAD82ECAAAAQJKJuQZz2LBhZtmyZeb88883s2bNMnPnzjWdOnUyn3zyienZs6dJS0sz33//vV1nxowZZtOmTaZjx472/+HDhyf2WwAAAAAA8u40JaeffrrtX7lhwwZTokQJ+9qBAwdM9erVzc6dO80777xjunXrlu49v//+uznllFNMq1atzNdff21SSaoPVwwAAACkggYpnu+PuQbz119/tX0rXXApRYsWNWeeeab9+6KLLsrwnipVqphmzZrZWkwAAAAAQHKJOcA8evSoKVOmTIbXK1So4A8mg6lWrZodHAgAAAAAkFxiDjA1cM8ff/yR4XW1uA3X6vbIkSOmZMmSsW4WAAAAAJBsAWatWrXMzz//HHTwn40bN4Z8n95TuXLlWDcLAAAAAEi2AFNzX27ZssWsXLky3eulS5cO2TxWU5SsWLHC9t0EAAAAACSXmOfB7N27t52ipGzZshG/RyPHtm3b1lxxxRWxbhYAAAAAkGzTlCA6qT5cMQAAAJAKGqR4vj/mJrIAAAAAACSkiWwwe/fuNevXrzd79uyx/2u02Bo1aqSbKxMAAAAAkJziDjDXrFljXnzxRTNp0iQbXAajIPOyyy4zvXr1sqPPAgAAAACST1x9MF977TXTt29fO7elmxuzatWqpnjx4vb/ffv2mU2bNpnt27fb/wsWLGheeOEFc9ddd5lUk+ptsQEAAIBU0CDF8/0x12BOmTLF9OzZ05QrV8489NBD5sorr7TBZTAKMseOHWueeOIJc/fdd5uTTz7ZdOjQIZ79BgAAAAAkSw3meeedZxYsWGCWLFliTjnllIje8+uvv5omTZqYM844w3zzzTcmlaR6SQYAAACQChqkeL4/5lFkFy1aZC6++OKIg0upU6eOfY/eCwAAAABILnFNU3Lo0KGo33P48OF4NgkAAAAASLYAU01dp0+fbubPnx/xe+bNm2e+/PJL07Rp01g3CwAAAABItgDznnvusaPHnnvuuaZ///5mzpw55sCBAxnW02ta1q9fP9tv89ixY+bee++Nd78BAAAAAMk0TcmwYcNssHj8+HH/a2XKlDHFihWzf+/fv9/s2rXL/q3N5M+f3zz33HOmT58+JtWkemdfAAAAIBU0SPF8f1wBpvzyyy820NS0JRs2bAi6TvXq1U2nTp1M7969Td26dU0qSvUTLVo6LQ8ePJjTu4EwihQpYtLS0jhGAAAAHg1SPN8f8zyYjgLG1157zf69e/duG2Tu3bvX/l+iRAkbXJYqVSr+PUVKUXDZrl27nN4NhPHFF1+YokWLcowAAACQuADTS4Fkw4YNE/mRAAAAAIBUDDAjsXXrVjN06FDz9NNPZ/emkceaX6qGLFlqYzt37mz/njhxov1uySBZvgcAAADyYIC5ceNG8+yzz5oRI0bYDDcBJsJR375kbH6poCwZvxcAAAAQd4Cp0WPHjBlja5pUM1mxYkXToUMHc/XVV5t8+fL5A8vBgweb9957zxw9etS+dvnll3P0AQAAACDJxBxgKljs2LGj+eqrr+yIn87o0aPN2LFjzfjx4827775revbsaacr0TpdunQxgwYNMo0aNUrU/gMAAAAA8nqA+eqrr5rp06fbJn/dunWzw/Hu2bPHTJ061UyYMMHccccdZvjw4TawvPjii22T2CZNmiR27wEAAAAAeT/AVNPY/Pnzm5kzZ5oWLVr4Xx8wYIC58847zZtvvmn70T333HOmf//+idpfAAAAIFfauXOnmTx5slmyZIk5cOCAHXehadOmdj74smXL5vTuAdkizedt3xqF0qVLm8aNG9sAM9CaNWvMKaecYurXr5+yE4wGSvUJV1OZbjBuTk/mjgQAIPkcOnTIvPTSS7YlnxtzxKtAgQJ2nJJevXqZwoUL58g+Ivs0SPF8f8w1mGoOW7NmzaDLTj75ZPusABQAAABI5uDy3nvvtbWWokEvVXOpwTA16KUKmjUY5qRJk+zgl2rdR5CJZBZzgKmKTzWRDUZNY4V58gAAAJDMVHOp4FK1lMofK5gMpDyz8sdaT+srIAWSVbbNgwkAAAAkkx07dpgpU6bYv13TWDWPbN++ve1zqT6Zn3/+ebqmklr/lltuoU8mklZcAaamIdEjGJXShFquZcHapyM+KjU7ePAghzGX8f4m/D65k1pbuJYXAABE6rPPPjPHjh2zfxcvXtw89thj6Qa/lM6dO5sFCxaYRx55xOzbt8+ur/f961//4kAjKcUVYMY4PlDM70N4Cl7cYDLInXSTQe7D4EsAgFgocHSCBZeOXtdyN7PC/PnzCTCRtGIOMNVxGQAAAEhVW7Zssc/VqlULGVw6Wq71NNCPex+QjOiDmaT2nX6DMfn4eYGQjh81xRe9zwECAMTMdX059dRTI1pf6ynApMsMkhkRSLJScJm/YE7vBQAAQFL34f/777/NqlWrIlr/559/9r8PSFZZEmD+8ssv5o8//gi6rE6dOqZy5cpZsVkAAAAg2yhPq2lJVCup/pjhmslq+aZNm/zvA5JVXAHmJZdcYn777Tfz4YcfmqZNm/pff+qpp8x///vfoO9p2bKlmT17djybBQAAQBLJqyPhN2nSxCxdutT+PXDgQPPwww+bZs2aZVhv4cKFZsiQIf7/lW8+cOCAyUsYcR1ZHmB+8803dh6fbt26pQsuvQlF4IimKt2ZO3eufe95550X66YBAACQRJJhJPz9+/ebBx98MKJ1R40aZR95CSOuI8sDzLFjx9p54wYMGBB0uZZNnTo13WtqFlCzZk3z0UcfEWACAAAAQJKJOcD8/vvvbX/KunXrRvyeqlWrmoYNG9r3AgAAAK75pWrI8qJDhw7ZprE//vij/b98+fJm+/bt/ryvamfd/40aNTJPPPGEKVSokMlrGJgIWR5grl27NmQtpJrH6hGM5v+ZNWtWrJsFAABAHu63mGwKFy5s+1e+8cYbZtq0af5gUtygPgUKFDAXX3yxufPOO/NkcCnJdK7RnzSXBphqZ168ePGgy4YNG2ZLZ4IpWbKkfS+y2LEjHGKAawRAEkuGfoup4ujRo3bsEj2Q8+hPmksDzDJlythhmYMpXbq0fQSj94RaFi2NvqURa8eMGWM2bNhgypYta9q3b28ef/xxU6VKlag+a9euXWbQoEFmwoQJdoqVSpUqmcsvv9y+lqj9zU7FF3+Q07sAAAAAIMXEHGDWq1fPzJs3zxw5csQULFgw4jbqeo+GdE5Eqd35559vR6XVXEKdO3c269atMyNHjjSTJ0+2r9eqVSuiz1JThlatWtkpV/SeLl26mOXLl5sXX3zRDlSkPqMKXgEAAHKjYx2OZdHs5kCSOGpM/qn5c3ovUkLMSZGaZHz33Xfm5ZdfNv369YvoPVp33759pmPHjiZeauuuIFKBodq7lyhRwr4+dOhQ079/f9O9e3czY8aMiD6rT58+Nri84oor7Ai3aicvvXr18n+/vDaU9L6m1xuTP7LAH0hJx45Q0w8gaZBxBpBbpPlCjcYTQZNSTTmimkQFX9ddd13Y9T/44AM7Z6b6bWqAoHianR4+fNhUrFjR7N692yxatCjDPJyNGze2I3n98MMPQSe79dqyZYsd4UtBpZrZnnjiielqXDUo0c6dO83mzZvtNmPVoEED+6ya0ayiJsOuL8a+028wJh9FmUBIx4+a4ovet3/SFwNAXuS97wOIXFbf9xtkQ74/aftgKrC88sorTdeuXc3rr79urr32WhvsaXhm1/R08eLFto/k7Nmz7Wt6T7x9GvVZCi5r166dIbgU7ZMCzEmTJmUaYH7++efm+PHjpk2bNumCSzcq2KWXXmpGjBhhO2UrQM4rXMYZAAAAALJLXFVcGgRn4sSJ5uabb7bNZV0QGUiVpOXKlbP9Iy+55BITr6VLl9rn008/Pehy97qbjyjez1KAGclnAQAAZJe8PHdkMlPrPo0NIsonM39k7sNvkrXibkOpgNENrqPaQAVsO3bssMsUVKq5aocOHfzNYxNBTVlFTVuDca+vX78+Wz/LWyUeaPXq1bbGNSsl043Gmzgjd0qmm2ayfA8AqSUtLS1Lm/llJ+b0zP2YOxKRSkgnPQWOPXv2tI/ssHfvXvtcrFixkPsje/bsydbPymnJdKNB3rjRcL4BABIhWef0TKbCcsYrQKQYBSbBQnXmDVWzieSvjU1W1PoBAAAgKQJMNyXJ/v37gy7XVChSsmTJbP0sJA61sQAApA4KlnM/CpaR5QFmrVq14goe1CcxVtWrV7fPmzZtCrrcvV6jRo1s/SwAAABEj4JlIHnEHGBqYJ94EpF4aOAg0RyYwbjXGzVqlK2fBQAAAACpLOYAc+3atSannHXWWaZUqVK2FnTJkiWmSZMm6ZaPGzfOPmsOy8y0b9/e5MuXz8yaNcts3brVVKxY0b/s0KFDdi7N/Pnzm44dO2bBNwEAAACA5JEv1jeqyWg8j3gUKlTIP2Jtjx49/P0kZejQoXbOyrZt25pmzZr5X3/llVdMvXr1zAMPPJDusypXrmyuu+46c/jwYXPXXXeZo0eP+pfdd999Ztu2baZr167pAk8AAAAAQIL7YF511VXmmWeeMTnh4YcfNtOnTzdz5swxderUMW3atLFzVc6bN89UqFDBjBgxIt3627dvN6tWrTJbtmzJ8FnDhg0zc+fONePHj7dBaPPmze1osMuWLbOfraA1Xppv88iRI4wmCwAAACSx1atXm4IFC5pUlS+ePpiq3cvJkay++eYbM3DgQDuH5YQJE2yA2a1bN9tvMppBiMqXL2/mz59v7r77bluT+cknn5jdu3ebXr162dfLli0b9/5qPs1UPtFSnRKaeAa2ApA3ce0DqYlrP7UVLFjQ5v1TVZrP5/PF8kb1W1QwF1hTCCD0PKih5kkFkJy49oHUxLWPVBZzDSYAAAAAAF4EmAAAAACAnB3kRzRFyGOPPRbTex955JF4Ng0AAAAASKYAc+nSpfYRDXX5TEtLI8AEAAAAgCQTV4BZu3Ztc9ZZZyVubwAAAAAAeRajyAIAAAAAEoJBfgAAAAAACUGACQAAAABICAJMAAAAAEBCEGACAAAAAHJ2kB8AAAAAALyowQQAAAAAJAQBJgAAAAAgIQgwAQAAAAAJQYAJ5HJbtmwxBQoUMGlpaaZ79+45vTtAwuicjuZRs2ZN+75169al+z+YnTt3mieffNKcc845pmLFiqZgwYKmVKlSpkmTJubOO+80X3/9dUT7lC9fPvu+li1bmmHDhpkjR46E/U6TJk0ybdu2NSeccIJ9nHvuueazzz4Luu769etN//797T5WrVrVFClSxJQoUcI0bdrUPPHEE2bfvn1B3zdz5kwzePBg06lTJ1OhQoVMj0Uwhw8fNqeddpp9r9KXUPbv32+GDBliGjRoYIoWLWrKlStnOnToYGbMmBHV9oBkp2tQ11MsDh06ZF544QXTqlUrm94UKlTIVK5c2TRv3tzcfffdIdMQILdikB8gl3v++efNPffcY/9WhvXPP/+0GVEgr+vWrVuG17777juzevVq07hxYxsMepUvX9785z//sQHmySefbGrUqGH/DvTJJ5/Yz/77779twHbmmWfaIFMB28qVK82vv/5q1+vYsWOGjJvLIN500032+dixY3Ybc+bMMcePHzcXXHCB+fzzz4MGZQpA+/bta5ddeOGFpnDhwmbatGnmwIED5uWXXzY9e/ZMt/7kyZPNpZdeaipVqmTq1atnn3ft2mXmzp1rdu/ebYO6WbNmmTJlyqR7n47L0qVL070W6liEMmjQIPPYY48ZjfOXP39+c/To0Qzr7N2715x33nnmhx9+MGXLljWtW7e2+6X90/pvv/02hV6AJ8BUoVG0Y2f+9ddfNl1ZtGiRLQhTkHnSSSfZ62/hwoW2kPnUU081P//8M8caeYdGkQWQezVu3Fh3K1/lypXt85gxY3J6l4Asc9NNN9nz/NFHHw25ztq1a+06NWrUyLBs0qRJvrS0NF+BAgV8zz77rO/gwYMZ1lm5cqXdTp06dTIs0+cGuzXOnTvXV6RIEbvsvffey7D8559/9uXPn99XuHBh35w5c/yvr1q1yleuXDm7P7/++mu692zevNm3bNmyDJ+1e/du3wUXXGC31b9//wzL7733Xt+QIUN8X3zxhW/58uUhj0UoK1as8BUqVMh322232fdqv4Pp2bOnXd6sWTPf1q1b/a/Pnj3bV6JECfsZ69ati3i7QDL77bffbNoSrbvvvtteZ02aNPFt2rQpw/J58+b5Bg8enKC9BLIHASaQi/3000/2xlOtWjXfqFGj7N+dOnXK6d0CcmWAuWfPHl/58uVDBoGBfvjhh4gDTLnjjjvssq5du2ZYduedd9plvXv3zrBs6NChdpkCtkjNmjXLvqdp06Zh19uyZUtUAebx48d9Z599tq9ixYq+nTt3hgwwDx065CtWrJhdroAy0IMPPmiX9enTJ+LvBCCjk046yV5LX375JYcHSYM+mICH69ulflNq1jZgwADb9ExN3U455RTzzDPPpGv+cv/999v1r7766gzHcfv27baZi5qfqdmfo6Z7eo/6MH3xxRe2CVrp0qXta2oq4/Xee+/Z5+uvv97885//NMWKFbPv2bZtG78bEGDUqFH2ulNTzq5du2Z6fJo1axbVMVSTVdm6dWuGZa6p7ZVXXplhmXtN/TMjpaZyor5YifTmm2/a9EhN7wOb3nqpKbH6XyrtU5O9QEq3ZOLEiQndPyAv5gVC9cH0fo6a7Pfr188279f13adPH7uOu5+rPzWQLAgwgRADYFx88cVm+PDhtpO9MlO///67vckMHDjQv97jjz9uB+QYO3aseffdd9N9xr///W/bd+KBBx4wZ599doZtfPDBB3awDPUL03OLFi3S3ZzU3+v999+3fyuzrL5kXbp0sX2fxowZw+8GBJg6dap9vu6667Lk2OzZs8c+qz+nlwqGNmzYYP9WehCoWrVqtv+o+mcpk5kZBXYa5Ec0kE+iKD1SGqb+XpkF4G6AIQ04EmzgEg32I2vXro3oOwHJnBfIjIJUDf6lQjD1ob7sssv8BTxKH+SNN96Iuv8mkGvldBUqkJu4pnd6tG3b1vaFchYsWGCbkqnZmJriefszFS1a1FeyZEnfmjVr7GtvvfWW/YwWLVr4jhw5ErQJYGb9KadPn27XUR9MZ8qUKf7PBZJRPE1kq1SpYl//7rvvYt5+uCay55xzjl02evTodK8vXbrUvl6mTJmQn6v+VVrnxx9/zLBMTVX1vfXo2LGj7bOpdbt06eLbv39/wprIXnHFFbaPqPqFer9vsCayv/zyi12m/qzB9mH8+PH+Y6Wm/ECq5wV0DQamHd7PadWqlW/Xrl0ZtvXUU0/516lXr55vwIABvk8++cS3cePGLP6WQNahBhMIQlMTqCmZRm11VHqpmkbVLmhURad+/fp2ZEvVbtxwww22aZlGklRz1tGjR4ecAkA1E9dcc03I4++ax3prGi666CJbe7JgwQKzatUqfjvAY8eOHfZZtYWBNDqrmqcHPjIbmVEtCTSqraY2+fbbb03nzp0zXLca7VF0zYdSvHjxdLWggbWFagGhx5QpU+z3ULP7t956y04Nkghqyvrxxx/bmpe6detmur6aAWqaBMWgga0zZMSIEf6/g30nINXyApl56aWXbHeYQPfdd599qNms0qOnn37aXH755bZm8x//+Iet2VQ6BOQlBJhAEOproWHBA7mMmZqaed111102YPz+++/tfHnKMGpOq3AZOTWRCdecRplB3dzU/9JRsOqa/7kAFEDmvEGc9/HHH38EXd/Ng6k+1Aq2lMlTs3dNgRJu3shYaA5MBXLKRKqp7TvvvGOD2YYNG9qpC+KlAFBTpCg9UpP9SOi7KxiVe++914wcOdLOLao+Zb1797Z9Tt1xUDoFJKNo8wKhuDktg9H1oz6durZefPFFO95C9erV7bLly5fbwi29RpCJvIS7AhAiwxdMyZIl/ZMiB1KmUPNTqj+SSjdvu+22sMfW3UCCmTBhgs0Unn/++XagIC9Xo6n+mfTXADL2C9RAP8Gu6f8bOd0+2rVrF/bQaR5MPVRbqTkqRf2wgtXmqX+0qEYjsz6NLg0JFdSp1qJ79+7m008/td/j5ptvjvs6f/DBB82mTZvMa6+9ZgcpiZQmeNdDNbTaJx1fDVCiOT2HDBni70MWbrAgINXyAtHe7x3d63v16mXGjRtn+2uvWLHCP8+s8gQffvhhVPsO5KTEFsMCSSKWEnllCA8ePGj/VvNVZcpcxjMYBaOhuNpJfU6wAYKUEVVpp0aDbNOmTdT7CiSjxo0b2wE4Fi9ebM4666y4PkuDcXg999xzthlbjx497EAfqtkIzDyqGa4CSdcc1ksBnnjfF44G/VLNyY8//mgH0qlVq1bM30Wj1yq90aBkegQ6duyYHeVShg0bZgchcemMmvUpk6smtjq2aqKv2pTTTjvNPProo7YJbzz7BuRmiaqdD3e/D0Xdb1RwrXRFLSfUakDdcIC8gAATSIBff/3V3++yffv2tnmrSiK9/ZQipSkQvvzyS/v3xo0b7SNcIEqACfz/1HJAfRg1yrKahCaSmolOnz7dTJs2zQwePDjdta1+VQoy1bxVwW1goZCuYdVGKrj09uXKjOtLqmkM4g3iVPg1c+bMkMvdssCpkkQBpws6HTXhVWCqQD7RTYYB/D9qyaQAM1jLDCC3ooksECdNG6Jmq6q5GDp0qB3YR03q1Gdp/PjxUX+emsHoMzV3nrdJn/ehGg3R9CiRNtEBkp0G7VEzztmzZ9vrMNE0+IYr2FETNi83nYiatwVyr1166aURb0tN7RWsqhZRzVLjodYOodISUT9T97+rycyMmslKZl0BAISXWRP43377zT5XqVKFQ4k8gwATiNNjjz1m5s+fbzOPt99+u20ypsytRoRT5mvz5s1RfZ5rHhtuLj9N6KzJz1XbMHnyZH5D4P/6QqpgR0GZ+i6qWatrth7YXDVcy4BQNMelm4v22WefTbdMA98oUNNgQHPnzk3XukFzWqqWT+t4vf3222bNmjUZtqOmqBrcS/2wFbgGzruZXdSaws3v6ei7q2msgmY1Fb7qqqtyZN+AZNG6dWubbrl+2l66vytNERU6A3kFASYQB40a++STT5oTTzzR9pVwmjVrZgYNGmRHXVStSqSDdGiKk4ULF9pmdB07dgy7LqPJAhmpoEctB9RcXX0mK1SoYC688EIbsGmZmnqqqaoG0DjzzDNNnTp1ojqMuq4VwKqJrHcEWvWXVECrFgVqtq7rV8Go+oVq2hG1btBotF4qiKpdu7Zp0KCB7dd47bXX2ianek39rfS6pioJpMBUo1Xr4WpONZqle02PRIw+q2OkwiylZ8rcutEtVaimYDtYbS2A6Oi+r37OahKv61/3dqUd6oOpNEtpyh133OG/1oG8gI4TQIw0iI+axqofkjKbysh6aYj/qVOn2v6UGjhDfTQjrb3UHFiZDQqgefL0mW7ePDeCJpDqdP20bdvWlvzr+li6dKmt7VfQqQBJmTkFc+rbpGAxGgoY9fnqZ62g0VuTqetRQaQCzVmzZtnXNDWBAt1LLrkkaL9OBZOq8fzmm29sjWWpUqVsgKhgTi0ggo36qhrYefPmpXvt8OHD6V5TE9t4ad80kq6aHCst04AnCqTvuece28e1UKFCcW8DSHXqz/z555+br776ys65u2TJEpuvUMG1CnaUXql/OZCXpPmY5wAAAAAAkAA0kQUAAAAAJAQBJgAAAAAgIQgwAQAAAAAJQYAJAAAAAEgIAkwAAAAAQEIQYAIAAAAAEoIAEwAAAACQEASYAAAAAICEIMAEAAAAACQEASYAAAAAICEIMAEAAAAACUGACQBIamlpaWEf5557rsktatasafcpkF7TMgAAcrsCOb0DAABkh5tuuino6/Xq1eMHAAAgQdJ8Pp8vUR8GAEBu42oE88LtbvXq1ebIkSMZgl59hxo1aph169bl2L4BABAJajABAMglateundO7AABAXOiDCQCAMWbWrFmmZ8+eplGjRqZMmTKmaNGitiZxwIAB5q+//spwjGbMmGFrFrt162a2bt1qbrnlFlOpUiVTvHhxc/bZZ5s5c+b4133jjTfs5+ozq1WrZgYNGmSOHz8ecR/MQOPGjbPrXX/99SHXue222+w6I0eO5PcFAGQbmsgCAJJapE1kW7ZsaZYuXWoDQQWBBw8eNIsWLTJbtmwxDRo0MHPnzjUlSpRIF2Ced9555rLLLjPLli0zx44ds5+hZqzz5s0zxYoVM/PnzzdvvfWWGT58uF03X758ZubMmWbPnj3mwQcfNE888USGAHP9+vUZ9jWwiaya0VavXt3s2rXL/P7776ZcuXLp1t+7d6+pXLmy3Z72X/sCAEB2oAYTAABjzKOPPmr++OMPGxyqhnDy5Mlm7dq1tiZw+fLlZujQoUGP06effmpat25tfv31VzNmzBgbiOqz9u/fb66++mr7WT/99JP57LPPzKRJk+zyQoUKmWHDhtlAMBYFCxY03bt3N4cOHTLvvfdehuXaD332DTfcQHAJAMhWBJgAgJQQapoSVyvYoUMHU6pUqXTvKVy4sA0ECxQoYCZOnBj0c0844QTz0ksv2aDP6du3r/3sFStWmMceeyxd38rTTjvNdOrUyQagP/zwQ8zfR4GvaihVOxro7bffts///ve/Y/58AABiwSA/AICUnqbE2+xVzU1Vy/jzzz+bv//+299PUjWOqqEMpnnz5rbPppcC1bJly5odO3aYiy++OMN7atWqZZ/VfDVWajLbvn17M2XKFNvfU7WootpS1cJqv5o2bRrz5wMAEAsCTABAShg1alTY5WoCqwF91L8xGlWqVAkZuCrADLbcBbVq4hqPO+64wwaYqsV0Aaar0aT2EgCQE2giCwBIeeoX2b9/f9tfUYGoms1qkB8NtqOHBswJeSPNF/5WmtnyeHTs2NEOSPS///3P1rhqn0ePHm0D2Ouuuy7LtgsAQCgEmACAlPfJJ5/YY6BRXdWUVs1P1f9SDhw4YAf/yY3y589vayrVn/P9998348ePtyPLXnvttaZkyZI5vXsAgBREgAkASHkKyqRq1aoZjsXYsWMzneIkJ9166612ECI1jaV5LAAgpxFgAgBSXt26de0xeOedd9L1wdQosPfff3+uPj5qvqu5OBcvXmzn2NQ8nmeccUZO7xYAIEURYAIAUt7NN99sKlWqZEeQPfXUU80111xjLrroItOkSRPTpk0b22Q2N9NgP97pSwAAyCkEmACAlFeuXDmzYMECc/3115vDhw+bTz/91E5Z8vjjj5sPP/ww1x8fBcGah7No0aLmhhtuyOndAQCksDRfbu5YAgAAMqUgWMGxBijKbDoWAACyEgEmAAB5mPqMtmjRwixdutTMnz/f/g0AQE4pkGNbBgAAMVMz3gkTJtigcvny5aZLly4ElwCAHEcfTAAA8qBFixaZkSNHms2bN9vmsRoBFwCAnEYTWQAAAABAQlCDCQAAAABICAJMAAAAAEBCEGACAAAAABKCABMAAAAAkBAEmAAAAACAhCDABAAAAAAkBAEmAAAAACAhCDABAAAAAAlBgAkAAAAASAgCTAAAAABAQhBgAgAAAAASggATAAAAAJAQBJgAAAAAAJMI/x/3QKJ+KHxs+gAAAABJRU5ErkJggg==",
"text/plain": [
"
"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"for fam in families:\n",
" example_score_output = pd.read_csv(\n",
" os.path.join(OUT_DIR, \"scoring\", \"sequences\", f\"{fam}.csv.gz\")\n",
" )[[\"filename\", \"sequence_id\", \"label\", f\"{fam}_score\"]]\n",
"\n",
" labels = example_score_output[\"label\"].unique()\n",
" palette = dict(zip(labels, sns.color_palette(\"tab10\", len(labels))))\n",
"\n",
" plt.figure(figsize=(6, 2), dpi=150)\n",
" ax = sns.boxplot(\n",
" x=\"label\",\n",
" y=f\"{fam}_score\",\n",
" data=example_score_output,\n",
" hue=\"label\",\n",
" dodge=False,\n",
" palette=palette,\n",
" legend=False\n",
" )\n",
"\n",
" ax.set_title(f\"Distribution of {fam} Scores for Sequences in Different Families\")\n",
" ax.set_xlabel(\"Family\")\n",
" ax.set_ylabel(f\"{fam} Score\")\n",
" plt.tight_layout()\n"
]
},
{
"cell_type": "markdown",
"id": "fdc98b0f",
"metadata": {},
"source": [
"We can assess how well the scores perform using the weights determined for each family. Note that it is immediately obvious that each of the family scoring methods performs well in identifying in-family sequences versus out-of-family sequences.\n",
"\n",
"Not all family scoring methods perform equally well in terms of differentation between sequences belonging to different families. Differing scorer performances can be attributed to a variety of factors, e.g. parameters such as the alphabet and k, existing levels of similarity between sequences in different families, etc. The specificity of a given family kmer probability scorer is also impacted by (a) the selected family sequence set, and (b) the sequence set of the out-of-family kmers. In other words, as in other machine learning problems, the curation of the training set will strongly impact the resulting model.\n",
"\n",
"The probabilities and scores assigned to each feature in the kmer set is also computed and output into a dataframe. The contents of one of these dataframes is as follows:"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "0178e92c",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"example family:\t nirS\n"
]
},
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
kmer
\n",
"
sample
\n",
"
background
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
CPPPAPCA
\n",
"
0.267661
\n",
"
NaN
\n",
"
\n",
"
\n",
"
1
\n",
"
PPPAPCAP
\n",
"
-0.021455
\n",
"
NaN
\n",
"
\n",
"
\n",
"
2
\n",
"
PPAPCAPP
\n",
"
-0.010466
\n",
"
NaN
\n",
"
\n",
"
\n",
"
3
\n",
"
PAPCAPPA
\n",
"
0.002355
\n",
"
NaN
\n",
"
\n",
"
\n",
"
4
\n",
"
APCAPPAC
\n",
"
0.020408
\n",
"
NaN
\n",
"
\n",
"
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
\n",
"
\n",
"
4115
\n",
"
PACACCAC
\n",
"
0.020408
\n",
"
NaN
\n",
"
\n",
"
\n",
"
4116
\n",
"
ACACCACP
\n",
"
0.020408
\n",
"
NaN
\n",
"
\n",
"
\n",
"
4117
\n",
"
CACCACPP
\n",
"
0.020408
\n",
"
NaN
\n",
"
\n",
"
\n",
"
4118
\n",
"
ACCACPPC
\n",
"
0.007588
\n",
"
NaN
\n",
"
\n",
"
\n",
"
4119
\n",
"
PACPPCCP
\n",
"
-0.479592
\n",
"
NaN
\n",
"
\n",
" \n",
"
\n",
"
4120 rows × 3 columns
\n",
"
"
],
"text/plain": [
" kmer sample background\n",
"0 CPPPAPCA 0.267661 NaN\n",
"1 PPPAPCAP -0.021455 NaN\n",
"2 PPAPCAPP -0.010466 NaN\n",
"3 PAPCAPPA 0.002355 NaN\n",
"4 APCAPPAC 0.020408 NaN\n",
"... ... ... ...\n",
"4115 PACACCAC 0.020408 NaN\n",
"4116 ACACCACP 0.020408 NaN\n",
"4117 CACCACPP 0.020408 NaN\n",
"4118 ACCACPPC 0.007588 NaN\n",
"4119 PACPPCCP -0.479592 NaN\n",
"\n",
"[4120 rows x 3 columns]"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"print(\"example family:\\t\", example_family)\n",
"pd.read_csv(os.path.join(OUT_DIR, \"scoring\", \"weights\", f\"{example_family}.csv.gz\"))"
]
},
{
"cell_type": "markdown",
"id": "8cffa038-14c8-4ce0-9c5d-90f29649d0f2",
"metadata": {},
"source": [
"In this view, the relative weight of a given AAR-kmer to a given family assignment is summarized. Each column displays the following information:\n",
"\n",
"| **Column Name** | **Description** |\n",
"|-----------------|--------------------------------------------------------------------------------------------------------------------------------|\n",
"| kmer | Amino acid reduced (AAR) kmer |\n",
"| sample | Weight of the AAR-kmer toward family assignment based on prevalence in sample sequences |\n",
"| background | Weight of the AAR-kmer toward family assignment based on prevalence in sample sequences; `np.nan` if no background sequences are given |\n",
"\n",
"Note that this example does not include any sequences specified as background sequences, and thus the `background` column does not contribute additional weights in scoring.\n",
"\n",
"The model objects can be loaded (via `snekmer.io.load_pickle`) and then applied elsewhere, e.g. to a new set of unknown sequences."
]
},
{
"cell_type": "markdown",
"id": "82772d09",
"metadata": {},
"source": [
"## Snekmer Search Mode\n",
"\n",
"Say a user trains the four models above, and would then like to score and evaluate sequences with unknown family assignments. The user can use `snekmer search`, which uses the kmer basis set for the desired family to create kmer vectors for unknown sequences, then apply the family scorer to the vectorized unknown sequences, and finally use the model to predict family assignments for the unknown sequences.\n",
"\n",
"The results from `snekmer search` on the demo files are shown below:"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "5d6e4d18",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"example family:\t nirS\n"
]
},
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
filename
\n",
"
sequence_id
\n",
"
sequence_length
\n",
"
score
\n",
"
in_family
\n",
"
probability
\n",
"
model
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
nirS.faa
\n",
"
WP_011748767.1
\n",
"
596
\n",
"
0.806921
\n",
"
True
\n",
"
0.847682
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
1
\n",
"
nirS.faa
\n",
"
NP_249210.1
\n",
"
568
\n",
"
0.903336
\n",
"
True
\n",
"
0.898777
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
2
\n",
"
nirS.faa
\n",
"
WP_014339158.1
\n",
"
559
\n",
"
0.843952
\n",
"
True
\n",
"
0.869435
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
3
\n",
"
nirS.faa
\n",
"
WP_043221900.1
\n",
"
570
\n",
"
0.922663
\n",
"
True
\n",
"
0.906984
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
4
\n",
"
nirS.faa
\n",
"
WP_041771853.1
\n",
"
570
\n",
"
0.878081
\n",
"
True
\n",
"
0.887088
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
5
\n",
"
nirS.faa
\n",
"
WP_013953868.1
\n",
"
554
\n",
"
0.872977
\n",
"
True
\n",
"
0.884587
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
6
\n",
"
nirS.faa
\n",
"
WP_085944417.1
\n",
"
529
\n",
"
0.873901
\n",
"
True
\n",
"
0.885044
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
7
\n",
"
nirS.faa
\n",
"
WP_011517656.1
\n",
"
549
\n",
"
0.897850
\n",
"
True
\n",
"
0.896333
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
8
\n",
"
nirS.faa
\n",
"
WP_041100219.1
\n",
"
579
\n",
"
0.887953
\n",
"
True
\n",
"
0.891791
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
9
\n",
"
nirS.faa
\n",
"
WP_011310590.1
\n",
"
575
\n",
"
0.942577
\n",
"
True
\n",
"
0.914811
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
10
\n",
"
nirS.faa
\n",
"
WP_014422487.1
\n",
"
574
\n",
"
0.872136
\n",
"
True
\n",
"
0.884171
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
11
\n",
"
nirS.faa
\n",
"
WP_085938646.1
\n",
"
559
\n",
"
0.913921
\n",
"
True
\n",
"
0.903348
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
12
\n",
"
nirS.faa
\n",
"
WP_071946734.1
\n",
"
575
\n",
"
0.932024
\n",
"
True
\n",
"
0.910740
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
13
\n",
"
nirS.faa
\n",
"
WP_046857961.1
\n",
"
579
\n",
"
0.970848
\n",
"
True
\n",
"
0.924897
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
14
\n",
"
nirS.faa
\n",
"
WP_013651333.1
\n",
"
585
\n",
"
0.867557
\n",
"
True
\n",
"
0.881879
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
15
\n",
"
nirS.faa
\n",
"
WP_013029265.1
\n",
"
577
\n",
"
0.921728
\n",
"
True
\n",
"
0.906601
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
16
\n",
"
nirS.faa
\n",
"
WP_045480144.1
\n",
"
577
\n",
"
0.893515
\n",
"
True
\n",
"
0.894365
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
17
\n",
"
nirS.faa
\n",
"
WP_014237143.1
\n",
"
576
\n",
"
0.962037
\n",
"
True
\n",
"
0.921877
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
18
\n",
"
nirS.faa
\n",
"
WP_011386514.1
\n",
"
568
\n",
"
0.889133
\n",
"
True
\n",
"
0.892342
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
19
\n",
"
nirS.faa
\n",
"
WP_009205117.1
\n",
"
576
\n",
"
0.946725
\n",
"
True
\n",
"
0.916364
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
20
\n",
"
nirS.faa
\n",
"
WP_031269533.1
\n",
"
584
\n",
"
0.907522
\n",
"
True
\n",
"
0.900607
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
21
\n",
"
nirS.faa
\n",
"
WP_044029534.1
\n",
"
581
\n",
"
0.805285
\n",
"
True
\n",
"
0.846656
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
22
\n",
"
nirS.faa
\n",
"
WP_007089813.1
\n",
"
575
\n",
"
0.893495
\n",
"
True
\n",
"
0.894356
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
23
\n",
"
nirS.faa
\n",
"
WP_012179840.1
\n",
"
583
\n",
"
0.805569
\n",
"
True
\n",
"
0.846835
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
24
\n",
"
nirS.faa
\n",
"
WP_011289048.1
\n",
"
576
\n",
"
0.976724
\n",
"
True
\n",
"
0.926851
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
25
\n",
"
nirS.faa
\n",
"
WP_048708996.1
\n",
"
575
\n",
"
0.920702
\n",
"
True
\n",
"
0.906179
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
26
\n",
"
nirS.faa
\n",
"
WP_011805163.1
\n",
"
574
\n",
"
0.921624
\n",
"
True
\n",
"
0.906558
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
27
\n",
"
nirS.faa
\n",
"
WP_012250943.1
\n",
"
560
\n",
"
0.698289
\n",
"
True
\n",
"
0.766772
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
28
\n",
"
nirS.faa
\n",
"
WP_013518994.1
\n",
"
574
\n",
"
0.880298
\n",
"
True
\n",
"
0.888160
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
29
\n",
"
nirS.faa
\n",
"
WP_083536735.1
\n",
"
693
\n",
"
0.860222
\n",
"
True
\n",
"
0.878126
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
30
\n",
"
nirS.faa
\n",
"
WP_014426879.1
\n",
"
582
\n",
"
0.858500
\n",
"
True
\n",
"
0.877231
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
31
\n",
"
nirS.faa
\n",
"
WP_042340392.1
\n",
"
593
\n",
"
0.866062
\n",
"
True
\n",
"
0.881122
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
32
\n",
"
nirS.faa
\n",
"
WP_075148778.1
\n",
"
560
\n",
"
0.730918
\n",
"
True
\n",
"
0.793848
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
33
\n",
"
nirS.faa
\n",
"
WP_004255893.1
\n",
"
560
\n",
"
0.724783
\n",
"
True
\n",
"
0.788940
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
34
\n",
"
nirS.faa
\n",
"
WP_013963004.1
\n",
"
580
\n",
"
0.807332
\n",
"
True
\n",
"
0.847940
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
35
\n",
"
nirS.faa
\n",
"
WP_044032999.1
\n",
"
580
\n",
"
0.807332
\n",
"
True
\n",
"
0.847940
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
36
\n",
"
nirS.faa
\n",
"
WP_076002121.1
\n",
"
578
\n",
"
0.877717
\n",
"
True
\n",
"
0.886911
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
37
\n",
"
nirS.faa
\n",
"
WP_012346472.1
\n",
"
573
\n",
"
0.802448
\n",
"
True
\n",
"
0.844863
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
38
\n",
"
nirS.faa
\n",
"
WP_009206840.1
\n",
"
540
\n",
"
0.838056
\n",
"
True
\n",
"
0.866157
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
39
\n",
"
nirS.faa
\n",
"
WP_059399790.1
\n",
"
546
\n",
"
0.832846
\n",
"
True
\n",
"
0.863203
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
40
\n",
"
nirS.faa
\n",
"
WP_082990281.1
\n",
"
663
\n",
"
0.737690
\n",
"
True
\n",
"
0.799166
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
41
\n",
"
nirS.faa
\n",
"
WP_015781103.1
\n",
"
687
\n",
"
0.802908
\n",
"
True
\n",
"
0.845155
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
42
\n",
"
nirS.faa
\n",
"
WP_024079644.1
\n",
"
540
\n",
"
0.786725
\n",
"
True
\n",
"
0.834613
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
43
\n",
"
nirS.faa
\n",
"
WP_011289000.1
\n",
"
561
\n",
"
0.761704
\n",
"
True
\n",
"
0.817193
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
44
\n",
"
nirS.faa
\n",
"
WP_011383805.1
\n",
"
540
\n",
"
0.852271
\n",
"
True
\n",
"
0.873942
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
45
\n",
"
nirS.faa
\n",
"
WP_049724801.1
\n",
"
708
\n",
"
0.725143
\n",
"
True
\n",
"
0.789231
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
46
\n",
"
nirS.faa
\n",
"
WP_041099757.1
\n",
"
558
\n",
"
0.740383
\n",
"
True
\n",
"
0.801252
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
47
\n",
"
nirS.faa
\n",
"
WP_015258444.1
\n",
"
707
\n",
"
0.712667
\n",
"
True
\n",
"
0.778999
\n",
"
nirS.model
\n",
"
\n",
"
\n",
"
48
\n",
"
nirS.faa
\n",
"
WP_014238329.1
\n",
"
546
\n",
"
0.718369
\n",
"
True
\n",
"
0.783719
\n",
"
nirS.model
\n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" filename sequence_id sequence_length score in_family \\\n",
"0 nirS.faa WP_011748767.1 596 0.806921 True \n",
"1 nirS.faa NP_249210.1 568 0.903336 True \n",
"2 nirS.faa WP_014339158.1 559 0.843952 True \n",
"3 nirS.faa WP_043221900.1 570 0.922663 True \n",
"4 nirS.faa WP_041771853.1 570 0.878081 True \n",
"5 nirS.faa WP_013953868.1 554 0.872977 True \n",
"6 nirS.faa WP_085944417.1 529 0.873901 True \n",
"7 nirS.faa WP_011517656.1 549 0.897850 True \n",
"8 nirS.faa WP_041100219.1 579 0.887953 True \n",
"9 nirS.faa WP_011310590.1 575 0.942577 True \n",
"10 nirS.faa WP_014422487.1 574 0.872136 True \n",
"11 nirS.faa WP_085938646.1 559 0.913921 True \n",
"12 nirS.faa WP_071946734.1 575 0.932024 True \n",
"13 nirS.faa WP_046857961.1 579 0.970848 True \n",
"14 nirS.faa WP_013651333.1 585 0.867557 True \n",
"15 nirS.faa WP_013029265.1 577 0.921728 True \n",
"16 nirS.faa WP_045480144.1 577 0.893515 True \n",
"17 nirS.faa WP_014237143.1 576 0.962037 True \n",
"18 nirS.faa WP_011386514.1 568 0.889133 True \n",
"19 nirS.faa WP_009205117.1 576 0.946725 True \n",
"20 nirS.faa WP_031269533.1 584 0.907522 True \n",
"21 nirS.faa WP_044029534.1 581 0.805285 True \n",
"22 nirS.faa WP_007089813.1 575 0.893495 True \n",
"23 nirS.faa WP_012179840.1 583 0.805569 True \n",
"24 nirS.faa WP_011289048.1 576 0.976724 True \n",
"25 nirS.faa WP_048708996.1 575 0.920702 True \n",
"26 nirS.faa WP_011805163.1 574 0.921624 True \n",
"27 nirS.faa WP_012250943.1 560 0.698289 True \n",
"28 nirS.faa WP_013518994.1 574 0.880298 True \n",
"29 nirS.faa WP_083536735.1 693 0.860222 True \n",
"30 nirS.faa WP_014426879.1 582 0.858500 True \n",
"31 nirS.faa WP_042340392.1 593 0.866062 True \n",
"32 nirS.faa WP_075148778.1 560 0.730918 True \n",
"33 nirS.faa WP_004255893.1 560 0.724783 True \n",
"34 nirS.faa WP_013963004.1 580 0.807332 True \n",
"35 nirS.faa WP_044032999.1 580 0.807332 True \n",
"36 nirS.faa WP_076002121.1 578 0.877717 True \n",
"37 nirS.faa WP_012346472.1 573 0.802448 True \n",
"38 nirS.faa WP_009206840.1 540 0.838056 True \n",
"39 nirS.faa WP_059399790.1 546 0.832846 True \n",
"40 nirS.faa WP_082990281.1 663 0.737690 True \n",
"41 nirS.faa WP_015781103.1 687 0.802908 True \n",
"42 nirS.faa WP_024079644.1 540 0.786725 True \n",
"43 nirS.faa WP_011289000.1 561 0.761704 True \n",
"44 nirS.faa WP_011383805.1 540 0.852271 True \n",
"45 nirS.faa WP_049724801.1 708 0.725143 True \n",
"46 nirS.faa WP_041099757.1 558 0.740383 True \n",
"47 nirS.faa WP_015258444.1 707 0.712667 True \n",
"48 nirS.faa WP_014238329.1 546 0.718369 True \n",
"\n",
" probability model \n",
"0 0.847682 nirS.model \n",
"1 0.898777 nirS.model \n",
"2 0.869435 nirS.model \n",
"3 0.906984 nirS.model \n",
"4 0.887088 nirS.model \n",
"5 0.884587 nirS.model \n",
"6 0.885044 nirS.model \n",
"7 0.896333 nirS.model \n",
"8 0.891791 nirS.model \n",
"9 0.914811 nirS.model \n",
"10 0.884171 nirS.model \n",
"11 0.903348 nirS.model \n",
"12 0.910740 nirS.model \n",
"13 0.924897 nirS.model \n",
"14 0.881879 nirS.model \n",
"15 0.906601 nirS.model \n",
"16 0.894365 nirS.model \n",
"17 0.921877 nirS.model \n",
"18 0.892342 nirS.model \n",
"19 0.916364 nirS.model \n",
"20 0.900607 nirS.model \n",
"21 0.846656 nirS.model \n",
"22 0.894356 nirS.model \n",
"23 0.846835 nirS.model \n",
"24 0.926851 nirS.model \n",
"25 0.906179 nirS.model \n",
"26 0.906558 nirS.model \n",
"27 0.766772 nirS.model \n",
"28 0.888160 nirS.model \n",
"29 0.878126 nirS.model \n",
"30 0.877231 nirS.model \n",
"31 0.881122 nirS.model \n",
"32 0.793848 nirS.model \n",
"33 0.788940 nirS.model \n",
"34 0.847940 nirS.model \n",
"35 0.847940 nirS.model \n",
"36 0.886911 nirS.model \n",
"37 0.844863 nirS.model \n",
"38 0.866157 nirS.model \n",
"39 0.863203 nirS.model \n",
"40 0.799166 nirS.model \n",
"41 0.845155 nirS.model \n",
"42 0.834613 nirS.model \n",
"43 0.817193 nirS.model \n",
"44 0.873942 nirS.model \n",
"45 0.789231 nirS.model \n",
"46 0.801252 nirS.model \n",
"47 0.778999 nirS.model \n",
"48 0.783719 nirS.model "
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"print(\"example family:\\t\", example_family)\n",
"pd.read_csv(os.path.join(OUT_DIR, \"search\", example_family, f\"{example_family}.csv\"))"
]
},
{
"cell_type": "markdown",
"id": "3cf5c845",
"metadata": {},
"source": [
"Each column summarizes the following information for a given sequence:\n",
"\n",
"| **Column Name** | **Description** |\n",
"|-----------------|--------------------------------------------------------------------------------------------------------------------------------|\n",
"| filename | Name of file containing given sequence |\n",
"| sequence_id | Sequence ID, as taken from FASTA file |\n",
"| sequence_length | Length of sequence (i.e. number of characters long the sequence is) |\n",
"| score | Score for the assignment of the sequence into the desired family based on the family model. Scores are summed from kmer contributions using the family scoring model |\n",
"| in_family | True if in-family assignment is predicted (probability > 0.5); False otherwise. |\n",
"| probability | Probability of in-family assignment. 1.0 = maximum probability for a given sequence's assignment into a family; 0.0 = lowest probability; 0.5 = equal probability of in-family vs. out-of-family assignment |\n",
"| model | Name of model used to evaluate the sequence |\n",
"\n",
"In this example application, the **in_family** and **probability** columns are of particular importance to the user. The **in_family** column tells the user whether a particular input sequence is given an in-family assignment based on the machine learning model which has been previously trained, and the **probability** informs the user of the in-family assignment probability determined by the same model.\n",
"\n",
"In the case of the demo files, since all of the sequences above belong to the given family, and by design of the demo were also the families used to train the family model, the sequences all have relatively high probabilities and consistently do get assigned to the protein family. However, in this demonstration, we hope it is apparent to the user how trained protein family models can be applied to a new sequence set and the resulting `snekmer search` results evaluated."
]
},
{
"cell_type": "markdown",
"id": "59fec5be-7e46-40ba-8371-bd07019d3a51",
"metadata": {},
"source": [
"## Conclusion\n",
"\n",
"In conclusion, we have demonstrated Snekmer's utility across 3 potential operating models (cluster, model, and search). We hope this tutorial provides useful information to users regarding applying Snekmer to their own sequence sets and interpreting results from Snekmer."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "snekmer_env7_311",
"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.11.14"
}
},
"nbformat": 4,
"nbformat_minor": 5
}