{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n# Semi-supervised Classification on a Text Dataset\n\nIn this example, semi-supervised classifiers are trained on the 20 newsgroups\ndataset (which will be automatically downloaded).\n\nYou can adjust the number of categories by giving their names to the dataset\nloader or setting them to `None` to get all 20 of them.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Authors: The scikit-learn developers\n# SPDX-License-Identifier: BSD-3-Clause\n\nimport numpy as np\n\nfrom sklearn.datasets import fetch_20newsgroups\nfrom sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer\nfrom sklearn.linear_model import SGDClassifier\nfrom sklearn.metrics import f1_score\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.preprocessing import FunctionTransformer\nfrom sklearn.semi_supervised import LabelSpreading, SelfTrainingClassifier\n\n# Loading dataset containing first five categories\ndata = fetch_20newsgroups(\n subset=\"train\",\n categories=[\n \"alt.atheism\",\n \"comp.graphics\",\n \"comp.os.ms-windows.misc\",\n \"comp.sys.ibm.pc.hardware\",\n \"comp.sys.mac.hardware\",\n ],\n)\nprint(\"%d documents\" % len(data.filenames))\nprint(\"%d categories\" % len(data.target_names))\nprint()\n\n# Parameters\nsdg_params = dict(alpha=1e-5, penalty=\"l2\", loss=\"log_loss\")\nvectorizer_params = dict(ngram_range=(1, 2), min_df=5, max_df=0.8)\n\n# Supervised Pipeline\npipeline = Pipeline(\n [\n (\"vect\", CountVectorizer(**vectorizer_params)),\n (\"tfidf\", TfidfTransformer()),\n (\"clf\", SGDClassifier(**sdg_params)),\n ]\n)\n# SelfTraining Pipeline\nst_pipeline = Pipeline(\n [\n (\"vect\", CountVectorizer(**vectorizer_params)),\n (\"tfidf\", TfidfTransformer()),\n (\"clf\", SelfTrainingClassifier(SGDClassifier(**sdg_params), verbose=True)),\n ]\n)\n# LabelSpreading Pipeline\nls_pipeline = Pipeline(\n [\n (\"vect\", CountVectorizer(**vectorizer_params)),\n (\"tfidf\", TfidfTransformer()),\n # LabelSpreading does not support dense matrices\n (\"toarray\", FunctionTransformer(lambda x: x.toarray())),\n (\"clf\", LabelSpreading()),\n ]\n)\n\n\ndef eval_and_print_metrics(clf, X_train, y_train, X_test, y_test):\n print(\"Number of training samples:\", len(X_train))\n print(\"Unlabeled samples in training set:\", sum(1 for x in y_train if x == -1))\n clf.fit(X_train, y_train)\n y_pred = clf.predict(X_test)\n print(\n \"Micro-averaged F1 score on test set: %0.3f\"\n % f1_score(y_test, y_pred, average=\"micro\")\n )\n print(\"-\" * 10)\n print()\n\n\nif __name__ == \"__main__\":\n X, y = data.data, data.target\n X_train, X_test, y_train, y_test = train_test_split(X, y)\n\n print(\"Supervised SGDClassifier on 100% of the data:\")\n eval_and_print_metrics(pipeline, X_train, y_train, X_test, y_test)\n\n # select a mask of 20% of the train dataset\n y_mask = np.random.rand(len(y_train)) < 0.2\n\n # X_20 and y_20 are the subset of the train dataset indicated by the mask\n X_20, y_20 = map(\n list, zip(*((x, y) for x, y, m in zip(X_train, y_train, y_mask) if m))\n )\n print(\"Supervised SGDClassifier on 20% of the training data:\")\n eval_and_print_metrics(pipeline, X_20, y_20, X_test, y_test)\n\n # set the non-masked subset to be unlabeled\n y_train[~y_mask] = -1\n print(\"SelfTrainingClassifier on 20% of the training data (rest is unlabeled):\")\n eval_and_print_metrics(st_pipeline, X_train, y_train, X_test, y_test)\n\n print(\"LabelSpreading on 20% of the data (rest is unlabeled):\")\n eval_and_print_metrics(ls_pipeline, X_train, y_train, X_test, y_test)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.21" } }, "nbformat": 4, "nbformat_minor": 0 }