{ "cells": [ { "cell_type": "markdown", "id": "b13dc09f", "metadata": {}, "source": [ "# Lesson 44: TF-IDF parameter tuning activity\n", "\n", "In this activity, you will explore how different TF-IDF parameters affect text classification performance.\n", "\n", "1. **N-gram range** - Compare unigrams, bigrams, and trigrams\n", "2. **Vocabulary size** - Explore the effect of max_features\n", "3. **Document frequency filtering** - Use min_df and max_df parameters\n", "\n", "## Notebook set-up\n", "\n", "### Imports" ] }, { "cell_type": "code", "execution_count": null, "id": "deb282ad", "metadata": {}, "outputs": [], "source": [ "import nltk\n", "from nltk.corpus import movie_reviews\n", "from sklearn.feature_extraction.text import TfidfVectorizer\n", "from sklearn.model_selection import train_test_split\n", "from sklearn.naive_bayes import MultinomialNB\n", "from sklearn.metrics import accuracy_score\n", "\n", "nltk.download('movie_reviews', quiet=True)" ] }, { "cell_type": "markdown", "id": "b217e9d4", "metadata": {}, "source": [ "## 1. Load and prepare data" ] }, { "cell_type": "code", "execution_count": null, "id": "39de7cce", "metadata": {}, "outputs": [], "source": [ "# Load movie reviews\n", "documents = [\n", " (' '.join(movie_reviews.words(fileid)), category)\n", " for category in movie_reviews.categories()\n", " for fileid in movie_reviews.fileids(category)\n", "]\n", "\n", "texts = [doc[0] for doc in documents]\n", "labels = [1 if doc[1] == 'pos' else 0 for doc in documents]\n", "\n", "# Split data\n", "X_train, X_test, y_train, y_test = train_test_split(\n", " texts, labels, test_size=0.2, random_state=315\n", ")\n", "\n", "print(f'Training samples: {len(X_train)}')\n", "print(f'Testing samples: {len(X_test)}')" ] }, { "cell_type": "markdown", "id": "d32f5e3b", "metadata": {}, "source": [ "## 2. Helper function\n", "\n", "This function trains and evaluates a classifier with a given vectorizer configuration." ] }, { "cell_type": "code", "execution_count": null, "id": "4b530393", "metadata": {}, "outputs": [], "source": [ "def evaluate_vectorizer(vectorizer, X_train, X_test, y_train, y_test):\n", " '''Train Naive Bayes with given vectorizer and return accuracy and vocab size.'''\n", " \n", " X_train_vec = vectorizer.fit_transform(X_train)\n", " X_test_vec = vectorizer.transform(X_test)\n", " \n", " model = MultinomialNB()\n", " model.fit(X_train_vec, y_train)\n", " predictions = model.predict(X_test_vec)\n", " \n", " accuracy = accuracy_score(y_test, predictions)\n", " vocab_size = len(vectorizer.vocabulary_)\n", " \n", " return accuracy, vocab_size" ] }, { "cell_type": "markdown", "id": "4c2d99a3", "metadata": {}, "source": [ "## 3. N-gram range experiment\n", "\n", "### Task 1: Compare unigrams, bigrams, and combinations\n", "\n", "Complete the code below to test different n-gram ranges and observe their effect on accuracy.\n", "\n", "**Hints:**\n", "- `ngram_range=(1, 1)` uses only unigrams (single words)\n", "- `ngram_range=(1, 2)` uses unigrams and bigrams\n", "- `ngram_range=(2, 2)` uses only bigrams" ] }, { "cell_type": "code", "execution_count": null, "id": "2212cdd6", "metadata": {}, "outputs": [], "source": [ "# TODO: Define n-gram configurations to test\n", "ngram_configs = [\n", " # YOUR CODE HERE - add tuples like (1, 1), (1, 2), (2, 2), (1, 3)\n", "]\n", "\n", "print('N-gram range comparison:\\n')\n", "for ngram_range in ngram_configs:\n", "\n", " # TODO: Create TfidfVectorizer with this ngram_range\n", " vectorizer = None # YOUR CODE HERE\n", " \n", " # Evaluate\n", " accuracy, vocab_size = evaluate_vectorizer(\n", " vectorizer, X_train, X_test, y_train, y_test\n", " )\n", " \n", " print(f'ngram_range={ngram_range}: accuracy={accuracy:.4f}, vocab_size={vocab_size:,}')" ] }, { "cell_type": "markdown", "id": "73d7a469", "metadata": {}, "source": [ "## 4. Vocabulary size experiment\n", "\n", "### Task 2: Explore max_features parameter\n", "\n", "The `max_features` parameter limits vocabulary to the top N features. Test how this affects accuracy.\n", "\n", "**Hints:**\n", "- Try values like 100, 500, 1000, 5000, 10000, None (unlimited)\n", "- Consider the trade-off between model size and accuracy" ] }, { "cell_type": "code", "execution_count": null, "id": "87915988", "metadata": {}, "outputs": [], "source": [ "# TODO: Define max_features values to test\n", "max_features_values = [\n", " # YOUR CODE HERE - add values like 100, 500, 1000, 5000, 10000, None\n", "]\n", "\n", "print('max_features comparison:\\n')\n", "for max_features in max_features_values:\n", "\n", " # TODO: Create TfidfVectorizer with this max_features\n", " vectorizer = None # YOUR CODE HERE\n", " \n", " # Evaluate\n", " accuracy, vocab_size = evaluate_vectorizer(\n", " vectorizer, X_train, X_test, y_train, y_test\n", " )\n", " \n", " print(f'max_features={str(max_features):>6s}: accuracy={accuracy:.4f}, vocab_size={vocab_size:,}')" ] }, { "cell_type": "markdown", "id": "3b74bb40", "metadata": {}, "source": [ "## 5. Document frequency filtering\n", "\n", "### Task 3: Use min_df and max_df to filter terms\n", "\n", "- `min_df` removes terms appearing in fewer than N documents (or proportion)\n", "- `max_df` removes terms appearing in more than N documents (or proportion)\n", "\n", "**Your task:** Experiment with different combinations and observe the effect.\n", "\n", "**Hints:**\n", "- `min_df=5` means \"must appear in at least 5 documents\"\n", "- `max_df=0.95` means \"must appear in at most 95% of documents\"\n", "- These help remove rare typos and very common words" ] }, { "cell_type": "code", "execution_count": null, "id": "17e1b546", "metadata": {}, "outputs": [], "source": [ "# TODO: Define min_df/max_df configurations to test\n", "df_configs = [\n", " # YOUR CODE HERE - add tuples like (1, 1.0), (5, 0.95), (10, 0.8)\n", " # Format: (min_df, max_df)\n", "]\n", "\n", "print('Document frequency filtering comparison:\\n')\n", "for min_df, max_df in df_configs:\n", "\n", " # TODO: Create TfidfVectorizer with these parameters\n", " vectorizer = None # YOUR CODE HERE\n", " \n", " # Evaluate\n", " accuracy, vocab_size = evaluate_vectorizer(\n", " vectorizer, X_train, X_test, y_train, y_test\n", " )\n", " \n", " print(f'min_df={min_df}, max_df={max_df}: accuracy={accuracy:.4f}, vocab_size={vocab_size:,}')" ] }, { "cell_type": "markdown", "id": "4ac0907d", "metadata": {}, "source": [ "## 6. Analysis questions\n", "\n", "After completing the experiments above, answer these questions:\n", "\n", "1. Which n-gram configuration gave the best accuracy? Why?\n", "2. At what point does reducing max_features start hurting accuracy significantly?\n", "3. How do min_df and max_df affect both vocabulary size and accuracy?\n", "4. What combination of parameters would you recommend for a production system?" ] } ], "metadata": { "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 5 }