Иван Алексеев 79e6ec2ce9 вроде всё
2025-03-01 01:08:39 +04:00

472 lines
54 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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": "markdown",
"metadata": {},
"source": [
"# Начало лабораторной работы, ух"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Выгрузим документы и ресурсы NLTK\n",
"\n",
"Обработка текстов на естественном языке (Natural Language Processing, NLP) направление развития искусственного интеллекта и компьютерной лингвистики с целью разработки методов для понимания смысла текста и генерации грамотного текста.\n",
"\n",
"Популярные задачи:\n",
"\n",
"• Аннотирование и реферирование текстов\n",
"\n",
"• Проверка правописания\n",
"\n",
"• Машинный перевод\n",
"\n",
"• Понимание текста\n",
"\n",
"• Генерация текста\n",
"\n",
"• Вопросно-ответные системы\n",
"\n",
"NLTK (Natural Language Toolkit) — пакет библиотек и программ для символьной и статистической обработки естественного языка, написанных на Python.\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"[nltk_data] Downloading package stopwords to\n",
"[nltk_data] C:\\Users\\Admin\\AppData\\Roaming\\nltk_data...\n",
"[nltk_data] Package stopwords is already up-to-date!\n",
"[nltk_data] Downloading package punkt to\n",
"[nltk_data] C:\\Users\\Admin\\AppData\\Roaming\\nltk_data...\n",
"[nltk_data] Package punkt is already up-to-date!\n",
"[nltk_data] Downloading package wordnet to\n",
"[nltk_data] C:\\Users\\Admin\\AppData\\Roaming\\nltk_data...\n",
"[nltk_data] Package wordnet is already up-to-date!\n"
]
}
],
"source": [
"import os\n",
"import win32com.client\n",
"import re\n",
"import nltk\n",
"from nltk.corpus import stopwords\n",
"from nltk.stem import WordNetLemmatizer\n",
"from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer\n",
"from sklearn.cluster import KMeans\n",
"from sklearn.decomposition import PCA\n",
"import matplotlib.pyplot as plt\n",
"import spacy\n",
"from sklearn.model_selection import train_test_split\n",
"from sklearn.linear_model import LogisticRegression\n",
"from sklearn.metrics import accuracy_score, f1_score\n",
"\n",
"# Загрузка необходимых ресурсов NLTK\n",
"nltk.download('stopwords')\n",
"nltk.download('punkt')\n",
"nltk.download('wordnet')\n",
"\n",
"# Инициализация стоп-слов и лемматизатора\n",
"stop_words = set(stopwords.words('russian'))\n",
"lemmatizer = WordNetLemmatizer()\n",
"\n",
"# Загрузка модели spaCy для русского языка\n",
"nlp = spacy.load(\"ru_core_news_sm\")\n",
"\n",
"data_path = os.path.abspath(\".//static//csv//tz_itdocs\")\n",
"\n",
"if not os.path.exists(data_path):\n",
" raise FileNotFoundError(f\"Папка {data_path} не найдена.\")\n",
"\n",
"# Инициализация Word\n",
"word = win32com.client.Dispatch(\"Word.Application\")\n",
"word.visible = False\n",
"\n",
"texts = []\n",
"for filename in os.listdir(data_path):\n",
" if filename.endswith(\".doc\"):\n",
" file_path = os.path.join(data_path, filename)\n",
" try:\n",
" doc = word.Documents.Open(file_path)\n",
" text = doc.Content.Text\n",
" texts.append(text)\n",
" doc.Close(SaveChanges=False)\n",
" except Exception as e:\n",
" print(f\"Ошибка при чтении файла {filename}: {e}\")\n",
"word.Quit()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Применим методы предобработки текста\n",
"\n",
"Предобработка текста является важным этапом, на котором решаются следующие задачи:\n",
"1. Трансформация\n",
"2. Токенизация\n",
"3. Выделение частей речи (POS tagging)\n",
"4. Нормализация\n",
"5. Фильтрация\n",
"\n",
"Наш процесс предобработки будет выгялдеть следующим образом:\n",
"* Удаление спецсимволов(удаление из текста всех символов, которые не являются буквами или цифрами (например, знаки препинания, символы @, #, $, и т.д.))\n",
"* Приведение к нижнему регистру \n",
"* Токенизация(разделение текста на отдельные слова или токены (например, предложение разбивается на список слов))\n",
"* Удаление стоп-слов(удаление из текста слов, которые не несут смысловой нагрузки (например, предлоги, союзы, местоимения))\n",
"* Фильтрация по длине токенов(удаление из текста слов, которые слишком короткие (например, меньше 2 символов) или слишком длинные)\n",
"* Лемматизация по длине токенов(приведение слов к их начальной форме (лемме). Например, \"бежал\" → \"бежать\", \"кошки\" → \"кошка\")\n",
"* Удаление лишних пробелов\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"def preprocess_text(text):\n",
" # Удаление спецсимволов\n",
" text = re.sub(r'\\W+', ' ', text) # Удаляем все, кроме букв, цифр и пробелов\n",
" # Приведение к нижнему регистру\n",
" text = text.lower()\n",
" # Токенизация\n",
" tokens = text.split()\n",
" # Удаление стоп-слов, лемматизация и фильтрация по длине токенов\n",
" tokens = [\n",
" lemmatizer.lemmatize(word) \n",
" for word in tokens \n",
" if word not in stop_words and len(word) > 2\n",
" ]\n",
" # Удаление лишних пробелов\n",
" tokens = ' '.join(tokens).strip()\n",
" return tokens\n",
"\n",
"# Применение предобработки к каждому документу\n",
"texts = [preprocess_text(text) for text in texts]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Обработуем документы на основе лемматизации"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"def lemmatize_text(texts):\n",
" lemmatized_texts = []\n",
" for doc in nlp.pipe(texts):\n",
" lemmatized_texts.append(\" \".join([token.lemma_ for token in doc]))\n",
" return lemmatized_texts\n",
"\n",
"# Лемматизация текстов\n",
"lemmatized_texts = lemmatize_text(texts)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Удалим редкие и частые слова на основе лематизации"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [],
"source": [
"from sklearn.feature_extraction.text import TfidfVectorizer\n",
"\n",
"vectorizer = TfidfVectorizer(max_df=0.8, min_df=3, max_features=10000)\n",
"X_filtered = vectorizer.fit_transform(lemmatized_texts)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Формируем N-граммы\n",
"\n",
"Формирование N-грамм — это процесс разбиения текста на последовательности из N слов или символов. N-граммы широко используются в обработке NLP для анализа текста, построения языковых моделей, классификации текста и других задач.\n",
"\n",
"N-грамма — это последовательность из N элементов (слов, символов или других единиц).\n",
"\n",
"N — это число, которое определяет длину последовательности:\n",
"\n",
"* Униграммы (1-граммы): Отдельные слова или символы\n",
"\n",
"* Биграммы (2-граммы): Пары последовательных слов или символов\n",
"\n",
"* Триграммы (3-граммы): Тройки последовательных слов или символов\n",
"\n",
"И так далее.\n",
"\n",
"Зачем нужны N-граммы?\n",
"* Анализ контекста:\n",
"\n",
" N-граммы позволяют учитывать контекст слов. Например, биграммы помогают понять, как слова связаны друг с другом\n",
"\n",
"* Построение языковых моделей:\n",
"\n",
" N-граммы используются для создания моделей, которые предсказывают следующее слово в последовательности (например, в автодополнении)\n",
"\n",
"* Классификация текста:\n",
"\n",
" N-граммы могут использоваться как признаки для классификации текста (например, определение тематики или тональности)\n",
"\n",
"* Поиск шаблонов:\n",
"\n",
" N-граммы помогают находить часто встречающиеся последовательности слов или символов\n",
"\n",
"TF-IDF векторизация — это метод преобразования текстовых данных в числовые векторы, который учитывает важность слов в документе относительно всей коллекции документов (корпуса).\n",
"\n",
"* TF-IDF расшифровывается как Term Frequency-Inverse Document Frequency (Частота термина Обратная частота документа). Он состоит из двух компонентов:\n",
"* TF (Term Frequency):\n",
"\n",
" * Частота термина в документе.\n",
"\n",
" * Показывает, насколько часто слово встречается в конкретном документе.\n",
"\n",
" Формула:\n",
"\n",
" TF(t,d) = Количество вхождений термина t в документ d / Общее количество терминов в документе d\n",
"\n",
"* IDF (Inverse Document Frequency):\n",
"\n",
" * Обратная частота документа.\n",
"\n",
" * Показывает, насколько редким является слово во всей коллекции документов.\n",
"\n",
" Формула:\n",
" \n",
" IDF(t,D) = log(Общее количество документов в корпусе D / Количество документов, содержащих термин t)"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Количество признаков (N-грамм): 10000\n",
"Размерность данных N-грамм: (41, 10000)\n"
]
}
],
"source": [
"from sklearn.feature_extraction.text import TfidfVectorizer\n",
"\n",
"# Формирование N-грамм (одиночные слова до триады) с использованием TF-IDF векторизации\n",
"vectorizer_ngrams = TfidfVectorizer(ngram_range=(1, 3), max_features=10000)\n",
"\n",
"# Подготовка N-грамм из лемматизированных текстов\n",
"X_ngrams = vectorizer_ngrams.fit_transform(lemmatized_texts)\n",
"\n",
"print(f\"Количество признаков (N-грамм): {X_ngrams.shape[1]}\")\n",
"print(f\"Размерность данных N-грамм: {X_ngrams.shape}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Индексируем текст TF-IDF"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [],
"source": [
"tfidf_vectorizer = TfidfVectorizer(max_features=5000)\n",
"X_tfidf = tfidf_vectorizer.fit_transform(lemmatized_texts)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Выполним обучение модели с учителем или без учителя для решения задач. Оценим качество решений"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Обучаем модель и оцениеваем её качество с помощью кластеризации"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Силуэт-коэффициент: 0.09539462151298214\n"
]
},
{
"data": {
"image/png": "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SUlJOHbsGJo2bQogL1FRFAXNmzfXuczUqVMxevRorWkNGjTA559/jqeffrokYRLyurCfiL2DqKT7cLWzQ5uqIXy6NhERWR2j9FqqU6cOunXrhpdeeglLly5FTk4OJkyYgIEDB2p6LMXExKBz5874/vvvER4ejoCAAJ13a6pWrYpq1aoZI0yrdfzObUz9exuu3E/UTHOytcXLzZpjXLNwdm0nIiKrYbRxZFatWoWwsDB07twZPXr0QJs2bfD1119r5ufk5ODixYtIT083VggV0tn4OAz+bQ2uJd3Xmp6ek4O5kfvw+cEDZoqMiIio7ElCCGHuIMpSSkoK3N3dkZycXCEb/o7c+Bv23oiGWs9hVUkSDowcC19nZxNHRkREpF9pr9981pIVuZeejn+uR+lNYgBAAPj9Uul6lhEREZU3TGSsSGJGBoq6vaaSJNxNTzNJPERERMbGRMaK+Dg5oahmvGohEODiYpJ4iIiIjI2JjBXxdHRE52qhUBnolSRLEnrVDDNhVERERMbDRMbKvNGqDexVNpD1JDOvNG8JbycnE0dFRERkHExkrEwtbx+s6T8Q9X21n3Xl4eCA6e074uVmugckJCIiskRGGRCPzKuurx82DHwRFxLuIjopCS52dgivXAV2KpW5QyMiIipTTGSsWJiPL8J8in6kBBERkaVi1RIRERFZLCYyREREZLGYyBAREZHFYiJDREREFouJDBEREVksJjJERERksZjIEBERkcViIkNEREQWi4kMERERWSyrG9lXCAEASElJMXMkREREVFz51+3863hxWV0ik5qaCgAICgoycyRERERUUqmpqXB3dy92eUmUNPUp5xRFwe3bt+Hq6gpJkswdTomlpKQgKCgIN2/ehJubm7nDqbB4HMoHHgfz4zEoHyrCcRBCIDU1FYGBgZDl4rd8sbo7MrIso0qVKuYO47G5ublZ7clqSXgcygceB/PjMSgfrP04lOROTD429iUiIiKLxUSGiIiILBYTmXLG3t4e06dPh729vblDqdB4HMoHHgfz4zEoH3gc9LO6xr5ERERUcfCODBEREVksJjJERERksZjIEBERkcViIkNEREQWi4kMERERWSwmMuVAYmIiBg8eDDc3N3h4eGDUqFF48OBBsZYVQqB79+6QJAkbNmwwbqBWrqTHITExERMnTkTt2rXh6OiIqlWrYtKkSUhOTjZh1Jbviy++QEhICBwcHNC8eXMcPnzYYPm1a9ciLCwMDg4OaNCgAbZs2WKiSK1XSY7BsmXL0LZtW3h6esLT0xMRERFFHjMqnpJ+FvL98ssvkCQJffr0MW6A5RQTmXJg8ODBOHv2LLZv344//vgDe/bswZgxY4q17Pz58y3ymVLlUUmPw+3bt3H79m3MnTsXZ86cwYoVK7B161aMGjXKhFFbttWrV2Py5MmYPn06jh8/jkaNGqFr166Ij4/XWf7AgQMYNGgQRo0ahRMnTqBPnz7o06cPzpw5Y+LIrUdJj8Hu3bsxaNAg7Nq1C5GRkQgKCsJTTz2FmJgYE0duXUp6HPJFR0fjjTfeQNu2bU0UaTkkyKzOnTsnAIgjR45opv35559CkiQRExNjcNkTJ06IypUrizt37ggAYv369UaO1no9znEoaM2aNcLOzk7k5OQYI0yrEx4eLsaPH695r1arRWBgoJg1a5bO8gMGDBA9e/bUmta8eXMxduxYo8ZpzUp6DB6Vm5srXF1dxcqVK40VYoVQmuOQm5srWrVqJZYvXy6GDRsmnnnmGRNEWv7wjoyZRUZGwsPDA82aNdNMi4iIgCzLOHTokN7l0tPT8cILL+CLL75AQECAKUK1aqU9Do9KTk6Gm5sbbGys7nmsZS47OxvHjh1DRESEZposy4iIiEBkZKTOZSIjI7XKA0DXrl31lifDSnMMHpWeno6cnBx4eXkZK0yrV9rj8P7778PPz6/C3wXmt62ZxcbGws/PT2uajY0NvLy8EBsbq3e51157Da1atcIzzzxj7BArhNIeh4ISEhLwwQcfFLtasKJLSEiAWq2Gv7+/1nR/f39cuHBB5zKxsbE6yxf3GJG20hyDR7311lsIDAwslGBS8ZXmOOzbtw/ffPMNTp48aYIIyzfekTGSqVOnQpIkg6/iflE8atOmTdi5cyfmz59ftkFbIWMeh4JSUlLQs2dP1K1bFzNmzHj8wIkswOzZs/HLL79g/fr1cHBwMHc4FUZqaiqGDBmCZcuWwcfHx9zhmB3vyBjJ66+/juHDhxssU716dQQEBBRqzJWbm4vExES9VUY7d+7E1atX4eHhoTW9X79+aNu2LXbv3v0YkVsXYx6HfKmpqejWrRtcXV2xfv162NraPm7YFYKPjw9UKhXi4uK0psfFxend5wEBASUqT4aV5hjkmzt3LmbPno2///4bDRs2NGaYVq+kx+Hq1auIjo7G008/rZmmKAqAvDvJFy9eRGhoqHGDLk/M3UinostvZHr06FHNtG3bthlsZHrnzh1x+vRprRcAsWDBAnHt2jVThW5VSnMchBAiOTlZtGjRQrRv316kpaWZIlSrEh4eLiZMmKB5r1arReXKlQ029u3Vq5fWtJYtW7Kx72Mo6TEQQohPPvlEuLm5icjISFOEWCGU5DhkZGQUugY888wzolOnTuL06dMiKyvLlKGbHROZcqBbt26iSZMm4tChQ2Lfvn2iZs2aYtCgQZr5t27dErVr1xaHDh3Suw6w19JjK+lxSE5OFs2bNxcNGjQQV65cEXfu3NG8cnNzzfVnWJRffvlF2NvbixUrVohz586JMWPGCA8PDxEbGyuEEGLIkCFi6tSpmvL79+8XNjY2Yu7cueL8+fNi+vTpwtbWVpw+fdpcf4LFK+kxmD17trCzsxPr1q3TOudTU1PN9SdYhZIeh0dV5F5LTGTKgXv37olBgwYJFxcX4ebmJkaMGKH1pRAVFSUAiF27duldBxOZx1fS47Br1y4BQOcrKirKPH+EBVq0aJGoWrWqsLOzE+Hh4eLgwYOaee3btxfDhg3TKr9mzRpRq1YtYWdnJ+rVqyc2b95s4oitT0mOQXBwsM5zfvr06aYP3MqU9LNQUEVOZCQhhDB1dRYRERFRWWCvJSIiIrJYTGSIiIjIYjGRISIiIovFRIaIiIgsFhMZIiIislhMZIiIiMhiMZEhIiIii8VEhoiIiCwWExkiIiKyWExkiIiIyGIxkSEiIiKL9f+p1lx0T8e71QAAAABJRU5ErkJggg==",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"from sklearn.cluster import AgglomerativeClustering\n",
"from sklearn.metrics import silhouette_score\n",
"from sklearn.decomposition import PCA\n",
"import matplotlib.pyplot as plt\n",
"\n",
"# Кластеризация с использованием иерархической кластеризации\n",
"n_clusters = 9 \n",
"hierarchical_clustering = AgglomerativeClustering(n_clusters=n_clusters)\n",
"hierarchical_clustering.fit(X_tfidf.toarray()) # Преобразуем X_tfidf в массив, если это необходимо\n",
"\n",
"# Получение меток кластеров\n",
"cluster_labels = hierarchical_clustering.labels_\n",
"\n",
"# Оценка качества кластеризации\n",
"silhouette_avg = silhouette_score(X_tfidf.toarray(), cluster_labels) # Преобразуем X_tfidf в массив\n",
"print(f\"Силуэт-коэффициент: {silhouette_avg}\")\n",
"\n",
"# Визуализация кластеров\n",
"pca = PCA(n_components=2) \n",
"X_pca = pca.fit_transform(X_tfidf.toarray())\n",
"\n",
"plt.scatter(X_pca[:, 0], X_pca[:, 1], c=cluster_labels, cmap='viridis')\n",
"plt.title(\"Иерархичсекая кластеризация документов по тематике)\")\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"Значение силуэт коэффициента: от -1 до 0.25\t\n",
"\n",
"Интерпретация: плохая кластеризация. Кластеры плохо разделены или объекты ошибочно отнесены."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Обучаем модель и оцениеваем её качество с помощью классификации\n",
"\n",
"Разделим документы на 2 типа: техническое задание (ТЗ) и научную статью"
]
},
{
"cell_type": "code",
"execution_count": 57,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Точность модели: 0.56\n",
"F1-мера: 0.56\n"
]
}
],
"source": [
"from sklearn.model_selection import train_test_split\n",
"from sklearn.linear_model import LogisticRegression\n",
"from sklearn.metrics import accuracy_score, f1_score, classification_report\n",
"import numpy as np\n",
"\n",
"# Определяем метки для классификации: 0 - Техническое задание (ТЗ), 1 - статья\n",
"# Исходя из примера, создаем метки для 41 текста: 20 \"ТЗ\" и 21 \"статья\"\n",
"labels = [0, 1] * 20 + [0]\n",
"\n",
"# Разделение данных на обучающую и тестовую выборки (80% на обучение, 20% на тестирование)\n",
"X_train, X_test, y_train, y_test = train_test_split(X_tfidf, labels, test_size=0.2, random_state=51)\n",
"\n",
"# Инициализируем модель логистической регрессии с максимальным количеством итераций для достижения сходимости\n",
"model = LogisticRegression(max_iter=1000)\n",
"\n",
"# Обучаем модель на обучающей выборке\n",
"model.fit(X_train, y_train)\n",
"\n",
"# Выполняем предсказание на тестовой выборке\n",
"y_pred = model.predict(X_test)\n",
"\n",
"# Оценка производительности модели\n",
"accuracy = accuracy_score(y_test, y_pred)\n",
"f1 = f1_score(y_test, y_pred, average='weighted') # Используем взвешенное среднее для F1-меры\n",
"\n",
"# Выводим результаты оценки\n",
"print(f\"Точность модели: {accuracy:.2f}\")\n",
"print(f\"F1-мера: {f1:.2f}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Точность — доля правильно классифицированных объектов от общего числа объектов. Точность 0.56 означает, что модель правильно классифицировала 56% всех объектов. Это довольно низкий показатель, так как идеальная точность равна 1.0 (100% правильных предсказаний).\n",
"\n",
"F1-мера — это гармоническое среднее между точностью (Precision) и полнотой (Recall). Она учитывает как ложноположительные, так и ложноотрицательные ошибки.\n",
"\n",
"* Precision (Точность) — доля правильно предсказанных положительных классов среди всех предсказанных положительных классов.\n",
"\n",
"* Recall (Полнота) — доля правильно предсказанных положительных классов среди всех реальных положительных классов.\n",
"\n",
"F1-мера 0.56 указывает на то, что модель имеет среднее качество классификации. Это значение говорит о том, что модель плохо балансирует между точностью и полнотой. Например, она может либо пропускать много положительных примеров (низкий Recall), либо делать много ложноположительных предсказаний (низкий Precision).\n",
"\n",
"Точности указывают на то, что модель работает не очень хорошо. Это может быть связано с качеством данных, слабостью модели или дисбалансом классов. Для улучшения результатов необходимо проанализировать данные, попробовать более сложные модели и настроить гиперпараметры."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "aimenv",
"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.12.6"
}
},
"nbformat": 4,
"nbformat_minor": 2
}