AI/test_pipeline.ipynb
2022-08-28 11:16:54 +03:00

593 lines
41 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "code",
"execution_count": 6,
"id": "a371550d-cbd7-4435-a41b-3fb35cccaa74",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Archive: test_dataset/Тестовый датасет (2).zip\n",
" inflating: test_dataset/2.docx \n",
" inflating: test_dataset/3.docx \n",
" inflating: test_dataset/4.docx \n",
" inflating: test_dataset/5.docx \n",
" inflating: test_dataset/6.docx \n",
" inflating: test_dataset/7.docx \n",
" inflating: test_dataset/8.docx \n",
" inflating: test_dataset/9.docx \n",
" inflating: test_dataset/10.docx \n",
" inflating: test_dataset/Названиеоманды.csv \n",
" inflating: test_dataset/Пояснения к валидации.docx \n",
" inflating: test_dataset/1.docx \n"
]
}
],
"source": [
"!unzip test_dataset/Тестовый\\ датасет\\ \\(2\\).zip -d test_dataset/"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "969b75f5-a211-44d2-b704-c3c4c90f4401",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/ubuntu/venv/lib/python3.8/site-packages/tqdm/auto.py:22: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
" from .autonotebook import tqdm as notebook_tqdm\n"
]
}
],
"source": [
"import torch\n",
"import numpy as np\n",
"from transformers import AutoTokenizer, AutoModel\n",
"from tqdm import tqdm\n",
"tqdm.pandas()\n",
"\n",
"import matplotlib.pyplot as plt\n",
"import seaborn as sns\n",
"sns.set()\n",
"import numpy as np\n",
"\n",
"import pandas as pd\n",
"import docx\n",
"import os\n",
"import re\n",
"\n",
"device = 'cuda'"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "358aad5c-210b-450f-a273-8b759ed88b9c",
"metadata": {},
"outputs": [],
"source": [
"#word preprocessing functions\n",
"\n",
"import nltk\n",
"from nltk.tokenize import word_tokenize\n",
"\n",
"from nltk.corpus import stopwords\n",
"from nltk.stem import SnowballStemmer\n",
"from nltk.tokenize import word_tokenize\n",
"\n",
"russian_stopwords = stopwords.words(\"russian\")\n",
"\n",
"russian_stopwords.append('российской')\n",
"russian_stopwords.append('федерации')\n",
"russian_stopwords.append('федерального')\n",
"russian_stopwords.append('настоящих')\n",
"russian_stopwords.append('соответствии')\n",
"russian_stopwords.append('также')\n",
"russian_stopwords.append('рф')\n",
"russian_stopwords.append('ред')\n",
"\n",
"russian_stopwords.append('субсидии')\n",
"russian_stopwords.append('предоставления')\n",
"\n",
"\n",
"def lowercase(text):\n",
" return str(text).lower()\n",
"\n",
"def clean_symb(text):\n",
" return re.sub(r'[^\\w]', ' ', text)\n",
"\n",
"def clear_token(text):\n",
" return word_tokenize(text)\n",
"\n",
"def clean_stopwords(token):\n",
" return ' '.join([i for i in token.split(' ') if i not in russian_stopwords])\n",
"\n",
"def clean_stem(token):\n",
" return [st.stem(i) for i in token]\n",
"\n",
"### combo 3 prev\n",
"def make_clean(s):\n",
" return ' '.join(clean_stem(clean_stopwords(clear_token(s))))"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "4d884c5c-cb0f-44ef-8127-175497c7da47",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"11"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#find all docs\n",
"\n",
"data_path = './test_dataset/'\n",
"documents = os.listdir(data_path)\n",
"documents = [data_path+d for d in documents]\n",
"len(documents)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "e009af9e-97bf-4e9f-928b-c6bd50424b4b",
"metadata": {},
"outputs": [],
"source": [
"#load and parse doc functions\n",
"\n",
"from nltk.corpus import stopwords\n",
"from nltk.stem import SnowballStemmer\n",
"from nltk.tokenize import word_tokenize\n",
"\n",
"\n",
"def get_text(filename):\n",
" doc = docx.Document(filename)\n",
" fullText = ''\n",
" for para in doc.paragraphs:\n",
" for run in para.runs:\n",
" fullText+=run.text\n",
" fullText+='\\n'\n",
" return fullText\n",
"\n",
"def split_text(text):\n",
" texts, groups = [],[]\n",
" regt = re.findall(r\"{(.*?)}(.*?){(.*?)}\",text.replace('\\n',''))\n",
" for t in regt:\n",
" if t[0]==t[-1]:\n",
" texts.append(t[1])\n",
" groups.append(int(t[0]))\n",
" else:\n",
" print(t)\n",
" \n",
" return texts, groups"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "c1ee24fe-988f-4d9e-97e6-522bf2e41798",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"('66', '18. ', '67')\n",
"('67', '', '68')\n",
"('68', '', '69')\n",
"('69', '', '70')\n",
"('Q = (К1 x ГС1) + (К2 x ГС1),где:{42', 'К1 - кандидаты на назначение государственных стипендий, являющиеся молодыми (до 35 лет включительно) творческими деятелями в области культуры и искусства;', '42')\n"
]
}
],
"source": [
"#load data\n",
"\n",
"all_text, all_groups, doc_paths, doc_names = [],[],[],[]\n",
"for d in documents:\n",
" if 'ipynb' not in d:\n",
" text = get_text(d)\n",
" texts,groups = split_text(text)\n",
" all_text.extend(texts)\n",
" all_groups.extend(groups)\n",
" doc_paths.extend([d for a in range(len(texts))])\n",
" doc_names.extend([d.split('/')[-1] for a in range(len(texts))])"
]
},
{
"cell_type": "code",
"execution_count": 41,
"id": "f3d481a5-b3e4-4367-bfa9-c41c43c05a7b",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(846, 7)"
]
},
"execution_count": 41,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#load documents\n",
"#apply preprocessing to documents\n",
"\n",
"df = pd.DataFrame([doc_paths, doc_names,all_text, all_groups]).T\n",
"df.columns = ['path','doc','text','id']\n",
"df['r_text']='r'\n",
"df['r_text'] = df.text.apply(lowercase)\n",
"df['r_text'] = df.r_text.apply(clean_symb)\n",
"df['r_text'] = df.r_text.apply(lambda x:''.join([a for a in x if not a.isdigit()]))\n",
"df['r_text'] = df.r_text.apply(lambda x:' '.join([a for a in x.split(' ') if len(a)>1]))\n",
"df['r_text'] = df.r_text.apply(clean_stopwords)\n",
"df['text_size'] = df['text'].apply(lambda x: len(x.strip()))\n",
"df['is_text'] = df.r_text.apply(lambda x:x.strip().isdigit())\n",
"df = df[~df.is_text]\n",
"df = df[df['text_size']>5]\n",
"df = df.reset_index(drop=True)\n",
"df.shape"
]
},
{
"cell_type": "code",
"execution_count": 42,
"id": "2e3997a7-7e66-4077-8827-007b64f663f5",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"правил 175\n",
"организации 155\n",
"предоставлении 123\n",
"соглашения 115\n",
"конкурса 90\n",
"министерством 85\n",
"средств 82\n",
"финансового 79\n",
"числе 76\n",
"заявок 74\n",
"dtype: int64"
]
},
"execution_count": 42,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#show most popular words in datset\n",
"\n",
"all_words = np.hstack([np.array(a) for a in df.r_text.apply(lambda x:[a for a in x.split(' ') if len(a)>0]).values])\n",
"pd.Series(all_words).value_counts()[:10]"
]
},
{
"cell_type": "code",
"execution_count": 43,
"id": "a3b50eb7-e8b4-4503-92dd-9f0c50b7c2e9",
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import torch\n",
"from transformers import BertTokenizer, BertForSequenceClassification\n",
"from torch.utils.data import Dataset, DataLoader\n",
"from transformers import AdamW, get_linear_schedule_with_warmup\n",
"\n",
"from bert_dataset import CustomDataset"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "b227db93-5193-4851-95dc-1b89277e3c2d",
"metadata": {},
"outputs": [],
"source": [
"#load model\n",
"model = torch.load('bert_opossum_best_0.6753.pt')\n",
"model.to(device)\n",
"pass\n",
"\n",
"#load tokenizer\n",
"tokenizer = BertTokenizer.from_pretrained('sberbank-ai/ruBert-base')"
]
},
{
"cell_type": "code",
"execution_count": 44,
"id": "e1a0c200-ec37-4058-96d1-b625f839e922",
"metadata": {},
"outputs": [],
"source": [
"#predict function\n",
"def predict(text):\n",
" encoding = tokenizer.encode_plus(\n",
" text,\n",
" add_special_tokens=True,\n",
" max_length=512,\n",
" return_token_type_ids=False,\n",
" truncation=True,\n",
" padding='max_length',\n",
" return_attention_mask=True,\n",
" return_tensors='pt',\n",
" )\n",
"\n",
" out = {\n",
" 'text': text,\n",
" 'input_ids': encoding['input_ids'].flatten(),\n",
" 'attention_mask': encoding['attention_mask'].flatten()\n",
" }\n",
" \n",
" input_ids = out[\"input_ids\"].to(device)\n",
" attention_mask = out[\"attention_mask\"].to(device)\n",
"\n",
" outputs = model(\n",
" input_ids=input_ids.unsqueeze(0),\n",
" attention_mask=attention_mask.unsqueeze(0)\n",
" )\n",
"\n",
" prediction = torch.argmax(outputs.logits, dim=1).cpu().numpy()[0]\n",
" return prediction"
]
},
{
"cell_type": "code",
"execution_count": 49,
"id": "b4095596-35ac-44e0-b6bb-dfc10bd712db",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"100%|█████████████████████████████████████████| 846/846 [00:29<00:00, 28.49it/s]\n"
]
}
],
"source": [
"#apply predict funtcion to text\n",
"df['class'] = df.r_text.progress_apply(predict)"
]
},
{
"cell_type": "code",
"execution_count": 50,
"id": "0392b3c9-7e93-47cf-8729-98be9dbb9285",
"metadata": {},
"outputs": [],
"source": [
"#get file_id\n",
"df['file_id'] = df.doc.apply(lambda x:int(x.split('.')[0]))"
]
},
{
"cell_type": "code",
"execution_count": 80,
"id": "3a8c8d64-4f5e-466b-a48f-79a18cf7de09",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>file_id</th>\n",
" <th>id</th>\n",
" <th>class</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>2</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>1</td>\n",
" <td>2</td>\n",
" <td>2</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>1</td>\n",
" <td>3</td>\n",
" <td>2</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>1</td>\n",
" <td>4</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>1</td>\n",
" <td>5</td>\n",
" <td>7</td>\n",
" </tr>\n",
" <tr>\n",
" <th>...</th>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>847</th>\n",
" <td>10</td>\n",
" <td>67</td>\n",
" <td>38</td>\n",
" </tr>\n",
" <tr>\n",
" <th>848</th>\n",
" <td>10</td>\n",
" <td>68</td>\n",
" <td>38</td>\n",
" </tr>\n",
" <tr>\n",
" <th>849</th>\n",
" <td>10</td>\n",
" <td>69</td>\n",
" <td>38</td>\n",
" </tr>\n",
" <tr>\n",
" <th>850</th>\n",
" <td>10</td>\n",
" <td>70</td>\n",
" <td>38</td>\n",
" </tr>\n",
" <tr>\n",
" <th>851</th>\n",
" <td>10</td>\n",
" <td>71</td>\n",
" <td>7</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>852 rows × 3 columns</p>\n",
"</div>"
],
"text/plain": [
" file_id id class\n",
"0 1 1 2\n",
"1 1 2 2\n",
"2 1 3 2\n",
"3 1 4 3\n",
"4 1 5 7\n",
".. ... .. ...\n",
"847 10 67 38\n",
"848 10 68 38\n",
"849 10 69 38\n",
"850 10 70 38\n",
"851 10 71 7\n",
"\n",
"[852 rows x 3 columns]"
]
},
"execution_count": 80,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#create submission\n",
"\n",
"pred = df[['file_id','id','class']]\n",
"sub = pd.read_csv('Названиеоманды.csv',delimiter=';')\n",
"sub = pd.merge(sub,pred,how='left',on=['file_id','id'])\n",
"sub.drop(columns=['class_x'],inplace=True)\n",
"sub.columns = ['file_id','id','class']\n",
"sub = sub.fillna(23).astype(int)\n",
"sub['class']+=1\n",
"sub"
]
},
{
"cell_type": "code",
"execution_count": 94,
"id": "e26e3480-9486-4dcb-927e-3f85cfb0fc77",
"metadata": {},
"outputs": [],
"source": [
"#save submission data\n",
"sub.to_csv('MAGNUM_OPOSSUM.csv',index=False,header=True,sep=';')"
]
},
{
"cell_type": "code",
"execution_count": 38,
"id": "038fa0f9-afc8-4750-8b72-36711d41b4e8",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<AxesSubplot:xlabel='class', ylabel='id'>"
]
},
"execution_count": 38,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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1LJlS02bNk3NmjXT7t27NWPGDJ09e1apqakVtrt06ZK6dOmikSNHKiwsTEePHtXSpUt19OhRrVq1yqvX+uqrr8pms3m1riStXLnSZfA2b9680jYrVqxQenq6xo8fr7i4OF28eFF79uzx2O/MmTN1+fJll2Vr1qzRRx99pMTERLdt9u3bpwkTJig5OVlTpkzRsWPHtGjRIhUUFOjpp592rufNPtq8ebNmzJih8ePHKyEhQRaLRS+88IKaNWum7t27V9guIyNDWVlZuuuuu7Ru3Tqv+jtz5ozWrVune++9V5MmTdKVK1e0cOFCff755/rVr35VYV95eXlKSUlRdHS0TCaTtmzZonnz5qlp06ZKSEiodPwVFhZq7ty5+tnPfqaioiKvxu2tt97qsi3/93//V3/9618VFxdXYbv8/HyNHDlSQUFBmj59um688UZ9+OGH2rRpU4Wv76abbnJuv6v7WrhwoSIiIhQWFua2r9mzZ+ujjz7SlClTFBMTo3379mnx4sVq0KCBevbsWWGNc+fO1fvvv69JkyYpKipKTz75pLKysjR58mR16dLF7XvS3RhJT0/Xr371K4/vZXdjpLJjgLsxsmrVKr388svq3bu3x/7KjpOnnnpKWVlZevDBB9W/f3+Px5urx8ilS5fUoEGDSo9TZcfIc889p7CwMI/t3I2R6dOnq169ehW2czdGHA6H7r//fkVERHjsr+w4mTZtmr777jv169dPDz74oNs2ZcfIxo0btWTJEg0ZMsTjMfiLL75Qamqqfve732n69On67LPPtGLFCvXt21ezZs2qsN2nn36qb7/9VrfffrtycnIkVX7MLywsVFpamn77299qzJgxMpvNWrx4sQ4dOqQJEyYoPj7e4+8Jh8OhF198UeHh4bJarV79fomMjNSCBQucjz/99FPl5OTo9ttvr7Cd3W7XhAkTlJWVpdTUVLVq1UqbNm3St99+q9GjR1fYruz+lqSnn35aDRo08Dr0lL5QlPHaa6854uLiHBcvXnQu+/vf/+7o0KGD4+zZsx7b2mw257+ffvppR3JycqX9nT9/vtyy5557znHrrbe6/DxvrFu3ztGuXbtK63Q4HI5jx4454uLiHG+//bajXbt2jgMHDlS47rvvvuto166d21o9OX78uKNjx46O7du3+9TOnb59+zrGjBlT4fOPPPKI47e//a3LsjfeeMPRqVMnR3Z2tnOZN/vo17/+tWPKlCkuy+677z7Ho48+6rHd1T+7Xbt2jpUrV1baX15eniM/P99lmdVqdfTo0cMxe/Zsr8dRaY0PP/ywxxpLLVq0yPHAAw84nn76acegQYM81uhwOBwPPvigY+zYsS7LvNmWf/7znx39+vVz5OXl+dSurN27dzvatWvnsFgsbtvYbDZH165dHUuWLHFZ/uSTTzr69etXYV9nz551dOjQwfHmm286l50/f94xePBgx/jx453Lyr4n3Y2Re++91zlGKmrnboxUdgxwN0YuX77s6N69u2P27Nke+yvr/PnzjuHDhzvHiac2V4+RgQMHeqzR4XA/Rrw5vrkbI1U5Ln722WfOMVJRO3fj5Pz5846nnnrKOU7KtnE3Rux2e7kx4nCUPwY/8sgjjuHDh7usM2XKFEdSUpLHdle/xj59+jhmzZrl9jVf3a6kpMRx6dIll+dLSkocAwcOdIwbN67Cvkpt2LDBcffddzsWLlzoiIuL89iXw+H9e7dsu/Xr1ztuu+02x7lz53xqV1ZWVpajXbt2jvT09EpruBpzfNzYuXOnEhMTFRYW5lyWlJQku92uXbt2eWxrNvu+ScPDw8st69Chgy5fvqz8/HyfflZpzcXFxZWuO2fOHI0YMUJRUVE+9eGLjRs3qlWrVrrzzjuv6ef8+9//1qlTpzRkyJAK1zl8+HC5L6rt2bOniouL9a9//cu5rLJ9lJWVpRMnTigpKclleXJysvbs2aOioqIK27r72ZX117BhQzVo0MBlWZMmTdS6dWv98MMPHtuW1axZM6/2/cmTJ7V69Wo999xzkuTxkqon3oz3d955R/fee68aNmzoU7uyLBaLGjdurL59+7p93uFwqKSkpNzp+9DQUI9nvr799lvZbDaXsRMeHq6ePXvqX//6l3N/X/2erGiMDB06tNwYKftedvfaKzsGuBsjjRo1Ups2bcqNkcqOHeHh4QoLC3MZJ+7alB0jV18u9rYvb16b5H6MVOW4uGnTJrdj5Op27sZJeHi4mjRp4jJOrm7jboyYTKZyY0RyPQYXFRVp7969GjhwoEs9gwYN0vHjx3Xq1Cm37STv3yNXtwsKClLTpk1dng8KClL79u1dxom73xNWq1ULFy7UM888o+Dg4Er78kXZdhs2bNDAgQMrPUtTWX+bNm2SyWTS4MGDfaqH4ONGZmamoqOjXZaFhoYqIiJCmZmZNVLDl19+qebNm6tx48aVrmuz2XTlyhUdOnRIy5cvV9++fdWqVSuPbTIyMnTkyBE9/vjjPtU1ePBgdejQQf369dPrr79e6WWy/fv3q127dnr11VeVmJiozp07a8SIEdq/f79P/W7atEkNGzas8Jq+9NM147JzsEofHz9+3Ou+Svdx2UAYExOj4uJiZWVlef2zqspqtTrno3hSehC3Wq36n//5H+3atUsPPPBApT//v//7vzVs2DD98pe/9Kmuzz//XHFxcYqNjdWDDz6o//3f//W4/qlTp5Sdna1mzZpp/Pjx6ty5s3r06KHnnntOeXl5XvdbXFysjz76SHfffbfq16/vdp2goCDdc889Wrt2rQ4cOKC8vDzt3r1b77//vh588MEKf3bpLy13Y6eoqMj5y+nq96QvY8SX9/LVKmtX0Rhx166yceKujTdjxF07b8bI1e18GSOetomnMXJ1O2/HydVtKhsj33//vdtj8MmTJ1VcXFxuH8XExEiSjh075vOxW/LtmF9SUqL9+/crKirKY5tFixapU6dO6tOnj099ff/997rtttvUuXNn3XPPPfr44489tisuLtY333yjFi1a6KmnnlJcXJy6deumJ554QtnZ2T69ts2bN+v222/XzTffXOk2uxpzfNywWq0KDQ0tt7xp06bOa63V6YsvvpDFYnG5Tu5Jnz59dO7cOUlSr169tHDhQo/rFxQUaP78+Zo8ebLXB+OIiAhNnDhRXbt2lclkck7WO3funMd5T9nZ2Tp48KCOHDmimTNnqkGDBnrttdf0yCOP6KOPPtKNN95Yad8lJSX68MMP1bdvX5e/CMu65ZZbdODAAZdl+/btkySf9lvpumXHQOnjmhgDL7/8skwmk/7rv/5LixYtqnC9PXv26OGHH5Yk1atXTzNmzCj312VZW7du1VdffaWMjAyfarr99ts1bNgw51mGN954Qw8//LD++te/qlu3bm7b/Pjjj5J+mmD761//Wunp6Tpx4oQWLlyo/Px8vfLKK171vXPnTl26dKnSv+xmzpypmTNnKiUlxbls3Lhxzm3kzi233CJJOnDggMsB9uqxU/Y96e0Y8fW9XMqbdlePkcraeRon7tp4M0bctfNmjJRt5+0YqWybVDRG3LWrbJyUbVPZGBk1apQuXLggyfUYXNk4eeqpp5zreHPsLuXLMX/lypU6d+6cdu/erS5durhtc/jwYb3zzjtuJyp76qtDhw6KjY1V27ZtlZubq7fffluPP/64Fi9erLlz57ptd+nSJRUXFys9PV233367li1bpgsXLujll1/WxIkTdebMGa9e27fffqsjR45o9uzZXm2zqxF8/MzZs2c1efJkxcfHa9SoUV61SUtLU0FBgY4dO6YVK1Zo/PjxWr16tdtT09JPk41LP/HkrV69eqlXr17Oxz179lT9+vW1Zs0ajR8/vsJTlg6HQ/n5+Vq8eLHzL8euXbuqb9++Wrt2rZ544olK+961a5cuXLhQ6S+9+++/X88++6zWrFmjYcOGOSc3V7Qd/NW7776r9evXa/78+ZX+JdOlSxe98847unz5snbu3Kk5c+YoKCjI5YB+tStXrmju3LmaOHGi20sJnvzhD39weXzXXXdp8ODBevXVV5Wenu62jd1ul/TTmZE//elPkqTExETVq1dPzz33nCZPnuxV3x988IF+9rOfVTixvdSCBQu0fft2zZkzR23atNG+ffu0fPlyhYaG6tFHH3Xbpl27durevbsWLFign//852rTpo02btzoPFNx4cIFvfDCCz69J6WqvZe9bedujHhqV9E46dWrV7k23oyRivqqbIy4a+fNGAkODq50m7gbIxXV6WmcDB48uFybysbItGnT1Lp163LH4MqMHj1aPXr08PrYXcrbY/6uXbu0dOlSTZgwQf3793fbxmw2a9asWbr//vudZ6K87euhhx5yWbdv374aMWKElixZUmG70v3dqFEjLVu2zHkW7Wc/+5kefvhhvfjii/rFL35R6Wv74IMPFBwcrAEDBlS6ncsi+LgRGhqq3NzccstzcnLKXT+9nqxWq8aMGaOwsDAtXbrU62u8pYGiW7duio2N1bBhw/TPf/7T7V/+p0+f1qpVq7R8+XLnayy9Xp6fn6+8vDw1atTIq36TkpK0atUqHT58uMLgExoaqrCwMJfT5WFhYerYsaOOHTvmVT+bNm1SWFiYevbs6XG9e+65R0eOHNFLL72kuXPnKjg4WKmpqVqzZo1PM/5L93Fubq4iIiKcy61Wq8vz1WHHjh16/vnnNWHCBP32t7+tdP3GjRs7b0GQmJgom82m+fPn65577nG7/po1a2Q2m5WcnOx8PcXFxbLb7bJarRXeXsCdhg0b6s4779SWLVsq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3wkPD1fjxo119OhRr9scOXJEJ06c0LRp0zR27Fj1799fv/rVr3TTTTe5Xb9169Z65JFHtGrVKm3atEnFxcVatWqVyzpxcXGaPHmyNm7cqAULFujo0aOyWCzX9NoA1C6CDwC/Yzab1b9/f23btk1ff/11uefdTW42m83lnnM4HHrzzTdd1isoKNCVK1dclrVu3VqNGjVSUVGRJCknJ6dcHx06dJAk5zoAAhNzfAD4pSlTpmjXrl0aOXKk7rvvPsXExCg7O1sZGRn629/+Vm796OhotW7dWn/605907tw5NW7cWFu2bJHVanVZ78SJE/r973+vgQMHqm3btgoKCtLHH3+sH3/8UcnJyZKk9957T2+//bb69++v1q1bKy8vT+vXr1fjxo3Vu3fvGnn9AKoHwQeAX2revLnWr1+vxYsX64MPPtDly5fVvHlz9e7d2+XTW6WCg4P12muvac6cOXr99ddVv3593X333XrggQc0bNgw53o333yzkpOTtWfPHv3jH/9QUFCQoqOjtWjRIg0YMEDST5Obv/76a1ksFv34449q0qSJunTpogULFigyMrLGtgGA68/kqOiGGAAAAHUMc3wAAIBhEHwAAIBhEHwAAIBhEHwAAIBhEHwAAIBhEHwAAIBhEHwAAIBhEHwAAIBhEHwAAIBhEHwAAIBhEHwAAIBhEHwAAIBhEHwAAIBh/H/Qs60peumbxQAAAABJRU5ErkJggg==\n",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"#show class distribution\n",
"\n",
"f = sub.groupby('class').count().reset_index()[['class','id']]\n",
"f['class'] = f['class']-1\n",
"\n",
"sns.barplot(x=f['class'],y=f['id'],color='#ff6666',errwidth=.32)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "hack",
"language": "python",
"name": "hack"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}