{ "cells": [ { "cell_type": "code", "execution_count": 2, "id": "3a40ada8-e64a-4c93-904c-b2a5a5c8ca70", "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " precision recall f1-score support\n", "\n", " 0 1.00 1.00 1.00 10\n", " 1 1.00 0.75 0.86 12\n", " 2 0.73 1.00 0.84 8\n", "\n", " accuracy 0.90 30\n", " macro avg 0.91 0.92 0.90 30\n", "weighted avg 0.93 0.90 0.90 30\n", "\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "D:\\4_week\\venv\\Lib\\site-packages\\sklearn\\neural_network\\_multilayer_perceptron.py:691: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (500) reached and the optimization hasn't converged yet.\n", " warnings.warn(\n" ] } ], "source": [ "from sklearn.datasets import load_iris\n", "from sklearn.model_selection import train_test_split\n", "from sklearn.neural_network import MLPClassifier\n", "from sklearn.metrics import classification_report\n", "\n", "# Загрузка и разбиение данных\n", "X, y = load_iris(return_X_y=True)\n", "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)\n", "\n", "# Модель MLP — многослойный перцептрон\n", "clf = MLPClassifier(hidden_layer_sizes=(10,), activation='relu', max_iter=500)\n", "clf.fit(X_train, y_train)\n", "\n", "# Отчёт о точности\n", "print(classification_report(y_test, clf.predict(X_test)))" ] }, { "cell_type": "markdown", "id": "daeaf6e9-855d-4f61-a062-2bc4aebc8ea2", "metadata": {}, "source": [ "Целью является сравнение различных способов векторизации текстовых данных на примере подмножества новостных текстов из набора 20 Newsgroups. Анализируется эффективность методов по скорости и числу уникальных признаков." ] }, { "cell_type": "markdown", "id": "befe0cc5-5c62-4a41-9f42-8aecb38c1d95", "metadata": {}, "source": [ "1. Загрузка данных. Загружаем подмножество новостных текстов по выбранным категориям" ] }, { "cell_type": "code", "execution_count": 12, "id": "5a6aa580-4e49-428c-9310-df95b84d7aea", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Loading 20 newsgroups training data\n", "3803 documents - 6.245MB\n" ] } ], "source": [ "from sklearn.datasets import fetch_20newsgroups\n", "\n", "categories = [\n", " \"alt.atheism\",\n", " \"comp.graphics\",\n", " \"comp.sys.ibm.pc.hardware\",\n", " \"misc.forsale\",\n", " \"rec.autos\",\n", " \"sci.space\",\n", " \"talk.religion.misc\",\n", "]\n", "\n", "print(\"Loading 20 newsgroups training data\")\n", "raw_data, _ = fetch_20newsgroups(subset=\"train\", categories=categories, return_X_y=True)\n", "data_size_mb = sum(len(s.encode(\"utf-8\")) for s in raw_data) / 1e6\n", "print(f\"{len(raw_data)} documents - {data_size_mb:.3f}MB\")\n" ] }, { "cell_type": "markdown", "id": "83f728a3-b22a-41e8-b51f-b8e7a5d55c95", "metadata": {}, "source": [ "2. Предобработка: токенизация и частоты слов. Создадим простую функцию для разбиения текста на токены и подсчета частоты слов" ] }, { "cell_type": "code", "execution_count": 13, "id": "e8466abd-87bc-4952-bd68-fdb4b4220bc5", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "defaultdict(int,\n", " {'that': 1,\n", " 'is': 2,\n", " 'one': 2,\n", " 'example': 1,\n", " 'but': 1,\n", " 'this': 1,\n", " 'another': 1})" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import re\n", "\n", "\n", "def tokenize(doc):\n", " \"\"\"Extract tokens from doc.\n", "\n", " This uses a simple regex that matches word characters to break strings\n", " into tokens. For a more principled approach, see CountVectorizer or\n", " TfidfVectorizer.\n", " \"\"\"\n", " return (tok.lower() for tok in re.findall(r\"\\w+\", doc))\n", "\n", "\n", "list(tokenize(\"This is a simple example, isn't it?\"))\n", "from collections import defaultdict\n", "\n", "\n", "def token_freqs(doc):\n", " \"\"\"Extract a dict mapping tokens from doc to their occurrences.\"\"\"\n", "\n", " freq = defaultdict(int)\n", " for tok in tokenize(doc):\n", " freq[tok] += 1\n", " return freq\n", "\n", "\n", "token_freqs(\"That is one example, but this is another one\")" ] }, { "cell_type": "markdown", "id": "99797511-8c47-4b5f-aa06-c074c88ee277", "metadata": {}, "source": [ "3. Векторизация с помощью DictVectorizer. Метод превращает словарь в разреженный числовой вектор" ] }, { "cell_type": "code", "execution_count": 14, "id": "6901e1e7-fa59-459d-8df4-a0a6aaeac7c3", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "done in 1.750 s at 3.6 MB/s\n", "Found 47928 unique terms\n" ] } ], "source": [ "from time import time\n", "\n", "from sklearn.feature_extraction import DictVectorizer\n", "\n", "dict_count_vectorizers = defaultdict(list)\n", "\n", "t0 = time()\n", "vectorizer = DictVectorizer()\n", "vectorizer.fit_transform(token_freqs(d) for d in raw_data)\n", "duration = time() - t0\n", "dict_count_vectorizers[\"vectorizer\"].append(\n", " vectorizer.__class__.__name__ + \"\\non freq dicts\"\n", ")\n", "dict_count_vectorizers[\"speed\"].append(data_size_mb / duration)\n", "print(f\"done in {duration:.3f} s at {data_size_mb / duration:.1f} MB/s\")\n", "print(f\"Found {len(vectorizer.get_feature_names_out())} unique terms\")\n" ] }, { "cell_type": "markdown", "id": "37e02d00-0cb1-4bb9-a9ba-03978e578808", "metadata": {}, "source": [ "4. Векторизация с помощью FeatureHasher. Метод применяет хеширование - каждому слову присваивается индекс с помощью хеш-функции" ] }, { "cell_type": "code", "execution_count": 15, "id": "33b89a91-1f29-4edd-9aa0-997e00393ec7", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "done in 0.947 s at 6.6 MB/s\n", "Found 43873 unique tokens\n", "done in 1.066 s at 5.9 MB/s\n", "Found 47668 unique tokens\n", "done in 0.909 s at 6.9 MB/s\n", "Found 43873 unique tokens\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAABCUAAAINCAYAAAAJJ8XzAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAAP1FJREFUeJzt3QnclmPeP/6jRIl2S0UUGbJv2bcMQgxjfewRxjbEZBvzyL5ONKZHEmIeIcPIMtZsg7HvyZY0WbJThET9X9/j97/u575TSbiPu+73+/W6XnWd13md53Fe9z2m83N9j+/RYNq0adMSAAAAQC1rWNsnBAAAAAhCCQAAAKAIoQQAAABQhFACAAAAKEIoAQAAABQhlAAAAACKEEoAAAAARQglAAAAgCIalTkttWXq1Knp3XffTc2aNUsNGjQoPRwAAADmcdOmTUuff/55at++fWrYcNa1EEKJeVwEEh06dCg9DAAAAOqZt956Ky255JKz3EcoMY+LConKL0Pz5s1LDwcAAIB53MSJE/OX45X70VkRSszjKlM2IpAQSgAAAFBbZqeFgEaXAAAAQBFCCQAAAKAIoQQAAABQhFACAAAAKEIoAQAAABQhlAAAAACKEEoAAAAARQglAAAAgCKEEgAAAEARQgkAAACgCKEEAAAAUIRQAgAAAChCKAEAAAAUIZQAAAAAihBKAAAAAEUIJQAAAIAihBIAAABAEUIJAAAAoIhGZU5LbVu5712pYeOmpYcBAHXa2HN6lB4CANQrKiUAAACAIoQSAAAAQBFCCQAAAKAIoQQAAABQhFACAAAAKEIoAQAAABQhlAAAAACKEEoAAAAARQglAAAAgCKEEgAAAEARQgkAAACgCKEEAAAAUIRQAgAAAChCKAEAAAAUIZQAAAAAihBKAAAAAEUIJQAAAIAihBIAAABAEUIJAAAAoAihBAAAAFCEUAIAAAAoQigBAAAAFCGUAAAAAIoQSgAAAABFCCUAAACAIoQSAAAAQBFCCQAAAKAIoQQAAABQhFACAAAAKEIoAQAAABQhlAAAAACKEEoAAAAARQglAAAAgCKEEgAAAEARQgkAAACgCKEEAAAAUIRQAgAAAChCKAEAAAAUIZQAAAAAihBKAAAAAEUIJQAAAIAihBIAAABAEUIJAAAAoAihBAAAAFCEUAIAAAAoQigBAAAAFCGUAAAAAObtUKJBgwZp+PDhqT7ZbLPNUu/evUsPAwAAAObNUKJnz545cIjH/PPPnxZffPG05ZZbpiuuuCJNnTq1ar/x48enbbbZZraOecopp6TVV1+96vk333yTFllkkXTOOefMcP/TTz89n3fKlCk/6VqmP+9P9Y9//COPDQAAAPiFKiW23nrrHDqMHTs23XHHHalbt27pqKOOStttt1369ttv8z5t27ZNjRs3nqPjL7DAAmnvvfdOQ4YM+d5r06ZNS1deeWXad999cyhSF0SIElq3bp2aNWv2i53np4YwAAAAMNeHEhE2ROiwxBJLpDXXXDP98Y9/TDfffHMOKCIwmNH0jbfffjvtscce+cZ9oYUWSmuvvXZ6/PHH8/6nnnpqev7556sqMGJbr1690muvvZYefvjhGud+8MEH05gxY/Lr4bLLLktdunRJTZo0SSussEK6+OKLa+z/Y88bxo0bl3bYYYe08MILp+bNm6fddtstvf/++9+rsIhzd+rUKZ97+ukbDzzwQNVxqz+i0qQiPrP4/OL9yyyzTB5PJdSpfIYDBw5Mv/nNb/LYzzzzzJ/jxwcAAABFNPqlDrz55pun1VZbLU9hOPDAA2u89sUXX6RNN900hxi33HJLDjSeeeaZPN1j9913TyNHjkx33nlnGjFiRN6/RYsWacEFF0xdu3bN00I22mijqmNF9cQGG2yQA4ihQ4emk08+OQ0YMCCtscYa6dlnn00HHXRQvoHfb7/95ui88VolkIgAJEKCww8/PO8fQUPF6NGj04033pivd7755vve5xFjjGqSipdffjltu+22aZNNNsnPH3rooVztcdFFF6WNN944vfHGG+nggw/Or/Xt27dGABLTWPr3758aNfrFfnwAAADwi/tF72ojKHjhhRe+t/2aa65JH374YXryySdzxULo3Llz1esRAMQNd4QG1UU1RJ8+ffKNe+zz+eefpxtuuCE/r9y89+vXL+200075eVQtjBo1Kg0aNCiHEnNy3nvuuSe9+OKL6c0330wdOnTI2/72t7+llVZaKR8ngpLKlI3Yvuiii850CkrluB9//HEOag444ID8CFEVccIJJ+RxhqiUiH4Uxx13XI1QYs8990z777//j/xJAAAAQD1bfSP6PcSUg+k999xzuZKhEgzMrph28d1336Xrr78+Px82bFhq2LBhrlqYNGlSri6I4CLChcrjjDPOyNvn9LxR0RBhRCWQCCuuuGJq2bJlfq1i6aWXnmkgMX0fiJ133jnv/5e//KVqe0wbOe2002qMPao8orriyy+/rNovppsAAADAvOAXrZSIm/aoVpheTMWYE9HPYZdddslTNqLCIP6M/g5xA1/p8TB48OC07rrr1nhfZTrFnJ53dsQUkdlx6KGHprfeeis98cQTNaZfxNSSqJaoVHlUV+lR8WPOAwAAAPU2lLjvvvvytIejjz76e6+tuuqquSnkJ598MsOqhZjqEBURMxKVENFA8rbbbkv//ve/0/nnn5+3x5Kg7du3z00v99prrxm+d07OG00zI0SIR6VaIqaEfPbZZ7li4se44IILcpVHjLtNmzY1XosGl6+++mqN6SQAAAAwL/tZpm9Mnjw5vffee+mdd97JjSPPOuus3BwylgSN5o0zmoYR/RV23HHH9Mgjj+QgIZpEPvroo/n1jh075h4OMd3io48+yseviMaQceMex42eFdFAsiIqDc4+++zcYyJW6ohQJKopIgyY0/NuscUWaZVVVslBR1xbVDjEuaNh5o+ZShHNM6M/RIQoiyyySP684jFhwoT8ejTojJ4UcQ0vvfRSrjK57rrr0p/+9Kef8JMBAACAeTyUiBUr2rVrl2/qt95663T//ffnYCCWuJzRShRRkXD33XenxRZbLK9AETf9saJEZd/ouRDH6datW+7TcO2111a9N3pUxNSNTz/9tKpJZEU0j4xKiAgi4pgRHMSynpUpJHNy3jhfXEerVq1yIBIhRTShjH4WP0YsZRpVGIccckj+rCqPo446Kr/evXv3XP0R44vmmeutt1668MILc+8JAAAAmBc1mBbdKJlnRHVH9cqSiRMn/r9Gnb2vTw0bNy06NgCo68ae06P0EABgrhf3oS1atMgzA6I3ZLHVN6h9MX0lfviVR/VVQwAAAKAuEUrMY0488cScRlUe0aATAAAA6t2SoNS+xo0b5wcAAADUdSolAAAAgCLm+lDilVdeyStVNGnSJK2++uqpLohVSPr371/1PFbwGD58eNExAQAAQF0z10/f6Nu3b1pooYXSq6++mhZeeOFUF40fPz4vKTo7TjnllBxgPPfcc7/4uAAAAKCkuT6UeOONN1KPHj3S0ksvPdN9pkyZkuaff/5UStu2bYudGwAAAFJ9n74xefLkdOSRR6bFFlssT7XYaKON0pNPPln1+gMPPJCnOdx7771p7bXXTk2bNk0bbLBBroCYmdj/6aefTqeddlr+e1QZjB07Nv992LBhadNNN83nGjp0aN7/sssuS126dMnbVlhhhXTxxRfXON4TTzyR1lhjjfx6jOGmm27Kx5pV1cIHH3yQtt9++7TgggumTp06VZ1r+nFWn77x9ttvpz322CO1bt06V3nEuR5//PF05ZVXplNPPTU9//zz+T3xiG3Tpk3L17bUUkvlJpbt27fPnyUAAADMzWqtUuK4445LN954Y7rqqqtyVcN5552XunfvnkaPHp1vzitOOumk1K9fv7ToooumQw45JB1wwAHpkUcemem0iC222CJtvfXWqU+fPnn6xkcffZRfO+GEE/JxKiFDhAUnn3xyGjBgQN727LPPpoMOOiiHAvvtt1/64osv0nbbbZe23HLLdPXVV6c333wzHXXUUT94XT179kzvvvtuuv/++3M1RoQFEVTMTJwnwpIlllgi3XLLLbmK4plnnklTp05Nu+++exo5cmS6884704gRI/L+LVq0yJ/bhRdemK677rq00korpffeey8HFwAAADA3q5VQYtKkSWngwIH5W/9tttkmbxs8eHC655570uWXX56OPfbYqn3PPPPMfNNeCRZiasbXX3+dg4XpxQ19o0aNchhRmSJRCSV69+6ddtpppxq9JyKkqGyLqoZRo0alQYMG5VDimmuuycFAjCfOFTf/UdFw6KGHzvS6XnvttXTHHXfkCouuXbvmbfH+qMaYmTjPhx9+mKtEKmFM586dq16Pa4lrqj7lY9y4cfl5BDARfETFxDrrrDMbnzwAAADU8+kb0fch+jpsuOGGVdvi5jpurF9++eUa+6666qpVf2/Xrl3+c1aVBzMTUyKqhyIxhl69euWb/srjjDPOyNtDjCPOXT38WH/99Wd5jnhPBAhrrbVW1baYFtKyZcuZviemgkSlRvXqkB+y6667pq+++iots8wyubojppV8++23s/1+AAAAqIvqXKPL6g0po6dCiAqGHyumZVSfMlGpzlh33XVr7DfffPOl2hS9J36sDh065N4aMaUjqksOO+ywdP7556cHH3ywaANPAAAAqPOVEssuu2xaYIEFavSGiMqJmMKw4oor/uLnX3zxxXNzyDFjxuSpEtUfMY0jxJSLF154IU8VqXjsscdmedyoioiKhWi2WRHh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vflaImCYOnVqfj2uK0KG66+/Pr366qv53B07dqxxjAhpdtttt/TCCy+kbbfdNu21117pk08+ya999tlnafPNN09rrLFGPkeEIO+//37ev7oYe1RHPPLII+mSSy750dcBAAAAc/X0jdtuuy1/m18R3+5/+umnORTYb7/98raolDj99NNz6NC3b9+8Lb7hr4gb9jPOOCMdcsghuXohbrRbtGiRKx6i8mJOxPF32mmnqudx3n79+lVt69SpU1VgUhln2GOPPXKlR3WTJ09OPXr0qHq+884713j9iiuuyFNW4ngrr7xyGjduXK5+iGqKuIaolJhRn4o4V4iAJIKMJ554Ik+HGTBgQA4kYnv1c0RFyWuvvZZ+9atf5W1xjvPOO2+OPh8AAACY60OJbt26pYEDB1Y9j+kYq666av72vnplxHfffZe+/vrr9OWXX+YpCyNGjMhTGl555ZU0ceLEPLWj+us/1dprr12jsiGmV/Tq1SsddNBBVdvjnBF+VHfhhRemLbbYosa2448/Po+/4vXXX89VF48//nieUlGpkIgwIkKJCBy23HLLtPzyy+eQIaZ3bLXVVjWOGZ9R9c8sqkI++OCD/Pz5559P999/f42wpyKuoxJKrLXWWnP8+QAAAMBcH0rEDXXnzp1rbIveEDE9oXqlQkX0WIi+D3Gjfuihh+bgonXr1unhhx/OoUH0Y5hVKBGVB9OmTfteI8sZjav6eMLgwYPTuuuuW2O/6asiojJj+utp1qxZnlJRsf322+fqhzhe+/btcygRYUSMPUQvjTfffDPdcccdOXyJaRcRdNxwww1Vx5i+8WZcVyXciPHGOc4999zvXVf0qZjRNQIAAEC9CyVmJG7Ko5fC9Df3FU8//XS+AY/pFNGPIUT/hepiCkf16oSKmCYRPSaqVy1EdcWsRKPICA/GjBmTezf8FB9//HG+tggkNt5447wtApXpReXD7rvvnh+77LJLrpiInhERwMzO53fjjTfmaS2NGv0sPxIAAACo836WO+CY2hCVEEsttVS+IY/gIaYkxIoS0TsiwoqobvjrX/+aKwJm1KgxbsijYiAaSa622mq5eiIe0QAyei6sv/76ObSIqRWzs9xnVG4ceeSRebpGBATRJyKaSEb/i2haObtatWqVV9y49NJLc9VCTNmI/hnVxcoi8Vr0hYhr//vf/54rMGK1jtlx+OGH59Ajek5EH44IMkaPHp2uu+66vILI9NUdAAAAMC/4WVbfiNUuogHm3Xffnbp27ZrWW2+93Kuh0vAxQoa4cY/pCTHtIVanmH7JzFiBIxpfRqVBVEdUGjpGdUU0fIwqhT333DOvyjE7PSgOPPDAfEM/ZMiQvBRpLBcaK4JEw8sfI0KGCAei2iPGfvTRR6fzzz//e9M9YrzR1yKuP6ar3H777VVVIT8kqjoiqInQJXpRxHijcWeEGrN7DAAAAJjbNJg2fcMG5mpRERKPimgqGqFOh97Xp4aNf3pDUQAAgPpi7Dn/tyojsy/uQ2PWwoQJE3Krg1nxNfw8JipQ4odfeUQgAQAAAHWRUGIec+KJJ+Y0qvJ46623Sg8JAAAAZshSD/OYxo0b5wcAAADUdSolAAAAgCLm+lDilVdeyat9NGnSJK2++uqpLojlTfv371/1vEGDBmn48OFFxwQAAAB1zVw/faNv375poYUWSq+++mpaeOGFU100fvz41KpVq9na95RTTskBxnPPPfeLjwsAAABKmutDiTfeeCP16NEjLb300jPdZ8qUKWn++edPpbRt27bYuQEAACDV9+kbkydPTkceeWRabLHF8lSLjTbaKD355JNVrz/wwAN5msO9996b1l577dS0adO0wQYb5AqImYn9n3766XTaaaflv0eVwdixY/Pfhw0bljbddNN8rqFDh+b9L7vsstSlS5e8bYUVVkgXX3xxjeM98cQTaY011sivxxhuuummfKxZVS188MEHafvtt08LLrhg6tSpU9W5ph9n9ekbb7/9dtpjjz1S69atc5VHnOvxxx9PV155ZTr11FPT888/n98Tj9g2bdq0fG1LLbVUbmLZvn37/FkCAADA3KzWKiWOO+64dOONN6arrroqVzWcd955qXv37mn06NH55rzipJNOSv369UuLLrpoOuSQQ9IBBxyQHnnkkZlOi9hiiy3S1ltvnfr06ZOnb3z00Uf5tRNOOCEfpxIyRFhw8sknpwEDBuRtzz77bDrooINyKLDffvulL774Im233XZpyy23TFdffXV6880301FHHfWD19WzZ8/07rvvpvvvvz9XY0RYEEHFzMR5IixZYokl0i233JKrKJ555pk0derUtPvuu6eRI0emO++8M40YMSLv36JFi/y5XXjhhem6665LK620UnrvvfdycAEAAABzs1oJJSZNmpQGDhyYv/XfZptt8rbBgwene+65J11++eXp2GOPrdr3zDPPzDftlWAhpmZ8/fXXOViYXtzQN2rUKIcRlSkSlVCid+/eaaeddqrReyJCisq2qGoYNWpUGjRoUA4lrrnmmhwMxHjiXHHzHxUNhx566Eyv67XXXkt33HFHrrDo2rVr3hbvj2qMmYnzfPjhh7lKpBLGdO7cuer1uJa4pupTPsaNG5efRwATwUdUTKyzzjqz8ckDAABAPZ++EX0foq/DhhtuWLUtbq7jxvrll1+use+qq65a9fd27drlP2dVeTAzMSWieigSY+jVq1e+6a88zjjjjLw9xDji3NXDj/XXX3+W54j3RICw1lprVW2LaSEtW7ac6XtiKkhUalSvDvkhu+66a/rqq6/SMsssk6s7YlrJt99+O9vvBwAAgLqozjW6rN6QMnoqhKhg+LFiWkb1KROV6ox11123xn7zzTdfqk3Re+LH6tChQ+6tEVM6orrksMMOS+eff3568MEHizbwBAAAgDpfKbHsssumBRZYoEZviKiciCkMK6644i9+/sUXXzw3hxwzZkyeKlH9EdM4Qky5eOGFF/JUkYrHHntslseNqoioWIhmmxURHnz22WczfU9UY0S1xCeffDLD1+Nz+u6772YYZkRDzYsuuig3BX300UfTiy++OFvXDwAAAPU2lIiqhejNEL0joolj9HKIaQhffvllnlJRG2JVi7PPPjvf1EcviLihHzJkSLrgggvy63vuuWeuzIhxxfhuv/329Oc//3mWx1x++eVzk83f/e53efWMCCcOPPDAWVZDxKob0R9ixx13zCFNBCXRyDJChtCxY8fcZDOCi+iPEauWRC+O6FURTTBj/2jEGeeY1TKoAAAAUNfV2pKg55xzTtp5553TPvvsk9Zcc8286sZdd92VWrVqVSvnj7AglgSNIGKVVVbJzTTjZr9SKRE9Jm699dYcVkTPh1gF5Nxzz/3B48bxogojjhdNNA8++OC87OnMRCXE3XffnffZdttt81jis6lMI4nPKIKObt265RVIrr322tyjIqaeRE+OqLSIaRwx1jZt2vyMnxAAAADUrgbTpk2bVsvnnGuMHTs2hxaxfOjqq6+e5kYTJ07My4p26H19ati4aenhAAAAzDXGntOj9BDm6vvQCRMmpObNm9eNSgkAAACA6oQSAAAAQBF1bknQuiSaTprdAgAAAL8MlRIAAABAEUIJAAAAoAihBAAAAFCEUAIAAAAoQigBAAAAFCGUAAAAAIoQSgAAAABFCCUAAACAIoQSAAAAQBFCCQAAAKAIoQQAAABQhFACAAAAKEIoAQAAABQhlAAAAACKEEoAAAAARQglAAAAgCKEEgAAAEARQgkAAACgCKEEAAAAUIRQAgAAAChCKAEAAAAUIZQAAAAAihBKAAAAAEUIJQAAAIAihBIAAABAEUIJAAAAoAihBAAAAFCEUAIAAAAoQigBAAAAFCGUAAAAAIoQSgAAAABFCCUAAACAIoQSAAAAQBFCCQAAAKAIoQQAAABQhFACAAAAKEIoAQAAABQhlAAAAACKEEoAAAAARQglAAAAgCKEEgAAAEARjcqclto28tTuqXnz5qWHAQAAAFVUSgAAAABFCCUAAACAIoQSAAAAQBFCCQAAAKAIoQQAAABQhFACAAAAKEIoAQAAABQhlAAAAACKEEoAAAAARQglAAAAgCKEEgAAAEARQgkAAACgCKEEAAAAUIRQAgAAAChCKAEAAAAUIZQAAAAAihBKAAAAAEUIJQAAAIAihBIAAABAEUIJAAAAoAihBAAAAFCEUAIAAAAoQigBAAAAFCGUAAAAAIoQSgAAAABFCCUAAACAIoQSAAAAQBFCCQAAAKAIoQQAAABQRKMyp6W2rdz3rtSwcdPSwwAAAGAOjD2nR5oXqZQAAAAAihBKAAAAAEUIJQAAAIAihBIAAABAEUIJAAAAoAihBAAAAFCEUAIAAAAoQigBAAAAFCGUAAAAAIoQSgAAAABFCCUAAACAIoQSAAAAQBFCCQAAAKAIoQQAAABQhFACAAAAKEIoAQAAABQhlAAAAACKEEoAAAAARQglAAAAgCKEEgAAAEARQgkAAACgCKEEAAAAUIRQAgAAAChCKAEAAAAUIZQAAAAAihBKAAAAAEUIJQAAAIAihBIAAABAEUIJAAAAoAihBAAAAFCEUAIAAAAoQigBAAAAFCGUAAAAAIoQSgAAAABFCCUAAACAIoQSAAAAQBFCCQAAAKAIoQQAAABQhFACAAAAKEIoAQAAABQhlAAAAACKEEoAAAAARQglAAAAgCKEEgAAAEARQgkAAACgCKEEAAAAUIRQAgAAAChCKFELGjRokIYPH156GAAAADD3hhI9e/bMN9jTP0aPHv2TB3LllVemli1bproQFsR17rjjjrU6FgAAAKhvGv3YN2y99dZpyJAhNbYtuuiiqS6ZMmVKmn/++dO87JtvvkkLLLBA6WEAAABA7U3faNy4cWrbtm2Nx3zzzZduvvnmtOaaa6YmTZqkZZZZJp166qnp22+/rXrfBRdckFZZZZW00EILpQ4dOqTDDjssffHFF/m1Bx54IO2///5pwoQJVdUXp5xyykyrGaKiIiorwtixY/M+w4YNS5tuumk+/9ChQ/Nrl112WerSpUvetsIKK6SLL754jj6kO++8M2200Ub5vG3atEnbbbddeuONN2oEBEcccURq165dPtfSSy+dzj777BrH+Oijj9Jvf/vb1LRp07TccsulW265pcbrI0eOTNtss01aeOGF0+KLL5722Wef/J6KzTbbLJ+jd+/eaZFFFkndu3efo2sBAACAeaqnxEMPPZT23XffdNRRR6VRo0alQYMG5dDgzDPP/L8TNWyYLrroovTSSy+lq666Kt13333puOOOy69tsMEGqX///ql58+Zp/Pjx+dGnT58fNYYTTjghn//ll1/ON+wRTJx88sl5DLHtrLPOSv/93/+dz/1jTZo0KR1zzDHpqaeeSvfee2++lggYpk6dml+P64qQ4frrr0+vvvpqPnfHjh1rHCNCmt122y298MILadttt0177bVX+uSTT/Jrn332Wdp8883TGmuskc8RIcj777+f968uxh7VEY888ki65JJLfvR1AAAAwFw9feO2227L3+ZXxLf7n376aQ4F9ttvv7wtKiVOP/30HDr07ds3b4tv+Cvihv2MM85IhxxySK5eiBvtFi1a5IqHqLyYE3H8nXbaqep5nLdfv35V2zp16lQVmFTGGfbYY49c6VHd5MmTU48ePaqe77zzzjVev+KKK/KUlTjeyiuvnMaNG5erH6KaIq4hKiVm1KcizhUiIIkg44knnsjTYQYMGJADidhe/RxRUfLaa6+lX/3qV3lbnOO8886bo88HAAAA5vpQolu3bmngwIFVz2M6xqqrrpq/va9eGfHdd9+lr7/+On355Zd5ysKIESPylIZXXnklTZw4MU/tqP76T7X22mvXqGyI6RW9evVKBx10UNX2OGeEH9VdeOGFaYsttqix7fjjj8/jr3j99ddz1cXjjz+ep1RUKiQijIhQIgKHLbfcMi2//PI5ZIjpHVtttVWNY8ZnVP0zi6qQDz74ID9//vnn0/33318j7KmI66iEEmuttdYcfz4AAAAw14cScUPduXPnGtuiN0RMT6heqVARPRai70PcqB966KE5uGjdunV6+OGHc2gQ/RhmFUpE5cG0adO+18hyRuOqPp4wePDgtO6669bYb/qqiKjMmP56mjVrlqdUVGy//fa5+iGO1759+xxKRBgRYw/RS+PNN99Md9xxRw5fYtpFBB033HBD1TGmb7wZ11UJN2K8cY5zzz33e9cVfSpmdI0AAABQ70KJGYmb8uilMP3NfcXTTz+db8BjOkX0YwjRf6G6mMJRvTqhIqZJRI+J6lULUV0xK9EoMsKDMWPG5N4NP8XHH3+cry0CiY033jhvi0BlelH5sPvuu+fHLrvskismomdEBDCz8/ndeOONeVpLo0Y/y48EAAAA6ryf5Q44pjZEJcRSSy2Vb8gjeIgpCbGiRPSOiLAiqhv++te/5oqAGTVqjBvyqBiIRpKrrbZarp6IRzSAjJ4L66+/fg4tYmrF7Cz3GZUbRx55ZJ6uEQFB9ImIJpLR/yKaVs6uVq1a5RU3Lr300ly1EFM2on9GdbGySLwWfSHi2v/+97/nCoxYrWN2HH744Tn0iJ4T0YcjgozRo0en6667Lq8gMn11BwAAAMwLfpbVN2K1i2iAeffdd6euXbum9dZbL/dqqDR8jJAhbtxjekJMe4jVKaZfMjNW4IjGl1FpENURlYaOUV0RDR+jSmHPPffMq3LMTg+KAw88MN/QDxkyJC9FGsuFxoog0fDyx4iQIcKBqPaIsR999NHp/PPP/950jxhv9LWI64/pKrfffntVVcgPiaqOCGoidIleFDHeaNwZocbsHgMAAADmNg2mTd+wgblaVITEoyKaikao06H39alh45/eUBQAAIDaN/ac/1shsq6L+9CYtTBhwoTc6mBWfA0/j4kKlPjhVx4RSAAAAEBdJJSYx5x44ok5jao83nrrrdJDAgAAgBmy1MM8pnHjxvkBAAAAdZ1KCQAAAKAIocTPoEGDBmn48OGlhwEAAABzFaFENcIFAAAAqD1zRSgxZcqU0kMAAAAA6lIoMXny5HTkkUemxRZbLDVp0iRttNFG6cknn6x6/YEHHsjVB/fee29ae+21U9OmTdMGG2yQXn311Zkec+zYsfk9w4YNS5tuumk+7tChQ9PHH3+c9thjj7TEEkvk46yyyirp2muvrXrfbbfdllq2bJm+++67/Py5557LxznhhBOq9jnwwAPT3nvvPcPzduzYMf/529/+Nr+v8jwMHDgwLbvssmmBBRZIyy+/fPrf//3fWX4uffv2Te3atUsvvPBCfv7www+njTfeOC244IJ5ic74zCZNmlTj3GeddVY64IADUrNmzdJSSy2VLr300qrXv/nmm3TEEUfkY8bnsfTSS+elPwEAAKDehhLHHXdcuvHGG9NVV12VnnnmmdS5c+fUvXv39Mknn9TY76STTkr9+vVLTz31VGrUqFG++f4hESYcddRR6eWXX87H/Prrr9Naa62V/vnPf6aRI0emgw8+OO2zzz7piSeeyPvHTf/nn3+enn322fz8wQcfTIssskgORipi22abbTbD81XClCFDhqTx48dXPb/pppvyOP7whz/k8/7ud79L+++/f7r//vu/d4xp06al3//+9+lvf/tbeuihh9Kqq66a3njjjbT11lunnXfeOYcUEbZESBEhQ3Xx+URwE+M/7LDD0qGHHloV3lx00UXplltuSddff33eFiFN9dAEAAAA5kYNpsWd9ByIb/pbtWqVrrzyyrTnnntWTbOIm+XevXunY489NgcC3bp1SyNGjEi//vWv8z6333576tGjR/rqq6/yt/4zqpTo1KlT6t+/fw4DZmW77bZLK6ywQvrzn/+cn0doEdUUffr0yRUPXbt2TaeeemquspgwYUJacskl02uvvZaWW265GX8YDRrkEGLHHXes2rbhhhumlVZaqUblwm677ZavPwKSyvv+/ve/5/dGqHDPPffkio5KdcZ8882XBg0aVPX+CCWiCiSOEZ9BfGYRqlQqMOJH0rZt2zz2Qw45JFdWvPTSS/lzjHP9GBMnTkwtWrRIHXpfnxo2bvqj3gsAAEDdMPacHmluUbkPjfvw5s2b/zKVElEBECFE3LRXzD///GmdddbJ1Q3VRcVARUxBCB988MEsjx9VA9XFtIzTTz89T9to3bp1WnjhhdNdd92Vxo0bV7VP3OhHEBI39VGpsNNOO6UuXbrkECCqJNq3bz/TQGJm4lqqX2OI59Nf49FHH50ef/zx9K9//asqkAjPP/98Dm5ivJVHVH5MnTo1vfnmmzP8jCJ4iFCi8hn17NkzT0eJqSMRUNx9990/6hoAAACg3ja6jLCiovJNf9yUz8pCCy1U4/n555+f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hNJUSsyjvvnmm/zN2BZbbFG1rWHDhvn5o48+WnRsQBkTJkyouiml/vnuu+/SddddlytlYhoH9UtUTfXo0aPGvwuoP+LGI6ZyLrPMMmmvvfZK48aNKz0katEtt9yS1l577fyteHw5scYaa6TBgweXHhYF7xOvvvrqdMABB9SJQCIIJeZRH330Uf4H6OKLL15jezx/7733io0LKCMqpSIVj/LNlVdeufRwqEUvvvhiWnjhhVPjxo3TIYcckiumVlxxxdLDohZFGBXTOKPPDPWzcvbKK69Md955Z+4z8+abb6aNN944ff7556WHRi0ZM2ZM/tkvt9xy6a677kqHHnpoOvLII9NVV11VemgUMHz48PTZZ5+lnj17prqiUekBAFA735KOHDnSPOJ6aPnll89l21Epc8MNN6T99tsvT+ERTNQPb731VjrqqKPy/OFoek39s80221T9PfqJREix9NJLp+uvv940rnr0xURUSpx11ln5eVRKxL8JLrnkkvz/CdQvl19+ef7vQlRP1RUqJeZRiyyySJpvvvnS+++/X2N7PG/btm2xcQG174gjjsjzBu+///7c+JD6ZYEFFkidO3dOa621Vv6mPJrf/uUvfyk9LGpJTOWMBtfRT6JRo0b5EaHURRddlP8eVZXULy1btky/+tWv0ujRo0sPhVrSrl277wXRXbp0MY2nHvrPf/6TRowYkQ488MBUlwgl5uF/hMY/QO+9994aKWk8N5cY6ofoYxyBRJTr33fffalTp06lh0QdEP9fMHny5NLDoJb8+te/zlN4olqm8ohvTKOvQPw9vsCg/jU9feONN/KNKvVDTN2cfknw1157LVfMUL8MGTIk9xWJHkN1iekb87BYDjRKsuIfH+uss07ush0Nzvbff//SQ6MW/+FR/ZuQmEca/wiNRodLLbVU0bFRO1M2rrnmmnTzzTenZs2aVfWTadGiRV6jnHnfiSeemEs043/vMX88fh8eeOCBPKeY+iH+tz99H5mFFlootWnTRn+ZeqJPnz5p++23zzeg7777bl4qPsKoPfbYo/TQqCVHH3102mCDDfL0jd122y098cQT6dJLL80P6teXEkOGDMn3h1EpV5fUrdHws9p9993zEoAnn3xyvhmJ5b+iydH0zS+Zdz311FOpW7duNYKqEP8xiqZXzNuiqVXYbLPNamyP/0OqS82N+OVE2f6+++6b1ySPMCrmk0cgseWWW5YeGlBL3n777RxAfPzxx2nRRRdNG220UXrsscfy36kfunbtmqsmI6g+7bTTcuVkfFkZFVPUHyNGjMhTdmLVjbqmwbSo7wUAAACoZXpKAAAAAEUIJQAAAIAihBIAAABAEUIJAAAAoAihBAAAAFCEUAIAAAAoQigBAAAAFCGUAADqvc022yz17t37B/fbZJNN0jXXXJPqkhNOOCH9/ve/Lz0MAJgjQgkAgNlwyy23pPfffz/913/9V9W2jh07pgYNGqTrrrvue/uvtNJK+bUrr7zye/vHY7755kvt27dPvXr1Sp9++un33v/ggw+mDh06/OC4+vTpk6666qo0ZsyYn3R9AFCCUAIAYDZcdNFFaf/9908NG9b851MEB0OGDKmx7bHHHkvvvfdeWmihhb53nNNOOy2NHz8+jRs3Lg0dOjT961//SkceeeT39rv55pvT9ttv/4PjWmSRRVL37t3TwIED5+i6AKAkoQQAUGtuuOGGtMoqq6QFF1wwtWnTJm2xxRZp0qRJ+bWePXumHXfcMZ166qlp0UUXTc2bN0+HHHJI+uabb6reP3Xq1HT22WenTp065WOsttpq+ZjVjRw5Mm2zzTZp4YUXTosvvnjaZ5990kcffVT1epxv3333za+3a9cu9evX7wfH/eGHH6b77rtvhiHBXnvtlasa3nrrraptV1xxRd7eqFGj7+3frFmz1LZt27TEEkukbt26pf322y8988wzM6zM+M1vfvODn1uIcc2oWgMA6jqhBABQK6I6YI899kgHHHBAevnll9MDDzyQdtpppzRt2rSqfe69996q16699tr0j3/8I4cUFRFI/O1vf0uXXHJJeumll9LRRx+d9t577xwKhM8++yxtvvnmaY011khPPfVUuvPOO/OUi912263qGMcee2zePyoR7r777nyuGYUC1T388MOpadOmqUuXLt97LYKPqFSIKRThyy+/TMOGDcvX+UPeeeeddOutt6Z11123xva4tg8++CBfy+x8buuss056++2309ixY3/wnABQl3w/vgcA+AXEzfW3336bb6iXXnrpvC2+/a9ugQUWyFUGEQBET4aY6hAhwumnn56mTJmSzjrrrDRixIi0/vrr5/2XWWaZHBgMGjQobbrppmnAgAE5kIj9KuJ4McXitddeyz0cLr/88nT11VenX//61/n1CBOWXHLJWY79P//5Tw4fpp+6URGBwR/+8Id00kkn5aqGZZddNq2++uoz3Pf4449Pf/rTn9J3332Xvv766xxIXHDBBTX2icAkgo74PGbnc4vrqowz+lYAwNxCpQQAUCtiqkUEAXFDveuuu6bBgwd/r8Fj7BOBREWED1988UWeGjF69OhchbDlllvmqReVR1ROvPHGG3n/559/Pt1///01Xl9hhRXya7FPPGI6SPXKhNatW6fll19+lmP/6quvUpMmTWb6eo8ePfI4oz9EhCCzqpKIkOW5555LL7zwQq4Mqbw/QorqoURl6sbsfG4xrSPE5wMAcxOVEgBArYjVJu65557073//O0+b+Otf/5orCx5//PHcI+KHxE1/+Oc//5n7MVTXuHHjqn2iv8K55577vfdH/4gINuZENJOc0QoZFdE7InpX9O3bN1/PTTfdNMtjde7cOf99ueWWS/3798/hS4Qp0SsiKiOeffbZHFTM7uf2ySef5D+jFwcAzE1USgAAtSaWwtxwww1zn4i48Y7pCdVv4KPSIaoSqq9iEdUOMf1ixRVXzOFDrFoRN/XVH5WlM9dcc83cjyGmMEy/T6yEEdMq5p9//nxDXxFhQ0ztmJWYEhKracwqmIjqiOhVscMOO6RWrVrN9mcSoUOoXHf0mNhggw1yBcfsfm7R3DOuK6a8AMDcRKUEAFArIgiI6QpbbbVVWmyxxfLzWNWievPImFrRq1ev3HMhmjZG5cERRxyReznEqhV9+vTJzS1jFY6NNtooTZgwIT3yyCN5pY5YxeLwww/P0xuiMeRxxx2Xb+yjOiJWprjssstywBHHjykUsYpFjCOqDmbWK6J6KBEVDnGu7bbbbob7xHXEKh/Vp5/MyOeff54DjmhUGdNSYpxR4RBBxPSrbszu5/bQQw+ljTfeuGoaBwDMLYQSAECtiOAgei7EdIWJEyfmpo2xHGcs31kRvRNiSsMmm2ySJk+enMOFU045per1aHgZN/CxCseYMWNSy5Ytc3XEH//4x6qGjxEcRDPJuImPY8R5tt5666rg4fzzz6+a5hFBRzSojHDjh6oZ9t9//zR06NCZhhIhgo4fcvLJJ+dHiGvp2rVrnpYR741lPiOAiM/ox3xuEbpU/5wAYG7RYFr19aQAAArp2bNnXtJz+PDhqS6K6oaYHhHLh1ZWwfi5xRKoUSUyatSo2X7PHXfckYOVaJwZvS0AYG6ipwQAwGxo27ZtXk40elr8UmJ6yYyadM5KVFcMGTJEIAHAXEmlBABQJ9T1SgkA4OcnlAAAAACKMH0DAAAAKEIoAQAAABQhlAAAAACKEEoAAAAARQglAAAAgCKEEgAAAEARQgkAAACgCKEEAAAAUIRQAgAAAEgl/H9ssMN2W/TSzQAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import numpy as np\n", "\n", "\n", "def n_nonzero_columns(X):\n", " \"\"\"Number of columns with at least one non-zero value in a CSR matrix.\n", "\n", " This is useful to count the number of features columns that are effectively\n", " active when using the FeatureHasher.\n", " \"\"\"\n", " return len(np.unique(X.nonzero()[1]))\n", "from sklearn.feature_extraction import FeatureHasher\n", "\n", "t0 = time()\n", "hasher = FeatureHasher(n_features=2**18)\n", "X = hasher.transform(token_freqs(d) for d in raw_data)\n", "duration = time() - t0\n", "dict_count_vectorizers[\"vectorizer\"].append(\n", " hasher.__class__.__name__ + \"\\non freq dicts\"\n", ")\n", "dict_count_vectorizers[\"speed\"].append(data_size_mb / duration)\n", "print(f\"done in {duration:.3f} s at {data_size_mb / duration:.1f} MB/s\")\n", "print(f\"Found {n_nonzero_columns(X)} unique tokens\")\n", "t0 = time()\n", "hasher = FeatureHasher(n_features=2**22)\n", "X = hasher.transform(token_freqs(d) for d in raw_data)\n", "duration = time() - t0\n", "\n", "print(f\"done in {duration:.3f} s at {data_size_mb / duration:.1f} MB/s\")\n", "print(f\"Found {n_nonzero_columns(X)} unique tokens\")\n", "t0 = time()\n", "hasher = FeatureHasher(n_features=2**18, input_type=\"string\")\n", "X = hasher.transform(tokenize(d) for d in raw_data)\n", "duration = time() - t0\n", "dict_count_vectorizers[\"vectorizer\"].append(\n", " hasher.__class__.__name__ + \"\\non raw tokens\"\n", ")\n", "dict_count_vectorizers[\"speed\"].append(data_size_mb / duration)\n", "print(f\"done in {duration:.3f} s at {data_size_mb / duration:.1f} MB/s\")\n", "print(f\"Found {n_nonzero_columns(X)} unique tokens\")\n", "import matplotlib.pyplot as plt\n", "\n", "fig, ax = plt.subplots(figsize=(12, 6))\n", "\n", "y_pos = np.arange(len(dict_count_vectorizers[\"vectorizer\"]))\n", "ax.barh(y_pos, dict_count_vectorizers[\"speed\"], align=\"center\")\n", "ax.set_yticks(y_pos)\n", "ax.set_yticklabels(dict_count_vectorizers[\"vectorizer\"])\n", "ax.invert_yaxis()\n", "_ = ax.set_xlabel(\"speed (MB/s)\")" ] }, { "cell_type": "markdown", "id": "83e7b545-4dc9-45c2-b5f4-31c2133d7d55", "metadata": {}, "source": [ "5. Сравнение с CountVectorizer. Метод представляет из себя токенизацию и частоты слов" ] }, { "cell_type": "code", "execution_count": 16, "id": "4cc0ea45-8784-400b-881a-312394c0335e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "done in 1.135 s at 5.5 MB/s\n", "Found 47885 unique terms\n", "done in 0.868 s at 7.2 MB/s\n" ] } ], "source": [ "from sklearn.feature_extraction.text import CountVectorizer\n", "\n", "t0 = time()\n", "vectorizer = CountVectorizer()\n", "vectorizer.fit_transform(raw_data)\n", "duration = time() - t0\n", "dict_count_vectorizers[\"vectorizer\"].append(vectorizer.__class__.__name__)\n", "dict_count_vectorizers[\"speed\"].append(data_size_mb / duration)\n", "print(f\"done in {duration:.3f} s at {data_size_mb / duration:.1f} MB/s\")\n", "print(f\"Found {len(vectorizer.get_feature_names_out())} unique terms\")\n", "from sklearn.feature_extraction.text import HashingVectorizer\n", "\n", "t0 = time()\n", "vectorizer = HashingVectorizer(n_features=2**18)\n", "vectorizer.fit_transform(raw_data)\n", "duration = time() - t0\n", "dict_count_vectorizers[\"vectorizer\"].append(vectorizer.__class__.__name__)\n", "dict_count_vectorizers[\"speed\"].append(data_size_mb / duration)\n", "print(f\"done in {duration:.3f} s at {data_size_mb / duration:.1f} MB/s\")" ] }, { "cell_type": "markdown", "id": "1bd2ed6d-508d-42e1-a8e4-6344b6ff493e", "metadata": {}, "source": [ "6. HashingVectorizer. Комбинация CountVectorizer и FeatureHasher" ] }, { "cell_type": "code", "execution_count": 17, "id": "e8ed6734-a8fe-41ee-b3a3-cbb06e0e1752", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "done in 1.030 s at 6.1 MB/s\n" ] } ], "source": [ "from sklearn.feature_extraction.text import HashingVectorizer\n", "\n", "t0 = time()\n", "vectorizer = HashingVectorizer(n_features=2**18)\n", "vectorizer.fit_transform(raw_data)\n", "duration = time() - t0\n", "dict_count_vectorizers[\"vectorizer\"].append(vectorizer.__class__.__name__)\n", "dict_count_vectorizers[\"speed\"].append(data_size_mb / duration)\n", "print(f\"done in {duration:.3f} s at {data_size_mb / duration:.1f} MB/s\")\n" ] }, { "cell_type": "markdown", "id": "8e3bb2ef-af88-488d-850a-154951863d53", "metadata": {}, "source": [ "7. TF-IDF Vectorizer. Преобразуем частоты слов с учетом их значимости в коллекции документов" ] }, { "cell_type": "code", "execution_count": 18, "id": "756d27ac-f26f-421b-82ef-a6a60dbf90af", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "done in 1.334 s at 4.7 MB/s\n", "Found 47885 unique terms\n" ] } ], "source": [ "from sklearn.feature_extraction.text import TfidfVectorizer\n", "\n", "t0 = time()\n", "vectorizer = TfidfVectorizer()\n", "vectorizer.fit_transform(raw_data)\n", "duration = time() - t0\n", "dict_count_vectorizers[\"vectorizer\"].append(vectorizer.__class__.__name__)\n", "dict_count_vectorizers[\"speed\"].append(data_size_mb / duration)\n", "print(f\"done in {duration:.3f} s at {data_size_mb / duration:.1f} MB/s\")\n", "print(f\"Found {len(vectorizer.get_feature_names_out())} unique terms\")" ] }, { "cell_type": "markdown", "id": "ecd038f0-c024-4a0b-a7fc-bcf648eed2f6", "metadata": {}, "source": [ "8. Визуализация. Сравним производительность (MB/s) разных подходов" ] }, { "cell_type": "code", "execution_count": 19, "id": "391b055b-fa67-4d43-903a-e7ff512b69c2", "metadata": {}, "outputs": [ { "data": { "image/png": "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oEFp8cUXT4ceemg64IAD0tNPPz3daSPdunVLPXr0SP369cvTW7755pu87aSTTsrHKYUYEUacdtppaejQofmzV155JR100EE5dNhvv/3Sjz/+mLbZZpu0xRZbpOuuuy599NFHqU+fPjO9rl69eqXPP/88Pfroo7maJMKICEKmJ84TYczSSy+dRowYkatAXn755TR58uS0++67p1GjRqX77rsvPfTQQ3n/Jk2a5Pt28cUXp5tuuimtssoq6YsvvsjBCAAAANRkhQg9Jk2alIYNG5arFrbaaqv82ZVXXpkefPDB9Le//S0df/zxZfueffbZORQoBRcxdeXnn3/OwUVlERjUqVMnhx2lKSSl0KNv375pp512qtD7I0KQ0mdRlfHWW2+lK664IoceN9xwQw4eYjxxrggXoiLjsMMOm+51vffee+nee+/NFSJdunTJn8X3o5pkeuI8X3/9da5yKYU9HTp0KNse1xLXVH5KzNixY/P7CHgiWImKj3XWWWcW7jwAAABUX7WL0ncj+mpssMEGZZ/Fw3s8uL/99tsV9l199dXLfl5qqaXynzOqnJiemDJSPnSJMfTu3TuHCqXXWWedlT8PMY44d/lwZb311pvhOeI7EVCstdZaZZ/FtJmmTZtO9zsxVSYqTcpXt8zMrrvumv7zn/+k9u3b5+qUmHbz3//+d5a/DwAAANVRISo9Zkf5hqPR0yJEBcbsimkr5aeUlKpL1l133Qr7LbTQQml+it4fs6t169a5t0lMeYnqmMMPPzxdcMEF6fHHH6/SBq0AAACQFvRKj+WWWy4tvPDCFXpzROVHTPFYeeWV5/n5l1xyydz888MPP8xTScq/YppLiCkpr7/+ep5KU/Lcc8/N8LhR1REVF9FMtSTCie+//36634lqkqj2GD9+/DS3x336/fffpxmWRMPUIUOG5Kavzz77bHrjjTdm6foBAACgOipE6BFVF9EbI3p3RJPO6KUR0zR++umnPOVkfohVUc4999wcGkQvjggMhg8fni666KK8fc8998yVJTGuGN8999yTLrzwwhkec8UVV8xNVA855JC8+kqEHwceeOAMqzli1Zboz7HDDjvkECiCmGhUGiFGaNu2bW6iGsFI9CeJVW+iF0r0Cokmp7F/NFqNc8xomV4AAACo7goReoSBAwemnXfeOe2zzz6pc+fOedWW+++/PzVr1my+nD/CiFiyNoKO1VZbLTdLjTChVOkRPT7uvvvuHIZEz41YRea8886b6XHjeFFFEseLJqkHH3xwXpZ3eqKS44EHHsj7bL311nkscW9K02ziHkWQ0rVr17yCzY033ph7hMTUnOiJEpUiMc0lxtqiRYu5eIcAAABg/qo1ZcqUKfP5nPyfMWPG5FAklrddc801U001ceLEvPRt6763pNr1GlT1cABgrhgzsGdVDwEAmMlz6IQJE1Ljxo2LX+kBAAAAUJ7QAwAAACikBW7J2uokmoqaXQQAAADzhkoPAAAAoJCEHgAAAEAhCT0AAACAQhJ6AAAAAIUk9AAAAAAKSegBAAAAFJIla5lrRg3onho3blzVwwAAAIBMpQcAAABQSEIPAAAAoJCEHgAAAEAhCT0AAACAQhJ6AAAAAIUk9AAAAAAKSegBAAAAFJLQAwAAACgkoQcAAABQSEIPAAAAoJCEHgAAAEAh1anqAVAcq/a/P9Wu16CqhwEAAFDBmIE9q3oIVBGVHgAAAEAhCT0AAACAQhJ6AAAAAIUk9AAAAAAKSegBAAAAFJLQAwAAACgkoQcAAABQSEIPAAAAoJCEHgAAAEAhCT0AAACAQhJ6AAAAAIUk9AAAAAAKSehRELVq1Up33nlnVQ8DAAAAqo1qF3r06tUrP8BXfo0ePfoPH/uaa65JTZs2TdUhjIjr3GGHHebrWAAAAGBBUidVQz169EjDhw+v8Nniiy+eqpPffvst1a1bNxXZr7/+mhZeeOGqHgYAAAAUo9Ij1KtXL7Vs2bLCa6GFFkp33XVX6ty5c6pfv35q3759GjBgQPrvf/9b9r2LLroorbbaaqlhw4apdevW6fDDD08//vhj3vbYY4+l/fffP02YMKGseuT000+fbjVGVIREZUgYM2ZM3ufmm29Om2yyST7/9ddfn7ddddVVqWPHjvmzlVZaKV122WVzdM333Xdf2nDDDfN5W7RokbbZZpv0wQcfVAggjjzyyLTUUkvlc7Vp0yade+65FY7xzTffpB133DE1aNAgLb/88mnEiBEVto8aNSpttdVWadFFF01LLrlk2mefffJ3SjbddNN8jr59+6bFFlssde/efY6uBQAAAKqDahl6TMuTTz6Z9t1339SnT5/01ltvpSuuuCKHEmeffXbZPrVr105DhgxJb775Zrr22mvTI488kk444YS8bf3110+DBw9OjRs3TuPGjcuvfv36zdYYTjrppHz+t99+OwcCEXycdtppeQzx2TnnnJP+8pe/5HPPrkmTJqVjjz02vfjii+nhhx/O1xIBxuTJk/P2uK4IMW655Zb07rvv5nO3bdu2wjEiBNptt93S66+/nrbeeuu01157pfHjx+dt33//fdpss81Sp06d8jkiZPnyyy/z/uXF2KO64+mnn06XX375bF8HAAAAVBfVcnrLv/71r1yNUBLVCd99910OHfbbb7/8WVR6nHnmmTnU6N+/f/4sKhRKIhA466yz0qGHHpqrL+JBvkmTJrliIypH5kQcf6eddip7H+cdNGhQ2Wft2rUrC2RK4wx77LFHrlQp75dffkk9e/Yse7/zzjtX2H711VfnKT1xvFVXXTWNHTs2V29ENUhcQ1R6TKtPSJwrRAATQcnIkSPzdKGhQ4fmwCM+L3+OqIh577330gorrJA/i3Ocf/75c3R/AAAAoDqplqFH165d07Bhw8rex3SV1VdfPVcflK/s+P3339PPP/+cfvrppzyl46GHHspTPt555500ceLEPPWl/PY/au21165QmRHTT3r37p0OOuigss/jnBGulHfxxRenbt26VfjsxBNPzOMvef/993PVyPPPP5+nnJQqPCLsiNAjAo0tttgirbjiijnEiOkvW265ZYVjxj0qf8+iquWrr77K71977bX06KOPVgiTSuI6SqHHWmutNcf3BwAAAKqTahl6xAN7hw4dKnwWvTli+kb5SouS6HERfTciCDjssMNyMNK8efP01FNP5VAi+mHMKPSIyokpU6ZM1ah0WuMqP55w5ZVXpnXXXbfCfpWrOqKypPL1NGrUKE85Kdl2221z9UYcr1WrVjn0iLAjxh6il8lHH32U7r333hzuxLSUCFJuvfXWsmNUbqwa11UKT2K8cY7zzjtvquuKPiHTukYAAACoyapl6DEt8dAfvSwqhwclL730Un7Aj+km0Q8jRP+L8mKKS/nqipKYRhI9PspXXUR1yIxEI9AIJz788MPcO+OP+Pbbb/O1ReCx0UYb5c8isKksKjd23333/Npll11yxUf07IiAZ1bu32233Zan/dSpU2N+7QAAADDHaszTb0z9iEqOZZddNj/wR7ARUzZiRZLo3RFhSFRnXHrppbmiYVqNOOOBPyoeolHoGmuskas/4hUNPqPnxXrrrZdDkZh6MivL0UblydFHH52ns0QAEX06oklo9B+JpqSzqlmzZnnFlr/+9a+56iKmtET/kvJiZZrYFn054tr/+c9/5gqSWO1lVhxxxBE5VImeH9EHJYKS0aNHp5tuuimvQFO5OgUAAABquhqzekuslhINTh944IHUpUuX9Kc//Sn3yig19IwQI4KBmL4R00JidZPKS7rGCi7R2DQqJaK6o9SwM6pDoqFnVFnsueeeeVWXWekBcuCBB+bAYPjw4Xmp3FjONlaUiYamsyNCjAgfololxn7MMcekCy64YKrpMDHe6CsS1x/Tee65556yqpaZiaqUCIIi1IleIDHeaMwaocmsHgMAAABqklpTKjezgJmIipZ4lUTT2AiNWve9JdWu98cbxgIAAMxNYwb+v5UzKYZ4Do1ZFxMmTMitIKbHX/Ez26KCJv7hKr0i8AAAAIDqRujBbDv55JNzmlZ6ffLJJ1U9JAAAAKi5jUypPurVq5dfAAAAUJ2p9AAAAAAKSegxE++8805eKaZ+/fppzTXXTNVBLL07ePDgsve1atVKd955Z5WOCQAAAKob01tmon///qlhw4bp3XffTYsuumiqjsaNG5eaNWs2S/uefvrpOSB59dVX5/m4AAAAoCoJPWbigw8+SD179kxt2rSZ7j6//fZbqlu3bqoqLVu2rLJzAwAAQHVVmOktv/zySzr66KPTEksskaeibLjhhumFF14o2/7YY4/laSAPP/xwWnvttVODBg3S+uuvnys4pif2f+mll9IZZ5yRf44qiTFjxuSfb7755rTJJpvkc11//fV5/6uuuip17Ngxf7bSSiulyy67rMLxRo4cmTp16pS3xxjuuOOOfKwZVV189dVXadttt02LLLJIateuXdm5Ko+z/PSWTz/9NO2xxx6pefPmuUolzvX888+na665Jg0YMCC99tpr+Tvxis+mTJmSr23ZZZfNDUpbtWqV7yUAAADUZIWp9DjhhBPSbbfdlq699tpclXH++een7t27p9GjR+eH/5JTTjklDRo0KC2++OLp0EMPTQcccEB6+umnpzttpFu3bqlHjx6pX79+eXrLN998k7eddNJJ+TilECPCiNNOOy0NHTo0f/bKK6+kgw46KIcO++23X/rxxx/TNttsk7bYYot03XXXpY8++ij16dNnptfVq1ev9Pnnn6dHH300V5NEGBFByPTEeSKMWXrppdOIESNyFcjLL7+cJk+enHbfffc0atSodN9996WHHnoo79+kSZN83y6++OJ00003pVVWWSV98cUXORgBAACAmqwQocekSZPSsGHDctXCVlttlT+78sor04MPPpj+9re/peOPP75s37PPPjuHAqXgIqau/Pzzzzm4qCwCgzp16uSwozSFpBR69O3bN+20004Ven9ECFL6LKoy3nrrrXTFFVfk0OOGG27IwUOMJ84V4UJUZBx22GHTva733nsv3XvvvblCpEuXLvmz+H5Uk0xPnOfrr7/OVS6lsKdDhw5l2+Na4prKT4kZO3Zsfh8BTwQrUfGxzjrrzMKdBwAAgOqrdlH6bkRfjQ022KDss3h4jwf3t99+u8K+q6++etnPSy21VP5zRpUT0xNTRsqHLjGG3r1751Ch9DrrrLPy5yHGEecuH66st956MzxHfCcCirXWWqvss5g207Rp0+l+J6bKRKVJ+eqWmdl1113Tf/7zn9S+fftcnRLTbv773//O8vcBAACgOipEpcfsKN9wNHpahKjAmF0xbaX8lJJSdcm6665bYb+FFloozU/R+2N2tW7dOvc2iSkvUR1z+OGHpwsuuCA9/vjjVdqgFQAAANKCXumx3HLLpYUXXrhCb46o/IgpHiuvvPI8P/+SSy6Zm39++OGHeSpJ+VdMcwkxJeX111/PU2lKnnvuuRkeN6o6ouIimqmWRDjx/fffT/c7UU0S1R7jx4+f5va4T7///vs0w5JomDpkyJDc9PXZZ59Nb7zxxixdPwAAAFRHhQg9ouoiemNE745o0hm9NGKaxk8//ZSnnMwPsSrKueeem0OD6MURgcHw4cPTRRddlLfvueeeubIkxhXju+eee9KFF144w2OuuOKKuYnqIYcckldfifDjwAMPnGE1R6zaEv05dthhhxwCRRATjUojxAht27bNTVQjGIn+JLHqTfRCiV4h0eQ09o9Gq3GOGS3TCwAAANVdIUKPMHDgwLTzzjunffbZJ3Xu3Dmv2nL//fenZs2azZfzRxgRS9ZG0LHaaqvlZqkRJpQqPaLHx913353DkOi5EavInHfeeTM9bhwvqkjieNEk9eCDD87L8k5PVHI88MADeZ+tt946jyXuTWmaTdyjCFK6du2aV7C58cYbc4+QmJoTPVGiUiSmucRYW7RoMRfvEAAAAMxftaZMmTJlPp+T/zNmzJgcisTytmuuuWaqqSZOnJiXvm3d95ZUu16Dqh4OAABABWMG9qzqITCPnkMnTJiQGjduXPxKDwAAAIDyhB4AAABAIS1wS9ZWJ9FU1OwiAAAAmDdUegAAAACFJPQAAAAACknoAQAAABSS0AMAAAAoJKEHAAAAUEhCDwAAAKCQLFnLXDNqQPfUuHHjqh4GAAAAZCo9AAAAgEISegAAAACFJPQAAAAACknoAQAAABSS0AMAAAAoJKEHAAAAUEhCDwAAAKCQhB4AAABAIQk9AAAAgEISegAAAACFJPQAAAAACqlOVQ+A4li1//2pdr0GVT0MAACAamnMwJ5VPYQFjkoPAAAAoJCEHgAAAEAhCT0AAACAQhJ6AAAAAIUk9AAAAAAKSegBAAAAFJLQAwAAACgkoQcAAABQSEIPAAAAoJCEHgAAAEAhCT0AAACAQhJ6AAAAAIUk9CiIWrVqpTvvvLOqhwEAAADVRrULPXr16pUf4Cu/Ro8e/YePfc0116SmTZum6hBGxHXusMMO83UsAAAAsCCpk6qhHj16pOHDh1f4bPHFF0/VyW+//Zbq1q2biuzXX39NCy+8cFUPAwAAAIpR6RHq1auXWrZsWeG10EILpbvuuit17tw51a9fP7Vv3z4NGDAg/fe//y373kUXXZRWW2211LBhw9S6det0+OGHpx9//DFve+yxx9L++++fJkyYUFY9cvrpp0+3GiMqQqIyJIwZMybvc/PNN6dNNtkkn//666/P26666qrUsWPH/NlKK62ULrvssjm65vvuuy9tuOGG+bwtWrRI22yzTfrggw8qBBBHHnlkWmqppfK52rRpk84999wKx/jmm2/SjjvumBo0aJCWX375NGLEiArbR40albbaaqu06KKLpiWXXDLts88++Tslm266aT5H375902KLLZa6d+8+R9cCAAAA1UG1DD2m5cknn0z77rtv6tOnT3rrrbfSFVdckUOJs88+u2yf2rVrpyFDhqQ333wzXXvttemRRx5JJ5xwQt62/vrrp8GDB6fGjRuncePG5Ve/fv1mawwnnXRSPv/bb7+dA4EIPk477bQ8hvjsnHPOSX/5y1/yuWfXpEmT0rHHHptefPHF9PDDD+driQBj8uTJeXtcV4QYt9xyS3r33Xfzudu2bVvhGBEC7bbbbun1119PW2+9ddprr73S+PHj87bvv/8+bbbZZqlTp075HBGyfPnll3n/8mLsUd3x9NNPp8svv3y2rwMAAACqi2o5veVf//pXrkYoieqE7777LocO++23X/4sKj3OPPPMHGr0798/fxYVCiURCJx11lnp0EMPzdUX8SDfpEmTXLERlSNzIo6/0047lb2P8w4aNKjss3bt2pUFMqVxhj322CNXqpT3yy+/pJ49e5a933nnnStsv/rqq/OUnjjeqquumsaOHZurN6IaJK4hKj2m1SckzhUigImgZOTIkXm60NChQ3PgEZ+XP0dUxLz33ntphRVWyJ/FOc4///w5uj8AAABQnVTL0KNr165p2LBhZe9jusrqq6+eqw/KV3b8/vvv6eeff04//fRTntLx0EMP5Skf77zzTpo4cWKe+lJ++x+19tprV6jMiOknvXv3TgcddFDZ53HOCFfKu/jii1O3bt0qfHbiiSfm8Ze8//77uWrk+eefz1NOShUeEXZE6BGBxhZbbJFWXHHFHGLE9Jctt9yywjHjHpW/Z1HV8tVXX+X3r732Wnr00UcrhEklcR2l0GOttdaa4/sDAAAA1Um1DD3igb1Dhw4VPoveHDF9o3ylRUn0uIi+GxEEHHbYYTkYad68eXrqqadyKBH9MGYUekTlxJQpU6ZqVDqtcZUfT7jyyivTuuuuW2G/ylUdUVlS+XoaNWqUp5yUbLvttrl6I47XqlWrHHpE2BFjD9HL5KOPPkr33ntvDndiWkoEKbfeemvZMSo3Vo3rKoUnMd44x3nnnTfVdUWfkGldIwAAANRk1TL0mJZ46I9eFpXDg5KXXnopP+DHdJPohxGi/0V5McWlfHVFSUwjiR4f5asuojpkRqIRaIQTH374Ye6d8Ud8++23+doi8Nhoo43yZxHYVBaVG7vvvnt+7bLLLrniI3p2RMAzK/fvtttuy9N+6tSpMb92AAAAmGM15uk3pn5EJceyyy6bH/gj2IgpG7EiSfTuiDAkqjMuvfTSXNEwrUac8cAfFQ/RKHSNNdbI1R/xigaf0fNivfXWy6FITD2ZleVoo/Lk6KOPztNZIoCIPh3RJDT6j0RT0lnVrFmzvGLLX//611x1EVNaon9JebEyTWyLvhxx7f/85z9zBUms9jIrjjjiiByqRM+P6IMSQcno0aPTTTfdlFegqVydAgAAADVdjVm9JVZLiQanDzzwQOrSpUv605/+lHtllBp6RogRwUBM34hpIbG6SeUlXWMFl2hsGpUSUd1RatgZ1SHR0DOqLPbcc8+8qsus9AA58MADc2AwfPjwvFRuLGcbK8pEQ9PZESFGhA9RrRJjP+aYY9IFF1ww1XSYGG/0FYnrj+k899xzT1lVy8xEVUoEQRHqRC+QGG80Zo3QZFaPAQAAADVJrSmVm1nATERFS7xKomlshEat+96Satf74w1jAQAAimjMwP+3gid/TDyHxqyLCRMm5FYQ0+Ov+JltUUET/3CVXhF4AAAAQHUj9GC2nXzyyTlNK70++eSTqh4SAAAA1NxGplQf9erVyy8AAACozlR6AAAAAIUk9KgBatWqle68886qHgYAAADUKEKP+Uh4AQAAAPOP0COl9Ntvv1X1EAAAAIAFKfT45Zdf0tFHH52WWGKJVL9+/bThhhumF154oWz7Y489lqsnHn744bT22munBg0apPXXXz+9++670z3mmDFj8nduvvnmtMkmm+TjXn/99enbb79Ne+yxR1p66aXzcVZbbbV04403ln3vX//6V2ratGn6/fff8/tXX301H+ekk04q2+fAAw9Me++99zTP27Zt2/znjjvumL9Xeh+GDRuWlltuubTwwgunFVdcMf3jH/+Y4X3p379/WmqppdLrr7+e3z/11FNpo402SossskhePjbu2aRJkyqc+5xzzkkHHHBAatSoUVp22WXTX//617Ltv/76azryyCPzMeN+tGnTJi9LCwAAADVZtQ49TjjhhHTbbbela6+9Nr388supQ4cOqXv37mn8+PEV9jvllFPSoEGD0osvvpjq1KmTH+5nJsKKPn36pLfffjsf8+eff05rrbVW+ve//51GjRqVDj744LTPPvukkSNH5v0jVPjhhx/SK6+8kt8//vjjabHFFsvBS0l8tummm07zfKWwZvjw4WncuHFl7++44448juOOOy6f95BDDkn7779/evTRR6c6xpQpU9JRRx2V/v73v6cnn3wyrb766umDDz5IPXr0SDvvvHMOQSLMiRAkQozy4v5EMBTjP/zww9Nhhx1WFg4NGTIkjRgxIt1yyy35swiByocyAAAAUBPVmhJP0tVQVCo0a9YsXXPNNWnPPfcsm4YSD+N9+/ZNxx9/fA4cunbtmh566KG0+eab533uueee1LNnz/Sf//wnVy1Mq9KjXbt2afDgwTlsmJFtttkmrbTSSunCCy/M7yMUiWqQfv365YqNLl26pAEDBuQqkQkTJqRlllkmvffee2n55Zef5vGiwiNCjh122KHssw022CCtssoqFSovdtttt3z9EcCUvvfPf/4zfzdCiwcffDBXpJSqSxZaaKF0xRVXlH0/Qo+oYoljxD2IexahTamCJH7lLVu2zGM/9NBDc2XIm2++me9jnGt2TZw4MTVp0iS17ntLql2vwWx/HwAAYEEwZmDPqh5CYZSeQ+NZvHHjxjWv0iMqGCLkiFCgpG7dummdddbJ1RnlRcVDSUzRCF999dUMjx9VD+XFtJUzzzwzT2tp3rx5WnTRRdP999+fxo4dW7ZPBAkRtERoEJUWO+20U+rYsWMOGaLKo1WrVtMNPKYnrqX8NYZ4X/kajznmmPT888+nJ554oizwCK+99loOhmK8pVdUrkyePDl99NFH07xHEWxE6FG6R7169crTdWJqTQQgDzzwwGxdAwAAAFRH1Tb0mB0RhpSUKhXioX9GGjZsWOH9BRdckC655JJ04okn5qklEQJEeBD9Lkpi6koEHBE0xDmjCiQ+iyAkQo8IReaVLbbYIn322Wc5iCnvxx9/zFNiYrylV4zv/fffz31CpnWPSvepdI86d+6cA5IIfaJCJipNdtlll3l2LQAAALBAhx6lxp5PP/102WdR+RG9MFZeeeW5fr44z/bbb58bka6xxhqpffv2eapKeaW+HhdffHFZwFEKPeI1vX4e5YOHUiPUkqgUKX+NpbFUvsbtttsu3XDDDXk6y0033VT2eQQWb731Vu53UvkV929WRTnQ7rvvnq688srcFyR6qVTunQIAAAA1SZ1UTUUlRjTbjN4dMd0kVhw5//zz008//ZR69+49188X01JuvfXW9Mwzz+ReIhdddFH68ssvK4QP8XlME4lGn0OHDs2fbbzxxrkyIgKZmVV6RG+NWGkmpq/Uq1cvHy+uL77fqVOn1K1bt3T33Xen22+/PffXqCz6iERfjmiwGg1boxojKlP+9Kc/5calEYjEfYsQJPp+lMY4M3GtMS0oxlC7du3cPySmv8RqNQAAAFBTVdvQIwwcODBPwYiH/KiwiD4cMb0jwoK57dRTT00ffvhhntISS9bG6i3RcDSaopQXwUZMISlVdUQgE8FIBCTRE2NGYgWVY489NldTRF+OaKoa54hpNdEsNRqrRpPVWOFlelUjEXSU7kkEFNFXJKbWxAo2UYkS/UaiSiaqNmZVLGMbgVJMiYmmqNGgNRrCxvEBAACgpqq2q7dQc1i9BQAAYOas3jL31PjVWwAAAAD+CKEHAAAAUEhCDwAAAKCQhB4AAABAIQk9AAAAgEISegAAAACFJPQAAAAACknoAQAAABSS0AMAAAAopDpVPQCKY9SA7qlx48ZVPQwAAADIVHoAAAAAhST0AAAAAApJ6AEAAAAUktADAAAAKCShBwAAAFBIQg8AAACgkIQeAAAAQCEJPQAAAIBCEnoAAAAAhST0AAAAAApJ6AEAAAAUUp2qHgDFsWr/+1Pteg2qehgAACygxgzsWdVDAKoZlR4AAABAIQk9AAAAgEISegAAAACFJPQAAAAACknoAQAAABSS0AMAAAAoJKEHAAAAUEhCDwAAAKCQhB4AAABAIQk9AAAAgEISegAAAACFJPQAAAAACknoAQAAABSS0AMAAAAoJKEHAAAAUEhCDwAAAKCQhB4AAABAIQk9AAAAgEISegAAAACFJPSowR577LFUq1at9P3331f1UAAAAKDame+hxxdffJGOOuqo1L59+1SvXr3UunXrtO2226aHH354vo4jwoI777yz7P2gQYNSs2bN0s8//zzVvj/99FNq3LhxGjJkyFw/7x+x/vrrp3HjxqUmTZrMleMBAABAkczX0GPMmDFprbXWSo888ki64IIL0htvvJHuu+++1LVr13TEEUekqrTPPvukSZMmpdtvv32qbbfeemv69ddf0957752qi99++y0tvPDCqWXLljlImRfimgEAAKCmmq+hx+GHH54f0EeOHJl23nnntMIKK6RVVlklHXvssem5557L+4wdOzZtv/32adFFF83VFbvttlv68ssvy47Rq1evtMMOO1Q4bt++fdOmm25a9j5+Pvroo9MJJ5yQmjdvnoOB008/vWx727Zt85877rhjHk+8X2KJJXLFydVXXz3VuOOzOGcc65NPPsljatq0aX4fY40wp/L+cV1RybLUUkulI488crrnLRk2bFhabrnlcpCx4oorpn/84x8Vjhn7xz7bbbddatiwYTr77LOnmt4S1x3vK79K44v9DjzwwLT44ovne7vZZpul1157rewccY/WXHPNdNVVV6V27dql+vXrz9bvFwAAABbI0GP8+PG5qiMqOuKhvbIIESZPnpxDhNj38ccfTw8++GD6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//B55mZY07p16zRu3Li06qqrzpXjAQAAQNFUu0qPWbH44ounBg0azLXjbbfddqlFixbp2muvnWrbE088kUaPHp169+6dqotff/01hzQtW7ZMderUmSfn+P3339PkyZPnybEBAACgRoYe3377bdpjjz3S0ksvnYOJ1VZbLd14440V9rn11lvz54ssskgOG7p165YmTZpUYZ8LL7wwLbXUUnn7EUcckX777bfpVkxElclVV12Vdtxxx3zOqMwYMWJEhePF+/i8fv36qWvXrjngKFWn1K1bN+2zzz7pmmuumep6rr766rTuuuumVVZZJe974IEH5tClcePGabPNNkuvvfZahf3vvvvu1KVLl3yexRZbLI8pbLrppunjjz9OxxxzTD5vvMpXmsTx69Wrl69t0KBBFY4Zn5155plp3333zeeNKpfK01uiCqd03PKvqMIJv/zyS+rXr1/+vTRs2DBfU2lbiGtv2rRpvk8rr7xyHsvYsWNn6XcOAAAAC0To8fPPP6e11lor/fvf/06jRo3KD+gRKIwcOTJvjykZEYoccMAB6e23384P3jvttFOaMmVK2TEeffTR9MEHH+Q/I5yIB/JpBRLlDRgwIO22227p9ddfT1tvvXXaa6+90vjx4/O2jz76KO2yyy55ak6EFIccckg65ZRTKnw/Kjnef//9XNlR8uOPP+aAplTlseuuu6avvvoq3Xvvvemll15KnTt3TptvvnnZeeKaI+SI87/yyivp4YcfTuuss07edvvtt6dlllkmnXHGGfkexCvEcWLcf/7zn9Mbb7yRTj/99PSXv/xlquuNEGiNNdbIx43tlV1yySVlx41Xnz590hJLLJFWWmmlvP3II49Mzz77bLrpppvyPYpr6dGjR77mkp9++imdd955OUB688038/enJQKUiRMnVngBAABAdVNrSvm0YSaimuC6667LVQyVp0JE2PHdd9/laoHKttlmm/zwHQ/uL7/8cg5FolKhTZs20zxHBCEResQUjhChQO3atfMDe6nyoW/fvvmVL6JWrXTqqafmaogQVSOLLrpoDifiwf6kk07KgUSECiWx/9lnn11hzOutt15accUVywKHqPI46qij0hdffJHDkp49e+bQI6ogSjp06JBOOOGEHO6sv/76qX379vkeTUvlcYcIZ77++uv0wAMPlH0Wx4vxRvBQ+l6nTp3SHXfcUbZP3L927drlEGTNNdescJ4IWOK4Dz30UNpggw1yxUaMK/5s1apV2X5RYROhzDnnnJOvef/998+VIxGuzEgEMxEyVda67y2pdr25N+0IAACA+WfMwJ6ppoi/fG/SpEmaMGFCnhEx1yo9YmpIPBiXf0VlQPkAJMKHmL7SvHnzHD7cf//9ZVMl4oE6qiNie1QbXHnllTl4KC+mepQCjxDTXCJsmJHVV1+97OeYvhEXXfrOu+++m6eclFeqwCgvqk+isuOHH34oCz1ijI0aNcqhR1R+xHSbuKbSK6pIIqAJcS/i2mZHVLtEMFFevI8KjLiXJWuvvfYsHS9CkKisGTp0aNlxI+yJY62wwgoVxv7444+XjT0svPDCFe7j9Jx88sn5H6zS65NPPpmNKwYAAID5Y7a7YEagENUN5X366adlP19wwQV5qkX03IhgI/aPyoZovhkizHjwwQfTM888k6sbLr300jzV5Pnnn8+VCyF6bJQXlRwza6o5J9+pLKaYRM+NW265JW288cbp6aefTueee27eFoFHhC/l+2CUlCpFokfJvBL3cWaiIiWaskbfkfKNV2Pscd9jKk35MClE+FES4y/fa2R6otKlfLULAAAAVEdzfemPCAq23377tPfee+f3ETy89957uTlmSTxYRxVCvE477bQ8zSWmbsyNZWGnJaas3HPPPVMte1tZVHREZUdUeEQFRFRGbLTRRnlb9O+IUCFWS4npJtMSVRLRxyOmiUxLVFKUr94IHTt2zPesvHgf564cUMxITC+K+x7TiC666KIK22JqTJw3Kl9K1wMAAABFN9cbmcYKKaVKjpi6EU1Dv/zyy7LtUdERPSRefPHFPOUl+k9ET4t4+J9XYgzvvPNOOvHEE3MAE5Ucpb4dlSsbokIixn755Zfn6S7l+19Ez49ohhoVKtFTI/aLKpW4ltC/f/+8Uk38Gdce00qiMWhJhCXRKPWzzz5L33zzTf7suOOOy0FJTAmKsUXj1piaEiutzO41xjSTIUOG5PsZAU28osImApTo8RGrv8T9jik50Vg2qliidwgAAAAU0VwPPaJBaFRFdO/ePS/T2rJlyxwUlESvjXjwjxVO4mE89o8lWrfaaqs0r8S0mejVEQ/8UY0xbNiwstVbKk/T2HDDDXNlSDRFiZCgJMKRqBaJaS9RyRFjj+kwsQztkksumfeJ6/3nP/+Zl32N5qKxpG1p1ZoQK7dEWLLccsvlZW9D3KsIYaJJ66qrrporX2K/aOg6O6I/R6zaEhU1MQ2n9IpgJgwfPjxfT4QscX3xO4lql2WXXfYP3FkAAAAoyOotRRIrt0Q1hyacc69rrtVbAAAAaq4xBVy9Za739KiuLrvssryCS6y+Ej0zouHqkUceWdXDAgAAAOaRBSb0iCVgzzrrrDR+/Pg8pSOmecTSqwAAAEAxLTChx8UXX5xfAAAAwIJhrjcyBQAAAKgOhB4AAABAIQk9AAAAgEISegAAAACFJPQAAAAACknoAQAAABSS0AMAAAAoJKEHAAAAUEhCDwAAAKCQhB4AAABAIQk9AAAAgEISegAAAACFJPQAAAAACknoAQAAABSS0AMAAAAopDpVPQCKY9SA7qlx48ZVPQwAAADIVHoAAAAAhST0AAAAAApJ6AEAAAAUktADAAAAKCShBwAAAFBIQg8AAACgkIQeAAAAQCEJPQAAAIBCEnoAAAAAhST0AAAAAApJ6AEAAAAUktADAAAAKKQ6VT0AimPV/ven2vUaVPUwAACA/zNmYM+qHgJUKZUeAAAAQCEJPQAAAIBCEnoAAAAAhST0AAAAAApJ6AEAAAAUktADAAAAKCShBwAAAFBIQg8AAACgkIQeAAAAQCEJPQAAAIBCEnoAAAAAhST0AAAAAApJ6AEAAAAUktADAAAAKCShBwAAAFBIQg8AAACgkIQeAAAAQCEJPQAAAIBCqnahR69evdIOO+www33atm2bBg8enBZkY8aMSbVq1UqvvvpqVQ8FAAAAan7oMb1A4rHHHssP4N9//32aH1544YV08MEHz7Xj3XbbbWmhhRZKn3322TS3L7/88unYY4/9w+eZm2FN69at07hx49Kqq646V44HAAAARVPtKj1mxeKLL54aNGgw14633XbbpRYtWqRrr712qm1PPPFEGj16dOrdu3eqLn799dcc0rRs2TLVqVNnnpzj999/T5MnT54nxwYAAIAaGXp8++23aY899khLL710DiZWW221dOONN1bY59Zbb82fL7LIIjls6NatW5o0aVKFfS688MK01FJL5e1HHHFE+u2336ZbMRFVJldddVXacccd8zmjMmPEiBEVjhfv4/P69eunrl275oCjVJ1St27dtM8++6Rrrrlmquu5+uqr07rrrptWWWWVvO+BBx6YQ5fG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KCShBwAAAFBIQg8AAACgkIQeAAAAQCEJPQAAAIBCEnoAAAAAhST0AAAAAApJ6AEAAAAUUp2qHgDFMWpA99S4ceOqHgYAAABkKj0AAACAQhJ6AAAAAIUk9AAAAAAKSegBAAAAFJLQAwAAACgkoQcAAABQSEIPAAAAoJCEHgAAAEAhCT0AAACAQhJ6AAAAAIUk9AAAAAAKqU5VD4DiWLX//al2vQZVPQwAgPlizMCeVT0EAGZCpQcAAABQSEIPAAAAoJCEHgAAAEAhCT0AAACAQhJ6AAAAAIUk9AAAAAAKSegBAAAAFJLQAwAAACgkoQcAAABQSEIPAAAAoJCEHgAAAEAhCT0AAACAQhJ6AAAAAIUk9AAAAAAKSegBAAAAFJLQAwAAACgkoQcAAABQSEIPAAAAoJCEHgAAAEAh1cjQ4+mnn06rrbZaqlu3btphhx3SY489lmrVqpW+//776X7nmmuuSU2bNq3w2V//+tfUunXrVLt27TR48OBU08zKdQMAAMCCqlqFHvEAP6PX6aefnvc79thj05prrpk++uijHGasv/76ady4calJkyazfK6JEyemI488Mp144onps88+S5MmTUrNmjVLP//881T7/vTTT6lx48ZpyJAhc+Ua77zzzjQ3zMl1AwAAwIKiWoUe8QBfekXlRQQN5T/r169f3u+DDz5Im222WVpmmWVy9cbCCy+cWrZsmQOFWTV27Nj022+/pZ49e6allloqHXTQQTn4uP3226fa99Zbb02//vpr2nvvvVN1EWOfk+ueHXHNAAAAUFNVq9AjHuBLr6heiIf58p998803+bNvv/02HXDAAfnnqPSY1jSP+HzZZZdNDRo0SDvuuGP+TvltMT0mtG/fPn83qjm23XbbdPXVV081rvgsptE0b948ffLJJ2m33XbLYUu833777dOYMWOm2n+VVVZJ9erVy4FKVJSEtm3b5j9jPHHO0vswbNiwtNxyy+UgY8UVV0z/+Mc/Khwz9o99tttuu9SwYcN09tlnT3Xdm2666TQrZErji/0OPPDAtPjii+dAKYKj1157rewcUUkTFTRXXXVVateuXapfv/4f/I0CAABA1alWocfMRP+NqPiIB/aoBImfd99996n2e/7551Pv3r1z2PDqq6+mrl27prPOOqtse3znoYceyj+PHDkyHyeOHd955JFH0scff1y274cffpieeOKJvC2qK7p3754aNWqUnnzyydxbZNFFF009evQoq4qIYOKII45IBx98cHrjjTfSiBEjUocOHfK2F154If85fPjwfM7S+zvuuCP16dMnHXfccWnUqFHpkEMOSfvvv3969NFHK1xXhBIRmMRxI/SpLKpUylfG7LTTTjlAWXLJJfP2XXfdNX311Vfp3nvvTS+99FLq3Llz2nzzzdP48ePLjjF69Oh022235WPFvZuWX375JU8PKv8CAACA6qZOqkEWWmihsukcUQkSP0/LJZdckoOIE044Ib9fYYUV0jPPPJPuu+++/H6RRRZJLVq0yD9H1UPpOBFotGrVKocSpf4hURUSgUiEAzfccEOaPHlyroQoTSmJfaPqI6outtxyyxyuRHgRIUZJly5dys4VYv/yY7/wwgtTr1690uGHH17Ws+S5557Ln0dgU7LnnnvmMKR8IFNeVJ6UXHzxxTnAiQAorvepp57KAU+EHlGBUjpv9BeJ6TsR0oQIb/7+97+XjXVazj333DRgwIAZ/q4AAACgqtWoSo9Z9fbbb6d11123wmfrrbfeLIUq++23Xw46pkyZkgOOa6+9NgcNscJLTAWJSoio9IgKj3hF0BDNT6PPSAQKn3/+eQ5IZne8G2ywQYXP4n18Xt7aa689S8eLSo6TTjop3XzzzTnwCTH2H3/8MYc9pbHHK5rBxthL2rRpM8PAI5x88slpwoQJZa+Y8gMAAADVTY2q9JgfYtpIVDJElUSEHvFAX6quiNBgrbXWStdff/1U34ugIIKReSl6eczMW2+9lf785z+ngQMH5sqTkhh79BeJipTKyi/lOyvniEqRUrUIAAAAVFeFDD06duyYp3WUF9NFZkU0E91kk01yM9Ko9ujWrVuufgjRAyOqJ5ZYYoncV2Raojnpww8/XGFaSnl169ZNv//++1Tjjf4gUWVSEu9XXnnlNDui0Ws0Y915553TMcccU2FbjP2LL75IderUqdBAFQAAAIqqkNNbjj766Ny/I3pWvP/++2no0KFl/TxmRTQtjUae0WA0fi7Za6+90mKLLZZXbIlGpjE1JCon4nyffvpp3id6gQwaNCgNGTIkn/vll19Ol1566VShSAQQ3333Xf7s+OOPz1NqoglqfOeiiy7K5y8t0TurIuyI1WpiDHH80itClghvYopPrELzwAMP5BVdos/JKaeckl588cXZOg8AAADUBIUMPf70pz+lK6+8Mjc0XWONNfJD/qmnnjpb4UFM34gAIUKCkngfK7nEUrixMkpUaEQoEj09SpUfUa0RK8tcdtllednabbbZJgcZJRGIPPjgg7k5aqdOnfJncY4Ya4Q08Z0rrrgiN0iNJWhnR4wtVn+JypSYylJ6xRSdaLx6zz33pI033jhP14leHzENJlaqKa3uAgAAAEVSa0rM4YA/IJasjdV0Wve9JdWu16CqhwMAMF+MGdizqocAkBb059AJEyZMt/1EYSs9AAAAAIQeAAAAQCEJPQAAAIBCEnoAAAAAhST0AAAAAApJ6AEAAAAUktADAAAAKCShBwAAAFBIQg8AAACgkIQeAAAAQCEJPQAAAIBCEnoAAAAAhST0AAAAAApJ6AEAAAAUktADAAAAKCShBwAAAFBIQg8AAACgkIQeAAAAQCHVqeoBUByjBnRPjRs3ruphAAAAQKbSAwAAACgkoQcAAABQSEIPAAAAoJCEHgAAAEAhCT0AAACAQhJ6AAAAAIUk9AAAAAAKSegBAAAAFJLQAwAAACgkoQcAAABQSEIPAAAAoJCEHgAAAEAhCT0AAACAQhJ6AAAAAIUk9AAAAAAKSegBAAAAFJLQAwAAACgkoQcAAABQSEIPAAAAoJDqVPUAqPmmTJmS/5w4cWJVDwUAAIAFwMT/e/4sPY9Oj9CDP+zbb7/Nf7Zu3bqqhwIAAMAC5IcffkhNmjSZ7nahB39Y8+bN859jx46d4T9sFCNNjXDrk08+SY0bN67q4TAP+V0vOPyuFxx+1wsWv+8Fh9/1gsPvuqKo8IjAo1WrVmlGhB78YbVr//+tYSLw8C/fgiF+z37XCwa/6wWH3/WCw+96weL3veDwu15w+F3/P7Pyl+4amQIAAACFJPQAAAAACknowR9Wr1691L9///wnxeZ3veDwu15w+F0vOPyuFyx+3wsOv+sFh9/1nKk1ZWbruwAAAADUQCo9AAAAgEISegAAAACFJPQAAAAACknoAQAAABSS0IM/5H//939T27ZtU/369dO6666bRo4cWdVDYh544okn0rbbbptatWqVatWqle68886qHhLzyLnnnpu6dOmSGjVqlJZYYom0ww47pHfffbeqh8U8MGzYsLT66qunxo0b59d6662X7r333qoeFvPBwIED8/+W9+3bt6qHwlx2+umn599t+ddKK61U1cNiHvnss8/S3nvvnVq0aJEWWWSRtNpqq6UXX3yxqofFPBDPW5X/3Y7XEUccUdVDqxGEHsyxm2++OR177LF52aSXX345rbHGGql79+7pq6++quqhMZdNmjQp/34j5KLYHn/88fx/oM8991x68MEH02+//Za23HLL/M8AxbLMMsvkh9+XXnop/0fyZpttlrbffvv05ptvVvXQmIdeeOGFdMUVV+TAi2JaZZVV0rhx48peTz31VFUPiXngu+++SxtssEGqW7duDqzfeuutNGjQoNSsWbOqHhrz6H+7y/97Hf+NFnbdddeqHlqNYMla5lhUdsTfCA8dOjS/nzx5cmrdunU66qij0kknnVTVw2MeiVT5jjvuyBUAFN/XX3+dKz4iDNl4442rejjMY82bN08XXHBB6t27d1UPhXngxx9/TJ07d06XXXZZOuuss9Kaa66ZBg8eXNXDYi5XekQ15quvvlrVQ2Eei//Wfvrpp9OTTz5Z1UOhCkSl3r/+9a/0/vvv5/82Z8ZUejBHfv311/y3g926dSv7rHbt2vn9s88+W6VjA+aeCRMmlD0MU1y///57uummm3JFT0xzoZiiiqtnz54V/r+b4omHoJiO2r59+7TXXnulsWPHVvWQmAdGjBiR1l577fw3/fGXE506dUpXXnllVQ+L+fQcdt1116UDDjhA4DGLhB7MkW+++Sb/R/KSSy5Z4fN4/8UXX1TZuIC5J6q34m8Sonx21VVXrerhMA+88cYbadFFF0316tVLhx56aK7iWnnllat6WMwDEWrFVNTo20Oxq3CvueaadN999+W+PR999FHaaKON0g8//FDVQ2Mu+/DDD/PvePnll0/3339/Ouyww9LRRx+drr322qoeGvNYVHN9//33qVevXlU9lBqjTlUPAIDq+7fCo0aNMh+8wFZcccVcBh8VPbfeemvab7/98lQmwUexfPLJJ6lPnz55Dng0Hqe4ttpqq7Kfo29LhCBt2rRJt9xyi2lrBfyLiaj0OOecc/L7qPSI/8++/PLL8/+WU1x/+9vf8r/rUdHFrFHpwRxZbLHF0kILLZS+/PLLCp/H+5YtW1bZuIC548gjj8xzRR999NHc8JJiWnjhhVOHDh3SWmutlSsAomHxJZdcUtXDYi6L6ajRZDz6edSpUye/ItwaMmRI/jkqNymmpk2bphVWWCGNHj26qofCXLbUUktNFVB37NjRdKaC+/jjj9NDDz2UDjzwwKoeSo0i9GCO/0M5/iP54YcfrpA4x3vzwaHmit7WEXjENIdHHnkktWvXrqqHxHwU/zv+yy+/VPUwmMs233zzPJUpqnpKr/gb4uj3ED/HX2JQ3Oa1H3zwQX5Aplhi6mnlJeXfe++9XNlDcQ0fPjz3cIn+TMw601uYY7FcbZTPxX84rbPOOrkDfDTB23///at6aMyD/2gq/7dEMUc4/kM5mlsuu+yyVTo25v6UlhtuuCHdddddqVGjRmU9epo0aZIWWWSRqh4ec9HJJ5+cy2Pj3+GY7x+/98ceeyzPDadY4t/lyn15GjZsmFq0aKFfT8H069cvbbvttvnB9/PPP0/9+/fPodYee+xR1UNjLjvmmGPS+uuvn6e37LbbbmnkyJHpr3/9a35R3L+YiNAjnr+iSo9Z524xx3bfffe8nOVpp52WH4xi6btonFW5uSk134svvpi6du1aIfAK8T+60TCN4oimaGHTTTet8Hn8n6yGWcUS0x323XffNG7cuBxqxfz/CDy22GKLqh4aMIc+/fTTHHB8++23afHFF08bbrhheu655/LPFEuXLl1yVWYE2GeccUauzIy/gIwKLoopprXE9KVYtYXZU2tK1DIDAAAAFIyeHgAAAEAhCT0AAACAQhJ6AAAAAIUk9AAAAAAKSegBAAAAFJLQAwAAACgkoQcAAABQSEIPAID5YNNNN019+/ad6X4bb7xxuuGGG1J1ctJJJ6WjjjqqqocBALNN6AEAUE2MGDEiffnll+nPf/5z2Wdt27ZNtWrVSjfddNNU+6+yyip52zXXXDPV/vFaaKGFUqtWrVLv3r3Td999N9X3H3/88dS6deuZjqtfv37p2muvTR9++OEfuj4AmN+EHgAA1cSQIUPS/vvvn2rXrvifaBFMDB8+vMJnzz33XPriiy9Sw4YNpzrOGWeckcaNG5fGjh2brr/++vTEE0+ko48+eqr97rrrrrTtttvOdFyLLbZY6t69exo2bNgcXRcAVBWhBwBQKLfeemtabbXV0iKLLJJatGiRunXrliZNmpS39erVK+2www5pwIABafHFF0+NGzdOhx56aPr111/Lvj958uR07rnnpnbt2uVjrLHGGvmY5Y0aNSpttdVWadFFF01LLrlk2meffdI333xTtj3Ot+++++btSy21VBo0aNBMx/3111+nRx55ZJohxF577ZWrMj755JOyz66++ur8eZ06dabav1GjRqlly5Zp6aWXTl27dk377bdfevnll6dZWbLddtvN9L6FGNe0qk0AoDoTegAAhRHVDXvssUc64IAD0ttvv50ee+yxtNNOO6UpU6aU7fPwww+XbbvxxhvT7bffnkOQkgg8/v73v6fLL788vfnmm+mYY45Je++9dw4dwvfff58222yz1KlTp/Tiiy+m++67L09J2W233cqOcfzxx+f9o5LigQceyOeaVuhQ3lNPPZUaNGiQOnbsONW2CFai0iKmmISffvop3Xzzzfk6Z+azzz5Ld999d1p33XUrfB7X9tVXX+VrmZX7ts4666RPP/00jRkzZqbnBIDqYuq/GgAAqKHi4f2///1vfmBv06ZN/iyqF8pbeOGFc5VEBAzREyOmgkRIceaZZ6bffvstnXPOOemhhx5K6623Xt6/ffv2OZC44oor0iabbJKGDh2aA4/YrySOF1NQ3nvvvdxD429/+1u67rrr0uabb563R1ixzDLLzHDsH3/8cQ43Kk9tKYlA4rjjjkunnHJKrspYbrnl0pprrjnNfU888cR06qmnpt9//z39/PPPOfC46KKLKuwTgUwEKXE/ZuW+xXWVxhl9QwCgJlDpAQAURkxFiaAhHth33XXXdOWVV07VwDP2icCjJMKNH3/8MU8dGT16dK6i2GKLLfLUlNIrKj8++OCDvP9rr72WHn300QrbV1pppbwt9olXTJcpX1nRvHnztOKKK85w7P/5z39S/fr1p7u9Z8+eeZzRnyNClhlVeUSI8+qrr6bXX389V7aUvh8hSPnQozS1ZVbuW0x7CXF/AKCmUOkBABRGrFby4IMPpmeeeSZPK7n00ktzZcTzzz+fe3TMTIQK4d///nfuh1FevXr1yvaJ/hbnnXfeVN+P/h0RnMyJaBY6rRVWSqJ3R/QO6d+/f76eO+64Y4bH6tChQ/55+eWXT4MHD87hToQ10asjKjteeeWVHITM6n0bP358/jN6oQBATaHSAwAolFiqdYMNNsh9OuLBPqZvlA8IolIjqirKr4IS1RoxPWXllVfO4UasehKhQflXaWnXzp07534YMcWj8j6xkkpMO6lbt24ODEoizIipLzMSU2ZiNZYZBR9R3RG9QrbffvvUrFmzWb4nEWqE0nVHj4/1118/V6DM6n2L5q1xXTElCABqCpUeAEBhRNAQ0zm23HLLtMQSS+T3sSpK+eagMfWkd+/euedFNOWMyokjjzwy99KIVU/69euXm5fGKi4bbrhhmjBhQnr66afzSi+xCsoRRxyRp39E488TTjghBwdR3RErm1x11VU5QInjxxSTWAUlxhFVE9Pr1VE+9IgKjTjXNttsM8194jpilZjy03Om5YcffsgBSjQijWk7Mc6o0Iigo/KqLbN635588sm00UYblU1zAYCaQOgBABRGBBPR8yKmc0ycODE35YzlYmN52ZLoXRFTPjbeeOP0yy+/5PDi9NNPL9seDU0jIIhVXD788MPUtGnTXN3xP//zP2UNPSOYiGahERLEMeI8PXr0KAs2LrjggrJpMBGkRAPSCE9mVo2x//77p+uvv366oUeIIGVmTjvttPwKcS1dunTJ01biu7EMbQQccY9m575FqFP+PgFATVBrSvm1yAAACqxXr155ydk777wzVUdRnRHTR2J529IqKnNbLNEbVS5vvfXWLH/n3nvvzcFNNEaN3iIAUFPo6QEAUE20bNkyL3cbPUXmlZh+M60mrDMS1SHDhw8XeABQ46j0AAAWGNW90gMAmLuEHgAAAEAhmd4CAAAAFJLQAwAAACgkoQcAAABQSEIPAAAAoJCEHgAAAEAhCT0AAACAQhJ6AAAAAIUk9AAAAAAKSegBAAAApCL6/wCSRKww5svsggAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig, ax = plt.subplots(figsize=(12, 6))\n", "\n", "y_pos = np.arange(len(dict_count_vectorizers[\"vectorizer\"]))\n", "ax.barh(y_pos, dict_count_vectorizers[\"speed\"], align=\"center\")\n", "ax.set_yticks(y_pos)\n", "ax.set_yticklabels(dict_count_vectorizers[\"vectorizer\"])\n", "ax.invert_yaxis()\n", "_ = ax.set_xlabel(\"speed (MB/s)\")" ] }, { "cell_type": "markdown", "id": "ef9b977b-196d-4de7-8c29-0004a5c2e31e", "metadata": {}, "source": [ "Задание успешно выполнено. Метод HashingVectorizer оказался самым быстрым. Он особенно быстрый на больших объемах данных и не требует хранения словаря, т.е. каждый токен сразу преобразуется в индекс по хеш-функции" ] }, { "cell_type": "code", "execution_count": null, "id": "8f0e8c91-1de2-4839-aedb-618ffdc3f838", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "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.13.3" } }, "nbformat": 4, "nbformat_minor": 5 }