{ "cells": [ { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "###### Natural Language Processing & Machine Learning\n", "

\n", "
\n", "

SC 4125: Developing Data Products

\n", "

Module-6: Statistical tools for natural language processing and machine learning


\n", "\n", " \n", "
\n", "by Anwitaman DATTA
\n", "School of Computer Science and Engineering, NTU Singapore. \n", "
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "#### Teaching material\n", "- .html deck of slides\n", "- .ipynb Jupyter notebook" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Disclaimer/Caveat emptor\n", "\n", "- Non-systematic and non-exhaustive review\n", "- Illustrative approaches are not necessarily the most efficient or elegant, let alone unique" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Acknowledgement & Disclaimer\n", "\n", "> This module is based on some original fragments of codes mixed with code snippets from many different sources (books, blogs, git repos, documentations, videos, ...). The narrative in the module is also influenced from the many sources consulted. They have been referenced in-place in a best effort manner. Links to several third-party videos and reading references have also been provided.\n", "\n", "> If there are any attribution omissions to be rectified, or should anything in the material need to be changed or redacted, the copyright owners are requested to contact me at anwitaman@ntu.edu.sg " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Elementary concepts" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "from IPython.display import HTML" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "import nltk\n", "#nltk.download(\"book\") \n", "# We may use some of the existing corpora for some of our examples\n", "# see more about nltk's corpora at https://www.nltk.org/book/ch02.html \n", "#from nltk.book import * ## Not used finally\n", "\n", "#########\n", "\n", "import spacy\n", "nlp = spacy.load(\"en_core_web_sm\")\n", "#!python -m spacy download en_core_web_sm\n", "# see more about spaCy models at https://spacy.io/models" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Making a first sense: What comprises the data?\n", "\n", "> Encoding: e.g. UTF-8
\n", "> - ♞ to F6 \n", "> - Smöoy Frozen Yogurt\n", "\n", "> Cleaning the data\n", "> - e.g., using RegEx: We studied this in one of the early modules " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Tokenization: Granularity - Word, Sentence\n", "\n", "
\n", "
\n", " \"Neo4j\n", "
Image source: Spacy.io \n", "
\n" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "NYT_Headline = \"F.D.A. Panel Recommends Booster for Many Moderna Vaccine Recipients. Those eligible for the extra shot would include adults over 65 and others at high risk — the same groups now eligible for a Pfizer-BioNTech boost. By Sharon LaFraniere and Noah Weiland, Oct. 14, 2021\"\n", "\n", "EE1 =\"An alarming problem looms once more: Iran is rapidly advancing its nuclear programme; Israel is threatening military action against it; and America is seeking a diplomatic solution. Anton La Guardia, The Economist’s diplomatic editor, wrote about the international crisis this poses. Al-Monitor, a publication that covers the Middle East, has been monitoring the negotiations to revive a nuclear deal from 2015. It makes for a fiendish dilemma that the former French president, Nicolas Sarkozy, encapsulated thus: `an Iranian bomb or the bombing of Iran'. Iran doesn't yet have a nuclear weapon. But the situation is in many ways worse than in the past. The country is closer than ever to being able to make a nuke. One expert, David Albright, puts the `breakout time'—the time needed to make one bomb’s worth of highly enriched uranium—at just one month. Mr Albright’s book is one of the most detailed accounts of the Iranian programme, drawing on years of inspections by the International Atomic Energy Agency and a trove of Iranian documents obtained by Israeli intelligence. Another problem is that the credibility of American diplomacy has been damaged by Donald Trump’s repudiation of the nuclear deal. His successor, Joe Biden, is trying to revive it but Iran doesn’t seem to be interested. Robert Malley, America's special envoy on Iran, discusses the impasse in a recent interview. Iran claims it seeks nuclear energy only for civilian purposes. The trouble is that the technology used to make low-enriched uranium fuel for nuclear power stations is also used to make highly-enriched uranium for weapons. Whatever its ultimate aim, Iran’s regime attaches great national pride to its mastery of nuclear technology: “our moon shot” is how one Iranian official put it, according to “The Back Channel”, a memoir by William Burns, the head of the CIA who, as a diplomat, helped negotiate the nuclear deal.\"" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['An', 'alarming', 'problem', 'looms', 'once', 'more:', 'Iran', 'is', 'rapidly', 'advancing', 'its', 'nuclear', 'programme;', 'Israel', 'is', 'threatening', 'military', 'action', 'against', 'it;', 'and', 'America', 'is', 'seeking', 'a', 'diplomatic', 'solution.', 'Anton', 'La', 'Guardia,', 'The', 'Economist’s', 'diplomatic', 'editor,', 'wrote', 'about', 'the', 'international', 'crisis', 'this', 'poses.', 'Al-Monitor,', 'a', 'publication', 'that', 'covers', 'the', 'Middle', 'East,', 'has', 'been', 'monitoring', 'the', 'negotiations', 'to', 'revive', 'a', 'nuclear', 'deal', 'from', '2015.', 'It', 'makes', 'for', 'a', 'fiendish', 'dilemma', 'that', 'the', 'former', 'French', 'president,', 'Nicolas', 'Sarkozy,', 'encapsulated', 'thus:', '`an', 'Iranian', 'bomb', 'or', 'the', 'bombing', 'of', \"Iran'.\", 'Iran', \"doesn't\", 'yet', 'have', 'a', 'nuclear', 'weapon.', 'But', 'the', 'situation', 'is', 'in', 'many', 'ways', 'worse', 'than', 'in', 'the', 'past.', 'The', 'country', 'is', 'closer', 'than', 'ever', 'to', 'being', 'able', 'to', 'make', 'a', 'nuke.', 'One', 'expert,', 'David', 'Albright,', 'puts', 'the', '`breakout', \"time'—the\", 'time', 'needed', 'to', 'make', 'one', 'bomb’s', 'worth', 'of', 'highly', 'enriched', 'uranium—at', 'just', 'one', 'month.', 'Mr', 'Albright’s', 'book', 'is', 'one', 'of', 'the', 'most', 'detailed', 'accounts', 'of', 'the', 'Iranian', 'programme,', 'drawing', 'on', 'years', 'of', 'inspections', 'by', 'the', 'International', 'Atomic', 'Energy', 'Agency', 'and', 'a', 'trove', 'of', 'Iranian', 'documents', 'obtained', 'by', 'Israeli', 'intelligence.', 'Another', 'problem', 'is', 'that', 'the', 'credibility', 'of', 'American', 'diplomacy', 'has', 'been', 'damaged', 'by', 'Donald', 'Trump’s', 'repudiation', 'of', 'the', 'nuclear', 'deal.', 'His', 'successor,', 'Joe', 'Biden,', 'is', 'trying', 'to', 'revive', 'it', 'but', 'Iran', 'doesn’t', 'seem', 'to', 'be', 'interested.', 'Robert', 'Malley,', \"America's\", 'special', 'envoy', 'on', 'Iran,', 'discusses', 'the', 'impasse', 'in', 'a', 'recent', 'interview.', 'Iran', 'claims', 'it', 'seeks', 'nuclear', 'energy', 'only', 'for', 'civilian', 'purposes.', 'The', 'trouble', 'is', 'that', 'the', 'technology', 'used', 'to', 'make', 'low-enriched', 'uranium', 'fuel', 'for', 'nuclear', 'power', 'stations', 'is', 'also', 'used', 'to', 'make', 'highly-enriched', 'uranium', 'for', 'weapons.', 'Whatever', 'its', 'ultimate', 'aim,', 'Iran’s', 'regime', 'attaches', 'great', 'national', 'pride', 'to', 'its', 'mastery', 'of', 'nuclear', 'technology:', '“our', 'moon', 'shot”', 'is', 'how', 'one', 'Iranian', 'official', 'put', 'it,', 'according', 'to', '“The', 'Back', 'Channel”,', 'a', 'memoir', 'by', 'William', 'Burns,', 'the', 'head', 'of', 'the', 'CIA', 'who,', 'as', 'a', 'diplomat,', 'helped', 'negotiate', 'the', 'nuclear', 'deal.']\n" ] } ], "source": [ "# Word tokenization\n", "# Just split by space?\n", "print(EE1.split())" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "scrolled": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['An', 'alarming', 'problem', 'looms', 'once', 'more', ':', 'Iran', 'is', 'rapidly', 'advancing', 'its', 'nuclear', 'programme', ';', 'Israel', 'is', 'threatening', 'military', 'action', 'against', 'it', ';', 'and', 'America', 'is', 'seeking', 'a', 'diplomatic', 'solution', '.', 'Anton', 'La', 'Guardia', ',', 'The', 'Economist', '’', 's', 'diplomatic', 'editor', ',', 'wrote', 'about', 'the', 'international', 'crisis', 'this', 'poses', '.', 'Al-Monitor', ',', 'a', 'publication', 'that', 'covers', 'the', 'Middle', 'East', ',', 'has', 'been', 'monitoring', 'the', 'negotiations', 'to', 'revive', 'a', 'nuclear', 'deal', 'from', '2015', '.', 'It', 'makes', 'for', 'a', 'fiendish', 'dilemma', 'that', 'the', 'former', 'French', 'president', ',', 'Nicolas', 'Sarkozy', ',', 'encapsulated', 'thus', ':', '`', 'an', 'Iranian', 'bomb', 'or', 'the', 'bombing', 'of', 'Iran', \"'\", '.', 'Iran', 'does', \"n't\", 'yet', 'have', 'a', 'nuclear', 'weapon', '.', 'But', 'the', 'situation', 'is', 'in', 'many', 'ways', 'worse', 'than', 'in', 'the', 'past', '.', 'The', 'country', 'is', 'closer', 'than', 'ever', 'to', 'being', 'able', 'to', 'make', 'a', 'nuke', '.', 'One', 'expert', ',', 'David', 'Albright', ',', 'puts', 'the', '`', 'breakout', \"time'—the\", 'time', 'needed', 'to', 'make', 'one', 'bomb', '’', 's', 'worth', 'of', 'highly', 'enriched', 'uranium—at', 'just', 'one', 'month', '.', 'Mr', 'Albright', '’', 's', 'book', 'is', 'one', 'of', 'the', 'most', 'detailed', 'accounts', 'of', 'the', 'Iranian', 'programme', ',', 'drawing', 'on', 'years', 'of', 'inspections', 'by', 'the', 'International', 'Atomic', 'Energy', 'Agency', 'and', 'a', 'trove', 'of', 'Iranian', 'documents', 'obtained', 'by', 'Israeli', 'intelligence', '.', 'Another', 'problem', 'is', 'that', 'the', 'credibility', 'of', 'American', 'diplomacy', 'has', 'been', 'damaged', 'by', 'Donald', 'Trump', '’', 's', 'repudiation', 'of', 'the', 'nuclear', 'deal', '.', 'His', 'successor', ',', 'Joe', 'Biden', ',', 'is', 'trying', 'to', 'revive', 'it', 'but', 'Iran', 'doesn', '’', 't', 'seem', 'to', 'be', 'interested', '.', 'Robert', 'Malley', ',', 'America', \"'s\", 'special', 'envoy', 'on', 'Iran', ',', 'discusses', 'the', 'impasse', 'in', 'a', 'recent', 'interview', '.', 'Iran', 'claims', 'it', 'seeks', 'nuclear', 'energy', 'only', 'for', 'civilian', 'purposes', '.', 'The', 'trouble', 'is', 'that', 'the', 'technology', 'used', 'to', 'make', 'low-enriched', 'uranium', 'fuel', 'for', 'nuclear', 'power', 'stations', 'is', 'also', 'used', 'to', 'make', 'highly-enriched', 'uranium', 'for', 'weapons', '.', 'Whatever', 'its', 'ultimate', 'aim', ',', 'Iran', '’', 's', 'regime', 'attaches', 'great', 'national', 'pride', 'to', 'its', 'mastery', 'of', 'nuclear', 'technology', ':', '“', 'our', 'moon', 'shot', '”', 'is', 'how', 'one', 'Iranian', 'official', 'put', 'it', ',', 'according', 'to', '“', 'The', 'Back', 'Channel', '”', ',', 'a', 'memoir', 'by', 'William', 'Burns', ',', 'the', 'head', 'of', 'the', 'CIA', 'who', ',', 'as', 'a', 'diplomat', ',', 'helped', 'negotiate', 'the', 'nuclear', 'deal', '.']\n" ] } ], "source": [ "# word tokenization using nltk\n", "print(nltk.word_tokenize(EE1))" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[An, alarming, problem, looms, once, more, :, Iran, is, rapidly, advancing, its, nuclear, programme, ;, Israel, is, threatening, military, action, against, it, ;, and, America, is, seeking, a, diplomatic, solution, ., Anton, La, Guardia, ,, The, Economist, ’s, diplomatic, editor, ,, wrote, about, the, international, crisis, this, poses, ., Al, -, Monitor, ,, a, publication, that, covers, the, Middle, East, ,, has, been, monitoring, the, negotiations, to, revive, a, nuclear, deal, from, 2015, ., It, makes, for, a, fiendish, dilemma, that, the, former, French, president, ,, Nicolas, Sarkozy, ,, encapsulated, thus, :, `, an, Iranian, bomb, or, the, bombing, of, Iran, ', ., Iran, does, n't, yet, have, a, nuclear, weapon, ., But, the, situation, is, in, many, ways, worse, than, in, the, past, ., The, country, is, closer, than, ever, to, being, able, to, make, a, nuke, ., One, expert, ,, David, Albright, ,, puts, the, `, breakout, time'—the, time, needed, to, make, one, bomb, ’s, worth, of, highly, enriched, uranium, —, at, just, one, month, ., Mr, Albright, ’s, book, is, one, of, the, most, detailed, accounts, of, the, Iranian, programme, ,, drawing, on, years, of, inspections, by, the, International, Atomic, Energy, Agency, and, a, trove, of, Iranian, documents, obtained, by, Israeli, intelligence, ., Another, problem, is, that, the, credibility, of, American, diplomacy, has, been, damaged, by, Donald, Trump, ’s, repudiation, of, the, nuclear, deal, ., His, successor, ,, Joe, Biden, ,, is, trying, to, revive, it, but, Iran, does, n’t, seem, to, be, interested, ., Robert, Malley, ,, America, 's, special, envoy, on, Iran, ,, discusses, the, impasse, in, a, recent, interview, ., Iran, claims, it, seeks, nuclear, energy, only, for, civilian, purposes, ., The, trouble, is, that, the, technology, used, to, make, low, -, enriched, uranium, fuel, for, nuclear, power, stations, is, also, used, to, make, highly, -, enriched, uranium, for, weapons, ., Whatever, its, ultimate, aim, ,, Iran, ’s, regime, attaches, great, national, pride, to, its, mastery, of, nuclear, technology, :, “, our, moon, shot, ”, is, how, one, Iranian, official, put, it, ,, according, to, “, The, Back, Channel, ”, ,, a, memoir, by, William, Burns, ,, the, head, of, the, CIA, who, ,, as, a, diplomat, ,, helped, negotiate, the, nuclear, deal, .]\n" ] } ], "source": [ "# word tokenization using spaCy\n", "docEE = nlp(EE1) \n", "# This simple step creates a Doc object which has lot of information, some of which we will use subsequently \n", "print([token for token in docEE])" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "scrolled": false, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "['An alarming problem looms once more: Iran is rapidly advancing its nuclear programme; Israel is threatening military action against it; and America is seeking a diplomatic solution.',\n", " 'Anton La Guardia, The Economist’s diplomatic editor, wrote about the international crisis this poses.',\n", " 'Al-Monitor, a publication that covers the Middle East, has been monitoring the negotiations to revive a nuclear deal from 2015.',\n", " \"It makes for a fiendish dilemma that the former French president, Nicolas Sarkozy, encapsulated thus: `an Iranian bomb or the bombing of Iran'.\",\n", " \"Iran doesn't yet have a nuclear weapon.\",\n", " 'But the situation is in many ways worse than in the past.',\n", " 'The country is closer than ever to being able to make a nuke.',\n", " \"One expert, David Albright, puts the `breakout time'—the time needed to make one bomb’s worth of highly enriched uranium—at just one month.\",\n", " 'Mr Albright’s book is one of the most detailed accounts of the Iranian programme, drawing on years of inspections by the International Atomic Energy Agency and a trove of Iranian documents obtained by Israeli intelligence.',\n", " 'Another problem is that the credibility of American diplomacy has been damaged by Donald Trump’s repudiation of the nuclear deal.',\n", " 'His successor, Joe Biden, is trying to revive it but Iran doesn’t seem to be interested.',\n", " \"Robert Malley, America's special envoy on Iran, discusses the impasse in a recent interview.\",\n", " 'Iran claims it seeks nuclear energy only for civilian purposes.',\n", " 'The trouble is that the technology used to make low-enriched uranium fuel for nuclear power stations is also used to make highly-enriched uranium for weapons.',\n", " 'Whatever its ultimate aim, Iran’s regime attaches great national pride to its mastery of nuclear technology: “our moon shot” is how one Iranian official put it, according to “The Back Channel”, a memoir by William Burns, the head of the CIA who, as a diplomat, helped negotiate the nuclear deal.']" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Sentence tokenization using nltk\n", "nltk.sent_tokenize(EE1)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "[An alarming problem looms once more: Iran is rapidly advancing its nuclear programme; Israel is threatening military action against it; and America is seeking a diplomatic solution.,\n", " Anton La Guardia, The Economist’s diplomatic editor, wrote about the international crisis this poses.,\n", " Al-Monitor, a publication that covers the Middle East, has been monitoring the negotiations to revive a nuclear deal from 2015.,\n", " It makes for a fiendish dilemma that the former French president, Nicolas Sarkozy, encapsulated thus: `an Iranian bomb or the bombing of Iran'.,\n", " Iran doesn't yet have a nuclear weapon.,\n", " But the situation is in many ways worse than in the past.,\n", " The country is closer than ever to being able to make a nuke.,\n", " One expert, David Albright, puts the `breakout time'—the time needed to make one bomb’s worth of highly enriched uranium—at just one month.,\n", " Mr Albright’s book is one of the most detailed accounts of the Iranian programme, drawing on years of inspections by the International Atomic Energy Agency and a trove of Iranian documents obtained by Israeli intelligence.,\n", " Another problem is that the credibility of American diplomacy has been damaged by Donald Trump’s repudiation of the nuclear deal.,\n", " His successor, Joe Biden, is trying to revive it,\n", " but Iran doesn’t seem to be interested.,\n", " Robert Malley, America's special envoy on Iran, discusses the impasse in a recent interview.,\n", " Iran claims it seeks nuclear energy only for civilian purposes.,\n", " The trouble is that the technology used to make low-enriched uranium fuel for nuclear power stations is also used to make highly-enriched uranium for weapons.,\n", " Whatever its ultimate aim, Iran’s regime attaches great national pride to its mastery of nuclear technology: “our moon shot” is how one Iranian official put it, according to “The Back Channel”, a memoir by William Burns, the head of the CIA who, as a diplomat, helped negotiate the nuclear deal.]" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Sentence tokenization using spaCy\n", "[x for x in docEE.sents]" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['F.D.A.', 'Panel Recommends Booster for Many Moderna Vaccine Recipients.', 'Those eligible for the extra shot would include adults over 65 and others at high risk — the same groups now eligible for a Pfizer-BioNTech boost.', 'By Sharon LaFraniere and Noah Weiland, Oct. 14, 2021']\n", "\n", "[F.D.A. Panel Recommends Booster for Many Moderna Vaccine Recipients., Those eligible for the extra shot would include adults over 65 and others at high risk — the same groups now eligible for a Pfizer-BioNTech boost., By Sharon LaFraniere and Noah Weiland, Oct. 14, 2021]\n" ] } ], "source": [ "# Sentence tokenization: Further example\n", "# With the NYT headline example, the nltk model thinks F.D.A. is a sentence of its own!\n", "# This example is NOT to be used to conclude one toolkit's superiority over other. \n", "# More rigorous/exhaustive experiments are needed for that, and each excels for some or other tasks.\n", "# The only point I want to make with this example is the potential limitations in general of these black-box tools!\n", "\n", "print(nltk.sent_tokenize(NYT_Headline)) # nltk \n", "print()\n", "docNYT = nlp(NYT_Headline) # spaCy \n", "print([x for x in docNYT.sents])" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "> Normalization: Map text to a canonical representation. \n", "> - Examples:\n", "> * b4, Before, befor, before\n", "> * US, U.S.A., USA, United States, United States of America, ... \n", "> * 5th of November, 5 Nov., November 5, ...\n", "> * synonyms: Pfizer–BioNTech COVID-19 vaccine, Comirnaty, BNT162b2, ... \n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "> Normalization: Map text to a canonical representation. \n", "> - Some standard tools: \n", "> * Stemming: usually refers to a crude heuristic process that chops off the ends of words in the hope of achieving this goal correctly most of the time, and often includes the removal of derivational affixes. \n", "> * Lemmatization: usually refers to doing things properly with the use of a vocabulary and morphological analysis of words, normally aiming to remove inflectional endings only and to return the base or dictionary form of a word, which is known as the lemma.\n", "> * Definitions from Introduction to Information Retrieval\n", " by Manning et al. " ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "# Stemming and Lemmatization example with a list of words\n", "input_list = \"resting restful restless being is was am goodness goods\"\n", "words_list = input_list.lower().split(' ')" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "NLTK PorterStemmer ['rest', 'rest', 'restless', 'be', 'is', 'wa', 'am', 'good', 'good']\n", "NLTK SnowStemmer ['rest', 'rest', 'restless', 'be', 'is', 'was', 'am', 'good', 'good']\n" ] } ], "source": [ "# nltk includes multiple stemming algorithms, e.g., Porter, Snowball, ...\n", "## see more at https://www.nltk.org/api/nltk.stem.html\n", "porter = nltk.PorterStemmer()\n", "print(\"NLTK PorterStemmer\", [porter.stem(t) for t in words_list])\n", "##\n", "snowball = nltk.SnowballStemmer(\"english\")\n", "print(\"NLTK SnowStemmer\", [snowball.stem(t) for t in words_list])" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "NLTK Wordnet Lemmatizer ['resting', 'restful', 'restless', 'being', 'is', 'wa', 'am', 'goodness', 'good']\n" ] } ], "source": [ "# Wordnet based lemmatizer in nltk\n", "WNlemma = nltk.WordNetLemmatizer()\n", "print(\"NLTK Wordnet Lemmatizer\", [WNlemma.lemmatize(x) for x in words_list])" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[(10960894369163974213, 'rest'), (12859622076218287646, 'restful'), (15810880026682126118, 'restless'), (3899131925553995529, 'being'), (10382539506755952630, 'be'), (10382539506755952630, 'be'), (10382539506755952630, 'be'), (13871556783787251893, 'goodness'), (5711639017775284443, 'good')]\n" ] } ], "source": [ "# spaCy also returns hash of a lemma if you want e.g., convenient for aggregating, Map-Reduce, etc)\n", "list_variations=nlp(input_list)\n", "print([(x.lemma, x.lemma_) for x in list_variations])" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Ungraded task 6.1: Write a function which takes as input text, and returns a list of lemmatized tokens with stopwords and punctuations filtered out. \n", "\n", "Example output: ['alarming', 'problem', 'loom', 'Iran', ...]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Making sense of sentence structure: Part-of-speech (POS) tagging\n", "\n", "> Note: Need to be careful about which kinds of normalizations are carried out in earlier stages, since some of those have destructive effects on the semantics essential for making sense of the sentence, e.g., US versus us.\n", "\n", "\n", "> May need to detect/determine the language before this step (since the grammar rules are language dependent)." ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "F.D.A. Panel Recommends Booster for Many Moderna Vaccine Recipients. Those eligible for the extra shot would include adults over 65 and others at high risk — the same groups now eligible for a Pfizer-BioNTech boost. By Sharon LaFraniere and Noah Weiland, Oct. 14, 2021\n", "\n", "[('F.D.A', 'NNP'), ('.', '.'), ('Panel', 'NNP'), ('Recommends', 'VBZ'), ('Booster', 'NNP'), ('for', 'IN'), ('Many', 'NNP'), ('Moderna', 'NNP'), ('Vaccine', 'NNP'), ('Recipients', 'NNP'), ('.', '.'), ('Those', 'DT'), ('eligible', 'JJ'), ('for', 'IN'), ('the', 'DT'), ('extra', 'JJ'), ('shot', 'NN'), ('would', 'MD'), ('include', 'VB'), ('adults', 'NNS'), ('over', 'IN'), ('65', 'CD'), ('and', 'CC'), ('others', 'NNS'), ('at', 'IN'), ('high', 'JJ'), ('risk', 'NN'), ('—', 'VBP'), ('the', 'DT'), ('same', 'JJ'), ('groups', 'NNS'), ('now', 'RB'), ('eligible', 'VBP'), ('for', 'IN'), ('a', 'DT'), ('Pfizer-BioNTech', 'JJ'), ('boost', 'NN'), ('.', '.'), ('By', 'IN'), ('Sharon', 'NNP'), ('LaFraniere', 'NNP'), ('and', 'CC'), ('Noah', 'NNP'), ('Weiland', 'NNP'), (',', ','), ('Oct.', 'NNP'), ('14', 'CD'), (',', ','), ('2021', 'CD')]\n" ] } ], "source": [ "print(NYT_Headline +\"\\n\")\n", "NYT_postags=nltk.pos_tag(nltk.word_tokenize(NYT_Headline))\n", "print(NYT_postags)" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "NNP: noun, proper, singular\n", " Motown Venneboerger Czestochwa Ranzer Conchita Trumplane Christos\n", " Oceanside Escobar Kreisler Sawyer Cougar Yvette Ervin ODI Darryl CTCA\n", " Shannon A.K.C. Meltex Liverpool ...\n" ] } ], "source": [ "nltk.help.upenn_tagset(NYT_postags[0][1])\n", "# For full list, use nltk.help.upenn_tagset()" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "scrolled": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "[('F.D.A.', 'F.D.A.', 'PROPN', 'NNP'),\n", " ('Panel', 'Panel', 'PROPN', 'NNP'),\n", " ('Recommends', 'recommend', 'VERB', 'VBZ'),\n", " ('Booster', 'Booster', 'PROPN', 'NNP'),\n", " ('for', 'for', 'ADP', 'IN'),\n", " ('Many', 'many', 'ADJ', 'JJ'),\n", " ('Moderna', 'Moderna', 'PROPN', 'NNP'),\n", " ('Vaccine', 'Vaccine', 'PROPN', 'NNP'),\n", " ('Recipients', 'Recipients', 'PROPN', 'NNP'),\n", " ('.', '.', 'PUNCT', '.'),\n", " ('Those', 'those', 'DET', 'DT'),\n", " ('eligible', 'eligible', 'ADJ', 'JJ'),\n", " ('for', 'for', 'ADP', 'IN'),\n", " ('the', 'the', 'DET', 'DT'),\n", " ('extra', 'extra', 'ADJ', 'JJ'),\n", " ('shot', 'shot', 'NOUN', 'NN'),\n", " ('would', 'would', 'AUX', 'MD'),\n", " ('include', 'include', 'VERB', 'VB'),\n", " ('adults', 'adult', 'NOUN', 'NNS'),\n", " ('over', 'over', 'ADP', 'IN'),\n", " ('65', '65', 'NUM', 'CD'),\n", " ('and', 'and', 'CCONJ', 'CC'),\n", " ('others', 'other', 'NOUN', 'NNS'),\n", " ('at', 'at', 'ADP', 'IN'),\n", " ('high', 'high', 'ADJ', 'JJ'),\n", " ('risk', 'risk', 'NOUN', 'NN'),\n", " ('—', '—', 'PUNCT', ':'),\n", " ('the', 'the', 'DET', 'DT'),\n", " ('same', 'same', 'ADJ', 'JJ'),\n", " ('groups', 'group', 'NOUN', 'NNS'),\n", " ('now', 'now', 'ADV', 'RB'),\n", " ('eligible', 'eligible', 'ADJ', 'JJ'),\n", " ('for', 'for', 'ADP', 'IN'),\n", " ('a', 'a', 'DET', 'DT'),\n", " ('Pfizer', 'Pfizer', 'PROPN', 'NNP'),\n", " ('-', '-', 'PUNCT', 'HYPH'),\n", " ('BioNTech', 'BioNTech', 'PROPN', 'NNP'),\n", " ('boost', 'boost', 'NOUN', 'NN'),\n", " ('.', '.', 'PUNCT', '.'),\n", " ('By', 'by', 'ADP', 'IN'),\n", " ('Sharon', 'Sharon', 'PROPN', 'NNP'),\n", " ('LaFraniere', 'LaFraniere', 'PROPN', 'NNP'),\n", " ('and', 'and', 'CCONJ', 'CC'),\n", " ('Noah', 'Noah', 'PROPN', 'NNP'),\n", " ('Weiland', 'Weiland', 'PROPN', 'NNP'),\n", " (',', ',', 'PUNCT', ','),\n", " ('Oct.', 'Oct.', 'PROPN', 'NNP'),\n", " ('14', '14', 'NUM', 'CD'),\n", " (',', ',', 'PUNCT', ','),\n", " ('2021', '2021', 'NUM', 'CD')]" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# with spaCy\n", "[(token.text, token.lemma_, token.pos_, token.tag_) for token in docNYT]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Caution: Ambiguities" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "nltk: No verb!\n", "[('British', 'JJ'), ('Left', 'NNP'), ('Waffles', 'NNP'), ('on', 'IN'), ('Falkland', 'NNP'), ('Islands', 'NNP')]\n", "\n", "spaCy: The second meaning!\n", "[('British', 'NNP'), ('Left', 'VBD'), ('Waffles', 'NNP'), ('on', 'IN'), ('Falkland', 'NNP'), ('Islands', 'NNPS')]\n" ] } ], "source": [ "# POS taggers typically round up the usual suspects (i.e., looks at the most common usage of words)\n", "\n", "guardian_headline=\"British Left Waffles on Falkland Islands\"\n", "# What does it mean?\n", "# To waffle: to speak or write at length in a vague or trivial manner, fail to make up one's mind.\n", "# The British party of the left rambles indecisively about Falkland Island policy.\n", "# The British forces left behind waffles (the pastry) on the Falkland Islands.\n", "\n", "print('nltk: No verb!')\n", "print(nltk.pos_tag(nltk.word_tokenize(guardian_headline)))\n", "print()\n", "print('spaCy: The second meaning!')\n", "docG=nlp(guardian_headline)\n", "print([(token.text, token.tag_) for token in docG])\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Classification & topic modeling" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "### Classification and topic modeling \n", "\n", "> Features \n", "> - words, word sequences, numbers, dates, which normalizations to do/not do, capitalization, POS, grammatical structure \n", ">\n", "> See an example of features used for spam detection \n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Classification/Sentiment Analysis\n", "\n", "> We will use an IMDB reviews dataset from Kaggle for exploring a simple (only two classes, using balanced data) example of classification\n", "> https://www.kaggle.com/lakshmi25npathi/imdb-dataset-of-50k-movie-reviews" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "positive 25000\n", "negative 25000\n", "Name: sentiment, dtype: int64\n", " review sentiment\n", "8134 That's the worst film I saw since a long time.... 0\n", "5960 I remember this bomb coming out in the early 8... 0\n", "19706 Okay, I'll admit it--I am a goof-ball and I oc... 1\n", "12826 This film lingered and lingered at a small mov... 1\n", "39656 Two things haunt you throughout L'intrus (The ... 1\n" ] } ], "source": [ "import pandas as pd\n", "import numpy as np\n", "imdb_df = pd.read_csv('data/IMDBPolarDataset.csv')\n", "# Data from https://www.kaggle.com/lakshmi25npathi/imdb-dataset-of-50k-movie-reviews\n", "print(imdb_df['sentiment'].value_counts())\n", "#print()\n", "#print(imdb_df.sample(3))\n", "#print()\n", "imdb_df['sentiment'] = np.where(imdb_df['sentiment'] == 'positive', 1, 0)\n", "print(imdb_df.sample(5))\n", "imdb_df=imdb_df.sample(frac=0.2, random_state=0) \n", "# For scalability, it may make sense to use a smaller sample of data for the whole ML pipeline\n", "# You may have to experiment with the sample size to find a good balance" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Train and test \n", "- Cross-validation\n", " * Discussed in greater detail later in the module" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "from sklearn.model_selection import train_test_split\n", "\n", "# Split data into training and test sets\n", "X_train, X_test, y_train, y_test = train_test_split(imdb_df['review'], \n", " imdb_df['sentiment'], \n", " random_state=0,test_size=0.2)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "#### detour: CountVectorizer\n", "> Need to represent the information (features) in a manner that the ML algorithm can \"consume\"" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['and' 'document' 'first' 'fourth' 'is' 'not' 'one' 'second' 'the' 'this']\n", "[[0 1 1 0 1 0 0 0 1 1]\n", " [0 2 0 0 1 0 0 1 1 1]\n", " [1 0 0 1 1 1 1 0 1 1]\n", " [0 1 1 0 1 0 0 0 1 1]]\n", "(4, 10)\n" ] } ], "source": [ "# detour \n", "## Example code from https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.CountVectorizer.html\n", "\n", "from sklearn.feature_extraction.text import CountVectorizer\n", "corpus = [\n", " 'This is the first document.',\n", " 'This document is the second document.',\n", " 'And this is not the fourth one.',\n", " 'Is this the first document?',\n", "]\n", "vectorizer = CountVectorizer()\n", "X = vectorizer.fit_transform(corpus)\n", "print(vectorizer.get_feature_names_out())\n", "print(X.toarray())\n", "print(X.toarray().shape)" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['document' 'fourth' 'second']\n", "[[1 0 0]\n", " [2 0 1]\n", " [0 1 0]\n", " [1 0 0]]\n", "(4, 3)\n" ] } ], "source": [ "# if you want to exclude stop words\n", "## be careful for what you ask for: e.g., we lost 'not'\n", "vectorizerWSW = CountVectorizer(stop_words='english')\n", "X_WSW = vectorizerWSW.fit_transform(corpus)\n", "print(vectorizerWSW.get_feature_names_out())\n", "print(X_WSW.toarray())\n", "print(X_WSW.toarray().shape)" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "# if you want to customize your stopwords, you may want to start with the default, and see what you want to add/remove\n", "from sklearn.feature_extraction import text \n", "#print(sorted(list(text.ENGLISH_STOP_WORDS)))\n", "set_to_remove={\"no\",\"nor\",\"not\",\"none\",\"nooooo!\"}\n", "new_set=text.ENGLISH_STOP_WORDS - set_to_remove" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['document' 'fourth' 'not' 'second']\n", "[[1 0 0 0]\n", " [2 0 0 1]\n", " [0 1 1 0]\n", " [1 0 0 0]]\n", "(4, 4)\n" ] } ], "source": [ "## you can provide your own customized list\n", "vectorizerWSW = CountVectorizer(stop_words=new_set)\n", "X_WSW = vectorizerWSW.fit_transform(corpus)\n", "print(vectorizerWSW.get_feature_names_out())\n", "print(X_WSW.toarray())\n", "print(X_WSW.toarray().shape)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['document' 'document second' 'fourth' 'not' 'not fourth' 'second'\n", " 'second document']\n", "[[1 0 0 0 0 0 0]\n", " [2 1 0 0 0 1 1]\n", " [0 0 1 1 1 0 0]\n", " [1 0 0 0 0 0 0]]\n" ] } ], "source": [ "# if you want n-grams\n", "vectorizer2 = CountVectorizer(analyzer='word', ngram_range=(1, 2), stop_words=new_set)\n", "# you can use 'char' and ‘char_wb’ options for analyzer for character (and respectively, characters restricted to word boundaries) based n-grams\n", "X2 = vectorizer2.fit_transform(corpus)\n", "print(vectorizer2.get_feature_names_out())\n", "print(X2.toarray())" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Back to the IMDB data" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Number of tokens: 47536\n", "Runtime for vectorization fitting for Model 1: 1.4932281970977783 seconds\n", "Number of tokens: 660629\n", "Runtime for vectorization fitting for Model 2: 7.169947862625122 seconds\n", "Number of tokens: 30295\n", "Runtime for vectorization fitting for Model 1: 7.134037256240845 seconds\n" ] } ], "source": [ "import time\n", "start = time.time()\n", "cv = CountVectorizer().fit(X_train)\n", "# Other vectorizers are possible, e.g., TF-IDf \n", "print(f\"Number of tokens: {len(cv.get_feature_names_out())}\")\n", "end = time.time()\n", "print(f\"Runtime for vectorization fitting for Model 1: {end - start} seconds\")\n", "# Using words and word bi-grams \n", "start = time.time()\n", "cv2 = CountVectorizer(analyzer='word', ngram_range=(1, 2)).fit(X_train)\n", "print(f\"Number of tokens: {len(cv2.get_feature_names_out())}\")\n", "end = time.time()\n", "print(f\"Runtime for vectorization fitting for Model 2: {end - start} seconds\")\n", "# Remove tokens that don't appear in at least 5 reviews, or if it appears in more than 50% of the reviews. \n", "# Use upto word tri-grams.\n", "start = time.time()\n", "cv3 = CountVectorizer(min_df=5, max_df=0.5, ngram_range=(1, 3), stop_words=new_set).fit(X_train)\n", "print(f\"Number of tokens: {len(cv3.get_feature_names_out())}\")\n", "end = time.time()\n", "print(f\"Runtime for vectorization fitting for Model 1: {end - start} seconds\")" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Runtime for transforming training data for Model 1: 2.2858214378356934 seconds\n", "Runtime for transforming training data for Model 2: 5.156646728515625 seconds\n", "Runtime for transforming training data for Model 3: 3.6959545612335205 seconds\n" ] } ], "source": [ "start = time.time()\n", "X_train_vec = cv.transform(X_train)\n", "end = time.time()\n", "print(f\"Runtime for transforming training data for Model 1: {end - start} seconds\")\n", "#\n", "start = time.time()\n", "X_train_vec2 = cv2.transform(X_train)\n", "end = time.time()\n", "print(f\"Runtime for transforming training data for Model 2: {end - start} seconds\")\n", "#\n", "start = time.time()\n", "X_train_vec3 = cv3.transform(X_train)\n", "end = time.time()\n", "print(f\"Runtime for transforming training data for Model 3: {end - start} seconds\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "#### Detour: Logistic Regression" ] }, { "cell_type": "code", "execution_count": 90, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Third party content:\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "execution_count": 90, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from sklearn.linear_model import LogisticRegression \n", "print(\"Third party content:\")\n", "# The StatQuest channel has many nice, easy to understand at an intuitive level videos. \n", "# Check them up for a quick introduction/brush-up of the underlying ideas (without the mathematical details)\n", "HTML('')" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Runtime for training Model 1: 9.124244213104248 seconds\n", "Runtime for training Model 2: 56.488693714141846 seconds\n", "Runtime for training Model 3: 1.4204068183898926 seconds\n" ] } ], "source": [ "# Train the models \n", "start = time.time()\n", "model1 = LogisticRegression(max_iter=1000)\n", "model1.fit(X_train_vec, y_train)\n", "end = time.time()\n", "print(f\"Runtime for training Model 1: {end - start} seconds\")\n", "###\n", "start = time.time()\n", "model2 = LogisticRegression(max_iter=1000)\n", "model2.fit(X_train_vec2, y_train)\n", "end = time.time()\n", "print(f\"Runtime for training Model 2: {end - start} seconds\")\n", "###\n", "start = time.time()\n", "model3 = LogisticRegression(max_iter=1000)\n", "model3.fit(X_train_vec3, y_train)\n", "end = time.time()\n", "print(f\"Runtime for training Model 3: {end - start} seconds\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Detour: Accuracy, Confusion Matrix and ROC/AUC" ] }, { "cell_type": "code", "execution_count": 91, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Third party content on : AUC (Area Under The Curve) / ROC (Receiver Operating Characteristics)\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "execution_count": 91, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print(\"Third party content on : AUC (Area Under The Curve) / ROC (Receiver Operating Characteristics)\")\n", "HTML('')" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "from sklearn.metrics import accuracy_score\n", "from sklearn.metrics import roc_auc_score\n", "from sklearn.metrics import confusion_matrix \n", "from sklearn.metrics import ConfusionMatrixDisplay\n", "from sklearn.metrics import f1_score\n", "import matplotlib as mpl \n", "#import matplotlib.cm as cm \n", "import matplotlib.pyplot as plt \n", "#import itertools" ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "scrolled": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "AUC (model with words): 0.8600351134074928\n", "Accuracy (model with words): 0.859\n", "Runtime for predicting with Model 1: 0.661902904510498 seconds\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "# Predict the transformed test documents\n", "start = time.time()\n", "predictions1 = model1.predict(cv.transform(X_test))\n", "print('AUC (model with words): ', roc_auc_score(y_test, predictions1))\n", "print(\"Accuracy (model with words): \", accuracy_score(y_test, predictions1))\n", "end = time.time()\n", "print(f\"Runtime for predicting with Model 1: {end - start} seconds\")\n", "ConfusionMatrixDisplay.from_predictions(y_test,predictions1,normalize=\"true\",cmap=plt.cm.Blues)\n", "# Absolute numbers can be used by removing attribute normalize=\"true\"" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "# Alternative: Plotting using a precomputed confusion matrix\n", "cm = confusion_matrix(y_test, predictions1, labels=model1.classes_) \n", "# confusion_matrix can also use attribute normalize=\"true\"\n", "fig, ax = plt.subplots(figsize=(4,4))\n", "ConfusionMatrixDisplay(confusion_matrix=cm,display_labels=model1.classes_).plot(cmap=plt.cm.Blues,ax=ax) " ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "AUC (with word bigrams): 0.8801952770163418\n", "Accuracy (with word bigrams): 0.8795\n", "Runtime for predicting with Model 2: 2.022491455078125 seconds\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "# Using model 2 (words and word bi-grams)\n", "start = time.time()\n", "predictions2 = model2.predict(cv2.transform(X_test))\n", "print('AUC (with word bigrams): ', roc_auc_score(y_test, predictions2))\n", "print(\"Accuracy (with word bigrams): \", accuracy_score(y_test, predictions2))\n", "end = time.time()\n", "print(f\"Runtime for predicting with Model 2: {end - start} seconds\")\n", "ConfusionMatrixDisplay.from_predictions(y_test,predictions2,normalize=\"true\",cmap=plt.cm.Blues)" ] }, { "cell_type": "code", "execution_count": 34, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "AUC (with filtering and upto trigrams): 0.8735486675233028\n", "Accuracy (with filtering and upto trigrams): 0.873\n", "Runtime for predicting with Model 3: 1.1680829524993896 seconds\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "### Using words bi/tri-grams and frequency based filtering \n", "start = time.time()\n", "predictions3 = model3.predict(cv3.transform(X_test))\n", "print('AUC (with filtering and upto trigrams): ', roc_auc_score(y_test, predictions3))\n", "print(\"Accuracy (with filtering and upto trigrams): \", accuracy_score(y_test, predictions3))\n", "end = time.time()\n", "print(f\"Runtime for predicting with Model 3: {end - start} seconds\")\n", "ConfusionMatrixDisplay.from_predictions(y_test,predictions3,normalize=\"true\",cmap=plt.cm.Blues)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "#### Some other popular/baseline models for text classification" ] }, { "cell_type": "code", "execution_count": 92, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Third party content:\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "execution_count": 92, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# from nltk.classify import SklearnClassifier\n", "from sklearn.naive_bayes import MultinomialNB\n", "print(\"Third party content:\")\n", "HTML('')" ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Third party content:\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from sklearn.svm import SVC\n", "# The following YouTube video on Suppor Verctor Machines provides a very nice high level overview\n", "# Even if you are familiar with SVM/SVC, you may gain some nice perspectives \n", "# The presenter has a sense of humor (Bam!) which is a bit weird, but as long as you like/ignore it, the technical coverage for the intuitions is nice.\n", "print(\"Third party content:\")\n", "HTML('')" ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Runtime for fitting NB: 0.014167547225952148 seconds\n", "AUC (Naive): 0.8308722567024445\n", "Runtime for predicting with NB: 0.8845677375793457 seconds\n" ] } ], "source": [ "start = time.time()\n", "modelNB = MultinomialNB().fit(X_train_vec,y_train)\n", "end = time.time()\n", "print(f\"Runtime for fitting NB: {end - start} seconds\")\n", "#\n", "start = time.time()\n", "predictionsNB = modelNB.predict(cv.transform(X_test))\n", "print('AUC (Naive): ', roc_auc_score(y_test, predictionsNB))\n", "end = time.time()\n", "print(f\"Runtime for predicting with NB: {end - start} seconds\")\n" ] }, { "cell_type": "code", "execution_count": 38, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Runtime for fitting NB: 0.025911569595336914 seconds\n", "AUC (Naive): 0.8501495775073887\n", "Runtime for predicting with NB: 1.344125509262085 seconds\n" ] } ], "source": [ "start = time.time()\n", "modelNB = MultinomialNB().fit(X_train_vec3,y_train)\n", "end = time.time()\n", "print(f\"Runtime for fitting NB: {end - start} seconds\")\n", "start = time.time()\n", "predictionsNB = modelNB.predict(cv3.transform(X_test))\n", "print('AUC (Naive): ', roc_auc_score(y_test, predictionsNB))\n", "end = time.time()\n", "print(f\"Runtime for predicting with NB: {end - start} seconds\")" ] }, { "cell_type": "code", "execution_count": 39, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Runtime for fitting SVC: 48.139628410339355 seconds\n", "AUC (SVC): 0.8429310982003627\n", "Runtime for predicting with SVC: 9.894097089767456 seconds\n" ] } ], "source": [ "start = time.time()\n", "modelSVC = SVC(kernel=\"linear\").fit(X_train_vec,y_train)\n", "end = time.time()\n", "print(f\"Runtime for fitting SVC: {end - start} seconds\")\n", "#\n", "start = time.time()\n", "predictionsSVC = modelSVC.predict(cv.transform(X_test))\n", "print('AUC (SVC): ', roc_auc_score(y_test, predictionsSVC))\n", "end = time.time()\n", "print(f\"Runtime for predicting with SVC: {end - start} seconds\")" ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Runtime for fitting SVC: 39.08421754837036 seconds\n", "AUC (SVC): 0.8604116861746717\n", "Runtime for predicting with SVC: 8.268787860870361 seconds\n" ] } ], "source": [ "start = time.time()\n", "modelSVC = SVC(kernel=\"linear\").fit(X_train_vec3,y_train)\n", "end = time.time()\n", "print(f\"Runtime for fitting SVC: {end - start} seconds\")\n", "start = time.time()\n", "predictionsSVC = modelSVC.predict(cv3.transform(X_test))\n", "print('AUC (SVC): ', roc_auc_score(y_test, predictionsSVC))\n", "end = time.time()\n", "print(f\"Runtime for predicting with SVC: {end - start} seconds\")" ] }, { "cell_type": "code", "execution_count": 41, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "#from sklearn.datasets import fetch_20newsgroups\n", "#newsgroups_train = fetch_20newsgroups(subset='train')\n", "#print(newsgroups_train.target_names)\n", "# print(newsgroups_train.data[10])" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### A few words on ... \n", "\n", "> Word embedding: Dimensionality reduction\n", "\n", "\n", "> Using pretrained models" ] }, { "cell_type": "code", "execution_count": 42, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "# The following code on using embedding for vectorization is adapted from:\n", "# https://github.com/practical-nlp\n", "\n", "import os\n", "import wget\n", "import gzip\n", "import shutil\n", "\n", "gn_vec_path = \"GoogleNews-vectors-negative300.bin\"\n", "gn_vec_zip_path = \"GoogleNews-vectors-negative300.bin.gz\"\n", "if not os.path.exists(gn_vec_path):\n", " if not os.path.exists(gn_vec_zip_path): \n", " wget.download(\"https://s3.amazonaws.com/dl4j-distribution/GoogleNews-vectors-negative300.bin.gz\")\n", " with gzip.open(gn_vec_zip_path, 'rb') as f_in:\n", " with open(gn_vec_path, 'wb') as f_out:\n", " shutil.copyfileobj(f_in, f_out)" ] }, { "cell_type": "code", "execution_count": 43, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Numver of words in vocablulary: 3000000\n" ] } ], "source": [ "from gensim.models import Word2Vec, KeyedVectors\n", "pretrainedpath = gn_vec_path\n", "w2v_model = KeyedVectors.load_word2vec_format(pretrainedpath, binary=True) #load the model\n", "print(\"Numver of words in vocablulary: \",len(list(w2v_model.index_to_key)))#Number of words in the vocabulary." ] }, { "cell_type": "code", "execution_count": 44, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "300\n" ] }, { "data": { "text/plain": [ "array([ 0.06005859, -0.07763672, -0.01135254, 0.08544922, -0.08154297,\n", " -0.13671875, -0.21875 , -0.05859375, -0.06176758, 0.14257812],\n", " dtype=float32)" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print(len(w2v_model['Singapore']))\n", "w2v_model['Singapore'][:10]" ] }, { "cell_type": "code", "execution_count": 45, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[('Hong_Kong', 0.7355004549026489), ('Malaysia', 0.7280135154724121), ('Kuala_Lumpur', 0.6947176456451416), ('Singaporean', 0.680225670337677), ('SIngapore', 0.665448784828186), (\"S'pore\", 0.6562163233757019), ('Malaysian', 0.6307142972946167), ('Inkster_Miyazato', 0.6058071851730347), ('Exchange_Ltd._S##.SG', 0.6021658778190613), ('GP_Pte_Ltd', 0.6005238890647888)]\n", "\n", "[('malaysia', 0.647721529006958), ('hong_kong', 0.6318016052246094), ('malaysian', 0.6025472283363342), ('australia', 0.597445011138916), ('uae', 0.5960760116577148), ('india', 0.5947676301002502), ('uk', 0.5883470773696899), ('chinese', 0.5872371792793274), ('usa', 0.583607017993927), ('simon', 0.5695350766181946)]\n" ] } ], "source": [ "print(w2v_model.most_similar('Singapore'))\n", "print()\n", "print(w2v_model.most_similar('singapore'))" ] }, { "cell_type": "code", "execution_count": 46, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.060058594\n", "0.06933594\n" ] } ], "source": [ "print(w2v_model['Singapore'][0])\n", "print(w2v_model['singapore'][0])" ] }, { "cell_type": "code", "execution_count": 47, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.546599805355072\n", "0.4534002\n" ] } ], "source": [ "print(w2v_model.distance('Singapore','Japan'))\n", "print(w2v_model.similarity('Singapore','Japan'))" ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "[nltk_data] Downloading package stopwords to\n", "[nltk_data] C:\\Users\\datta\\AppData\\Roaming\\nltk_data...\n", "[nltk_data] Package stopwords is already up-to-date!\n" ] } ], "source": [ "# may need to refactor the below code with other codes in this notebook\n", "nltk.download('stopwords')\n", "from nltk.tokenize import word_tokenize\n", "from nltk.corpus import stopwords\n", "from string import punctuation\n", "\n", "def preprocess_corpus(texts):\n", " mystopwords = set(stopwords.words(\"english\"))\n", " def remove_stops_digits(tokens):\n", " #Nested function that lowercases, removes stopwords and digits from a list of tokens\n", " return [token.lower() for token in tokens if token.lower() not in mystopwords and not token.isdigit()\n", " and token not in punctuation]\n", " #This return statement below uses the above function to process twitter tokenizer output further. \n", " return [remove_stops_digits(word_tokenize(text)) for text in texts]" ] }, { "cell_type": "code", "execution_count": 49, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "def embedding_feats(list_of_lists):\n", " DIMENSION = 300 ## This is essentially coming from the embedding space \n", " zero_vector = np.zeros(DIMENSION)\n", " feats = []\n", " for tokens in list_of_lists:\n", " feat_for_this = np.zeros(DIMENSION)\n", " count_for_this = 0 + 1e-5 # to avoid divide-by-zero \n", " for token in tokens:\n", " if token in w2v_model:\n", " feat_for_this += w2v_model[token]\n", " count_for_this +=1\n", " if(count_for_this!=0):\n", " feats.append(feat_for_this/count_for_this) \n", " else:\n", " feats.append(zero_vector)\n", " return feats" ] }, { "cell_type": "code", "execution_count": 50, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "Xtrain_prepro = preprocess_corpus(X_train)\n", "Xtest_prepro = preprocess_corpus(X_test)\n", "train_vect = embedding_feats(Xtrain_prepro)\n", "test_vect = embedding_feats(Xtest_prepro)" ] }, { "cell_type": "code", "execution_count": 51, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "AUC (with pretrained embedding): 0.8476652989196567\n", "Accuracy (with pretrained embedding): 0.847\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAATUAAAEGCAYAAAAE8QIHAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8vihELAAAACXBIWXMAAAsTAAALEwEAmpwYAAAcqklEQVR4nO3de5xVZb3H8c93ZrjIVXRQEZRQUcFUQkTtGBpmgSfDS+atk5keoyJPN82s9Kinc0zyHDuJESnZTUlTkxLF8oqmySVvYBgHRQEVBvGGGM7wO3/sPbgZZ/asJXuz96z5vnut12uvtZ79rGczr34+z3puigjMzLKiptIFMDMrJQc1M8sUBzUzyxQHNTPLFAc1M8uUukoXoJC69Ah161vpYlgK++85sNJFsBSee+5Z1jQ0aEvyqO0zOKJxfaK0sX717IgYtyXPS6u6glq3vnQbcUali2Ep3H3nRZUugqUw9tCDtjiPaFxPt70+lSjtW49Oqd/iB6ZUVUHNzDoCgar3zZWDmpmlI6CmttKlaJODmpmlpy16LVdWDmpmlpKbn2aWNa6pmVlmCNfUzCxL5JqamWWMez/NLDvcUWBmWSLc/DSzjHFNzcyyw81PM8sSAbXuKDCzLKnid2rVW4c0syqVb34mOdrLSRonabGkJZLOa+V+X0m/l/SYpIWSTm8vTwc1M0tPSnYUzUK1wBRgPDAcOFnS8BbJvgQsioj9gcOByyV1LZavg5qZpVeamtpoYElELI2IDcAMYEKLNAH0liSgF/Ay0FgsU79TM7N0EtTCEhoIPF9wvhxouTTvlcBMYCXQGzgxIjYWy9RBzczSSz5Nql7SvILzaRExLf+5tcgYLc4/BjwKjAV2B/4oaU5EvNbWAx3UzCylVOPUGiJiVBv3lgO7FJwPIlcjK3Q6cGlEBLBE0jPA3sAjbT3Q79TMLL0SdBQAc4GhkobkX/6fRK6pWeg54IjcI7UjsBewtFimrqmZWTolWk8tIholTQJmA7XA9IhYKGli/v5U4BLgWklP5J/8zYhoKJavg5qZpVS6aVIRMQuY1eLa1ILPK4GPpsnTQc3M0vN6amaWKVU8TcpBzczSkVfpMLOscU3NzLJEDmpmlhW51bwd1MwsKyRU46BmZhnimpqZZYqDmpllioOamWWHaH3RoCrhoGZmqQi5pmZm2VJT4xkFZpYhrqmZWXb4nZqZZY1ramaWGe4oMLPM8TQpM8sOuflpZhnjoGZmmVLNQa16R9CZWVVq7ihIcrSblzRO0mJJSySd18r9cyQ9mj+elNQkabtieTqomVl6SngUy0KqBaYA44HhwMmShhemiYjJETEiIkYA3wLui4iXi+Xr5qeZpaOSTZMaDSyJiKUAkmYAE4BFbaQ/Gbi+vUxdUzOz1FI0P+slzSs4zirIZiDwfMH58vy11p7XAxgH3NRe2VxTM7P0kvcTNETEqBS5RBtpjwYebK/pCQ5qW+SI0UP5r0lHUVtbwy9vm88V192/2f0+Pbvxk2+fwKAd+lJbW8OVv3mQ6+5YQLeuddz2wzPp1qWW2toaZt63kEuvvbtCv6Jzuefhp/juFTezceNGTj76YL78L0dudv/vy17ia9+7jieefp5vnvVxvnDKWACWLHuJiRf8fFO651Y2cM6ZR/GvJx6+NYtfNUrU+7kc2KXgfBCwso20J5Gg6QllDmqSxgE/BGqBqyPi0nI+b2uqqRGT/+1ojv3Gz1i5+jXunjqR2x98isXLVm9Kc+YxB7P42VWcfP6v2L5vD+b+8ivc+KfH+MeGRiZ8bTrr1m+grraG23/0r/zpkaeZt2h5BX9R9jU1beT8y29kxhVfZMAO23LUmZfzsUP3Zc8hO21K069PDy756nHccf8Tm313j8E78qefn7spn5HHXMD4w/bbquWvFkl7NhOYCwyVNARYQS5wndLK8/oChwGfTpJp2d6pJenZ6MgO2HsQS1esYdkLa3m7sYmb736Co/5p2GZpIoJePboB0HObbqx9fT2NTRsBWLd+AwBd6mrpUldLtFXptpL561PLeN+g/gweWE/XLnVMOGIks+dsHrzq+/VmxLDB1NXVtpnPnHlPM3hgPYN2KjqyINNKMaQjIhqBScBs4CnghohYKGmipIkFSY8F7oyIdUnKVs6aWtqejQ5lQP8+rFj96qbzlatf44DhgzZL89NbHua6//w0T930TXr16MoZF/2GyEevmhpx77QvMmTgdlxzy1+Y/5RraeX24upX2XmHbTedD9hhWxYsXJY6n1vvWsAxHxlZwpJ1PKWa+xkRs4BZLa5NbXF+LXBt0jzL2fuZqGdD0lnNPSPR+GYZi1Narb7hbFHdGjt6KE8seYFhx3+fMWdO4bJ/O5re+Zrbxo3BmDOnsM8Jkxk5bBDDhuywFUrdubX8+wCkbUVteLuROx94kqPHjihNoTqoUg2+LYdyBrVEPRsRMS0iRkXEKNX1KGNxSmvl6tcY2L/vpvOd+/fhxYbXN0tz6riR/OH+XMX0mRUvs+yFtQzdtX6zNK+98RYPPPoMR4weWv5Cd3IDdtiWlate2XT+wqpX2Km+b9tfaMXdDz/FvnsOov92fUpcug5EnTeopenZ6HAWLF7B7oO2Z9ed+tGlrpbjxu7L7X/+22Zplq96hTEH7A5A/3492WOXep59YS3b9+1Bn17dAejetY7DD9idvz/XsNV/Q2czYu9deWb5ap5buYYNbzdy610L+Oih70+Vx+/+OJ9jjuzkTU9yNdwkRyWU851aop6NjqqpaSPn/vAP3DT5NGpravj17fP527OrOP0TBwLws5lzmfyLe5ly3vE8OH0Skrho2mxefvVN9tltR6761vHU1tRQUyNuuedJZj+0uMK/KPvq6mr53leP55Sv/Zimpo2c9PGD2Wu3AfzilgcA+Myxh7JqzWuMP+MHvL7uLWpqarj6hnu599fn07tnd958awNz5i7msnNPrPAvqbTqXiRSrb1nKFnm0lHAFeSGdEyPiO8VS1/Ta0B0G3FG2cpjpbfyzosqXQRLYeyhB/HXBfO2KCJ132nPGHzajxKlffqycfOLDL4ti7KOU2utZ8PMOrgKNi2T8IwCM0tF5IYkVSsHNTNLzTU1M8uUau4ocFAzs3T8Ts3MskSoVItEloWDmpml5pqamWWK36mZWXb4nZqZZUlu7mf1RjUHNTNLrYpjmoOamaXnGQVmlh1y89PMMqR5PbVq5aBmZilV93pqDmpmlloVx7SyLudtZlmkXEdBkqPdrKRxkhZLWiLpvDbSHC7pUUkLJd3XXp6uqZlZKqUap1awN/CR5PY0mStpZkQsKkizLXAVMC4inpPU7rZrrqmZWWol2k1q097AEbEBaN4buNApwM0R8RxARKxqL1MHNTNLLcVuUvXN+/rmj7MKskmyN/CeQD9J90qaL+kz7ZXNzU8zSy1F87OhyMYrSfYGrgMOAI4AtgEekvRwRDzd1gMd1MwsndJNaE+yN/BycoFxHbBO0v3A/kCbQc3NTzNLJbdIZEl6PzftDSypK7m9gWe2SHMr8CFJdZJ6AAcBTxXL1DU1M0utpgRVtYholDQJmM07ewMvlDQxf39qRDwl6Q7gcWAjcHVEPFksXwc1M0utVINvW9sbOCKmtjifDExOmqeDmpmlIk9oN7OsqeKVh9oOapJ+xLu7VzeJiLPLUiIzq3oddT21eVutFGbWYYhcD2i1ajOoRcTPC88l9cyPFTGzTq6KK2rtj1OTdIikReTHhkjaX9JVZS+ZmVWnhPM+K9WZkGTw7RXAx4A1ABHxGDCmjGUysyqXYu7nVpeo9zMinm8RdZvKUxwzq3aiNINvyyVJUHte0geByE9lOJt2pimYWbZVc+9nkubnROBL5JYEWQGMyJ+bWSeUtOlZtc3PiGgATt0KZTGzDqKam59Jej93k/R7SaslrZJ0q6TdtkbhzKw6KeFRCUman9cBNwADgJ2BG4Hry1koM6tuHX1IhyLilxHRmD9+RZHpU2aWbbnez2RHJRSb+7ld/uM9+a2rZpALZicCt22FsplZNVKy7e8qpVhHwXxyQay59J8vuBfAJeUqlJlVtw659FBEDNmaBTGzjqG5+VmtEs0okPR+YDjQvflaRPyiXIUys+rWIWtqzSRdCBxOLqjNAsYDDwAOamadVPWGtGS9n58kt+feixFxOrntqbqVtVRmVrUkqK1RoqMSkjQ/10fERkmNkvoAqwAPvjXrxKq5+ZmkpjZP0rbAT8n1iC4AHilnocysupVq7qekcZIWS1qSHzrW8v7hkl6V9Gj+uKC9PJPM/fxi/uPU/P57fSLi8faLa2ZZJFSSuZ+SaoEpwJHkdmKfK2lmRCxqkXRORHw8ab7FBt+OLHYvIhYkfYiZZUjpVuAYDSyJiKUAkmYAE4CWQS2VYjW1y4vcC2Dsljy4NR/YayAP3vsfpc7WyqjfgZMqXQRL4R+LnytJPineqdVLKtzEaVpETMt/Hgg8X3BvOXBQK3kcIukxYCXwjYhYWOyBxQbffjhZmc2sMxFQmzyoNUTEqCJZtdRyXvkCYHBEvCHpKOB3wNBiD0zSUWBmtpkSTWhfDuxScD6IXG1sk4h4LSLeyH+eBXSRVF+0bKl/jZl1eiUKanOBoZKG5LcKOAmYWZhA0k7Kt3UljSYXs9YUyzTRNCkzs2a54Rpb3lMQEY2SJgGzgVpgekQslDQxf38qucH/X5DUCKwHToqIokufJZkmJXLLee8WERdL2hXYKSI8Vs2skyrVZIF8k3JWi2tTCz5fCVyZqmwJ0lwFHAKcnD9/ndzYEjPrpDr0xivAQRExUtJfASJibb79a2adkIC6Kp4mlSSovZ0f+RsAkvoDG8taKjOralUc0xIFtf8FbgF2kPQ9ci/uvlPWUplZ1ZJKM02qXJLM/fy1pPnklh8ScExEeId2s06simNaot7PXYE3gd8XXouI0sy3MLMOp6Mv530b72zA0h0YAiwG9iljucysSgkqtgBkEkman/sWnudX7/h8G8nNLOsquKdnEqlnFETEAkkHlqMwZtYxqIp3KUjyTu1rBac1wEhgddlKZGZVLQtb5PUu+NxI7h3bTeUpjpl1BB02qOUH3faKiHO2UnnMrAOo5o1Xii3nXZefRd/mst5m1vnktsirdCnaVqym9gi592ePSpoJ3Aisa74ZETeXuWxmVqU69IwCYDtyi7KN5Z3xagE4qJl1Qh25o2CHfM/nk7wTzJoVXaTNzLKtiitqRYNaLdCLZJsjmFmnIWo66Di1FyLi4q1WEjPrEETHralVcbHNrGIEdVX8Uq1YUDtiq5XCzDqMDltTi4iXt2ZBzKzjqOYhHVU8hM7MqlWpNl6RNE7SYklLJJ1XJN2BkpokfbK9PB3UzCwVkQscSY6i+eSmYU4BxgPDgZMlDW8j3ffJ7Q/aLgc1M0tHueZnkqMdo4ElEbE0IjYAM4AJraT7MrlFNFYlKZ53aDezVHIzChK/U6uXNK/gfFpETMt/Hgg8X3BvOXDQZs+SBgLHkpvRlGgdRwc1M0stRTdBQ0SMSpFNy4H9VwDfjIimpCuDOKiZWWol6vxcDuxScD4IWNkizShgRj6g1QNHSWqMiN+1lamDmpmlpFKtpzYXGCppCLACOAk4pTBBRAzZ9FTpWuAPxQIaOKiZWUrNvZ9bKr9e4yRyvZq1wPSIWChpYv7+1PeSr4OamaVWqsG3ETELmNXiWqvBLCI+myRPBzUzS0cddDlvM7PWlKr5WS4OamaWmmtqZpYp1RvSHNTMLCUBta6pmVmWVHFMc1Azs7SEqrgB6qBmZqm5pmZmmZEb0lG9Uc1BzczSSbiqbaU4qJlZatW8R4GDmpmlklskstKlaJuDmpml5t5PM8uUKm59VvW81Kr3pz8v4sDjL2bksf/O/1x757vuP/3si3z0cz9gxw9+hR/98k/vut/UtJExp17KiV/98dYorgFHHDKMR377XebffCFfOe3Id93v07M71//355nz6/P482++zSlHH/zOvV7bcO2lZ/CXG7/Dwzd8hwP3HfKu73cWSvi/SihbTU3SdODjwKqIeH+5nlMpTU0bOeeyG7jlyknsvOO2jD1tMuPH7Mveuw3YlKZfn55c+vUTuO2+x1rNY+qMe9hzyI68vu6trVXsTq2mRkw+91McO+lKVr70Cnf//Bxuv/8JFj/z4qY0Z54whsVLX+Tkr/2E7bftxdzffpcbb5/L241NXPr1T3LXQ4v47HnX0KWulm26d63gr6mcan+nVs6a2rXAuDLmX1HzFz7LbrvU875B9XTtUsdxR45k1n2Pb5am/3a9GbnPYLrU1b7r+yteWsudDyzkMxM+uLWK3OkdsM/7WPp8A8tWrOHtxiZu/uMCjjpsv83SBNCrZzcAevboxtrX3qSxaSO9e3bngx/YnV/e+hAAbzc28dob67f2T6gOCbfHq1QPadmCWkTcD7xcrvwr7YXVrzJwx36bznfesR8vrH418ffP/++buOjsY6ip5v/kZcyA/n1Z8dLaTecrX1rLgP59N0vz0xvuY8/37cRTt3+PB68/n29d/lsigsEDt6fhlTeYcuGnue9X3+SH3z6FHp20pga52lqSoxIq/k5N0lmS5kmat7phdaWLk1hEy528kr88vWPOE9T3682IYbuWuFRWTGtrgLX8M449eBhPPL2cYeO/zZhT/4vLzjmB3j27U1dby/577cL0387hsE9/nzff+gdf+ey738l1Bs37fna6mlpSETEtIkZFxKj+9f0rXZzEdt5h23f9V3+n+r5FvvGOvzy2lDvmPMF+n7iAM87/GXPmPs1Z3/15uYpqeStXvfKu2vWLDZvXrk89+mD+cE/uHegzyxtYtnINQwfvyMpVa1m56hXmL1wGwMy7HmX/vXahs3JNLYNGDh/M/z23mmUrGtjwdiM3/3EB48fs1/4XgQsnTWDhbf/B4zMv5pr/PJ0PHbgn0y45rcwltgWLlrH7rv3Zdeft6VJXy3FHjuT2+zd/D7r8xbWMOXAvIPdOdI/BO/LsigZWrXmdFS+tZY/BOwAw5sC9Nutg6HSqOKp5nNp7VFdXy2Xnforjz55CU1Nw6icOZtjuA5h+0xwAPnf8h3ip4TXGnnYZr697C0lMnXEvD/3m2/TptU2FS985NTVt5NzLbuCm//0StbXi1zMf5m9LX+T04w4F4Gc3P8Dka+5gyoWf5sHrz0eCi668lZdfXQfAuT+4kWkXf5auXWp5dkUDX7r4V5X8ORVVqqalpHHAD8ltkXd1RFza4v4E4BJgI9AIfCUiHiiaZ2vvhkpU2OuBw8ntqvwScGFEXFPsOwccMCoe/Mu8spTHyqPfgZMqXQRL4R+Lb2Djm6u2KCIN2/cD8Ytb702UdvTu286PiFGt3ZNUCzwNHElut/a5wMkRsaggTS9gXUSEpP2AGyJi72LPLFtNLSJOLlfeZlZhpamojQaWRMRSAEkzgAnApqAWEW8UpO9JbtRNUX6nZmap5F6XJZ5RUN88uiF/nFWQ1UDg+YLz5flrmz9POlbS34DbgM+1Vz6/UzOzdNKtp9bQVvOT1ut776qJRcQtwC2SxpB7v/aRYg90Tc3MUitR5+dyoHBczCBgZVuJ8wP6d5dUXyxTBzUzS0lIyY52zAWGShoiqStwEjBzsydJeyifkaSRQFdgTbFM3fw0s9RKMaIjIholTQJmkxvSMT0iFkqamL8/FTge+Iykt4H1wInRzpANBzUzS6WU42ojYhYwq8W1qQWfvw98P02eDmpmll4Vr8PgoGZmqXk5bzPLlGpezttBzczS8b6fZpY1bn6aWWYI19TMLGOqOKY5qJnZe1DFUc1BzcxSq9T+A0k4qJlZatUb0hzUzOy9qOKo5qBmZqk0LxJZrRzUzCwdD741s6yp4pjmoGZmaSVaALJiHNTMLLUqjmkOamaWTgU3X0/EQc3M0qviqOagZmapeUiHmWVKNb9T8xZ5ZpaOoCbh0W5W0jhJiyUtkXReK/dPlfR4/vizpP3by9M1NTN7D7a8qiapFpgCHEluY+O5kmZGxKKCZM8Ah0XEWknjgWnAQcXydVAzs1RKuEjkaGBJRCwFkDQDmABsCmoR8eeC9A+T28W9KDc/zSw1JTzaMRB4vuB8ef5aW84Abm8vU9fUzCy1FDW1eknzCs6nRcS05mxaSd/q7uuSPkwuqB3a3gMd1MwstRTTpBoiYlQb95YDuxScDwJWtvKs/YCrgfERsaa9B7r5aWaplaj5ORcYKmmIpK7AScDMzZ4j7QrcDPxLRDydpGyuqZlZKirR0kMR0ShpEjAbqAWmR8RCSRPz96cCFwDbA1fla4eNRWp+gIOamb0HpZpREBGzgFktrk0t+HwmcGaaPB3UzCy9Kp5R4KBmZqlVcUxzUDOztOQt8swsO0o4o6AsPKTDzDLFNTUzS62aa2oOamaWmheJNLPs8L6fZpYl1d5R4KBmZqm5+WlmmeKampllShXHNAc1M3sPqjiqOaiZWSqCqp4mpYhWV8+tCEmrgWWVLkcZ1AMNlS6EpZLVv9ngiOi/JRlIuoPcv08SDRExbkuel1ZVBbWskjSvvYXtrLr4b9Zxee6nmWWKg5qZZYqD2tYxrf0kVmX8N+ug/E7NzDLFNTUzyxQHNTPLFAe1MpI0TtJiSUsknVfp8lj7JE2XtErSk5Uui703DmplIqkWmAKMB4YDJ0saXtlSWQLXAlt1sKiVloNa+YwGlkTE0ojYAMwAJlS4TNaOiLgfeLnS5bD3zkGtfAYCzxecL89fM7MyclArn9Zm/Hr8jFmZOaiVz3Jgl4LzQcDKCpXFrNNwUCufucBQSUMkdQVOAmZWuExmmeegViYR0QhMAmYDTwE3RMTCypbK2iPpeuAhYC9JyyWdUekyWTqeJmVmmeKampllioOamWWKg5qZZYqDmpllioOamWWKg1oHIqlJ0qOSnpR0o6QeW5DXtZI+mf98dbHJ9pIOl/TB9/CMZyW9a9ehtq63SPNGymf9u6RvpC2jZY+DWseyPiJGRMT7gQ3AxMKb+ZVBUouIMyNiUZEkhwOpg5pZJTiodVxzgD3ytah7JF0HPCGpVtJkSXMlPS7p8wDKuVLSIkm3ATs0ZyTpXkmj8p/HSVog6TFJd0l6H7ng+dV8LfFDkvpLuin/jLmS/in/3e0l3Snpr5J+QoJ9vCX9TtJ8SQslndXi3uX5stwlqX/+2u6S7sh/Z46kvUvyr2mZ4R3aOyBJdeTWabsjf2k08P6IeCYfGF6NiAMldQMelHQn8AFgL2BfYEdgETC9Rb79gZ8CY/J5bRcRL0uaCrwRET/Ip7sO+J+IeEDSruRmTQwDLgQeiIiLJf0zsFmQasPn8s/YBpgr6aaIWAP0BBZExNclXZDPexK5DVEmRsTfJR0EXAWMfQ//jJZRDmodyzaSHs1/ngNcQ65Z+EhEPJO//lFgv+b3ZUBfYCgwBrg+IpqAlZLubiX/g4H7m/OKiLbWFfsIMFzaVBHrI6l3/hnH5b97m6S1CX7T2ZKOzX/eJV/WNcBG4Df5678CbpbUK/97byx4drcEz7BOxEGtY1kfESMKL+T/z72u8BLw5YiY3SLdUbS/9JESpIHca4tDImJ9K2VJPO9O0uHkAuQhEfGmpHuB7m0kj/xzX2n5b2BWyO/Usmc28AVJXQAk7SmpJ3A/cFL+ndsA4MOtfPch4DBJQ/Lf3S5//XWgd0G6O8k1BcmnG5H/eD9wav7aeKBfO2XtC6zNB7S9ydUUm9UAzbXNU8g1a18DnpF0Qv4ZkrR/O8+wTsZBLXuuJve+bEF+85CfkKuR3wL8HXgC+DFwX8svRsRqcu/Bbpb0GO80/34PHNvcUQCcDYzKd0Qs4p1e2IuAMZIWkGsGP9dOWe8A6iQ9DlwCPFxwbx2wj6T55N6ZXZy/fipwRr58C/ES6daCV+kws0xxTc3MMsVBzcwyxUHNzDLFQc3MMsVBzcwyxUHNzDLFQc3MMuX/ARFCmzLPO1RCAAAAAElFTkSuQmCC\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "model1.fit(train_vect, y_train) # Recall: It was the basic logistic regression model\n", "predictions = model1.predict(test_vect)\n", "print('AUC (with pretrained embedding): ', roc_auc_score(y_test, predictions))\n", "print(\"Accuracy (with pretrained embedding): \", accuracy_score(y_test, predictions))\n", "ConfusionMatrixDisplay.from_predictions(y_test,predictions,normalize=\"true\",cmap=plt.cm.Blues)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Topic modeling and document similarity" ] }, { "cell_type": "code", "execution_count": 52, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "# A few more toy documents\n", "EE2 =\"Colin Powell, America’s former secretary of state and chairman of the joint chiefs of staff, died from complications related to covid-19, aged 84. He was the first black man to hold either position. George H.W. Bush appointed him as the youngest person ever to serve as America’s highest-ranking military officer in 1989. Under George W. Bush he was the county’s top diplomat from 2001 to 2005.\"\n", "EE3 = \"The world’s biggest streaming service disappointed Wall Street last quarter when it revealed tepid growth in subscribers. Its earnings report today should tell a different tale. The main driver of subscriptions is new content. Though scarce earlier this year because of the disruption caused by covid-19, the pipeline is filling up again. Old favourites like “Money Heist” and “Sex Education” are back with new episodes, and “Squid Game”, a dystopic South Korean thriller, has proved to be Netflix’s biggest-ever hit.\"\n", "doc1 = nlp(EE1) \n", "doc2 = nlp(EE2)\n", "doc3 = nlp(EE3)" ] }, { "cell_type": "code", "execution_count": 53, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Similarity between documents 1 2 : 0.029378258437261235\n", "Similarity between documents 1 3 : 0.0\n", "Similarity between documents 2 3 : 0.024661696851234052\n" ] } ], "source": [ "from sklearn.feature_extraction.text import TfidfVectorizer\n", "\n", "corpus = [EE1,EE2,EE3]\n", "vect = TfidfVectorizer(min_df=1, stop_words=\"english\") \n", "tfidf = vect.fit_transform(corpus) \n", "pairwise_similarity = tfidf * tfidf.T \n", "\n", "import itertools\n", "for i,j in itertools.product(range(3), range(3)):\n", " if iKey ideas/intuitions: \n", "1. Each document is a mix of topics (following some \"unknown\" distribution)\n", " * Topics are not explicitly defined, but we have an \"estimate\" of the number of topics\n", "2. Each topic is a mix of words (again, following some \"unknown\" distribution) " ] }, { "cell_type": "code", "execution_count": 93, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Third party content:\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "execution_count": 93, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# The following YouTube video on Latent Dirichlet allocation provides a very nice high level overview\n", "# Even if you are familiar with LDA and topic modeling, you may gain some nice perspectives \n", "print(\"Third party content:\")\n", "HTML('')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "![LDA Big Idea.png](pics/LDA-overview.png)\n", "Image source: Above mentioned YouTube video" ] }, { "cell_type": "code", "execution_count": 56, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "7769 total train documents\n", "3019 total test documents\n", "['training/1', 'training/10', 'training/100', 'training/1000', 'training/10000', 'training/10002', 'training/10005', 'training/10008', 'training/10011', 'training/10014']\n", "['MOST', 'EC', 'STATES', 'SAID', 'TO', 'BE', 'AGAINST', 'OILS', '/', 'FATS', 'TAX', 'A', 'majority', 'of', 'European', 'Community', '(', 'EC', ')', 'member', 'states', 'are', 'either', 'against', 'or', 'have', 'strong', 'reservations', 'over', 'a', 'tax', 'on', 'both', 'imported', 'and', 'domestically', '-', 'produced', 'oils', 'and', 'fats', 'proposed', 'by', 'the', 'European', 'Commission', ',', 'senior', 'diplomats', 'said', '.', 'They', 'said', 'a', 'special', 'committee', 'of', 'agricultural', 'experts', 'from', 'EC', 'member', 'states', 'had', 'voiced', 'strong', 'objections', 'over', 'the', 'measure', 'during', 'a', 'meeting', 'charged', 'with', 'preparing', 'the', 'ground', 'for', 'the', 'annual', 'EC', 'farm', 'price', '-', 'fixing', 'which', 'begins', 'next', 'Monday', '.', 'They', 'added', 'that', 'only', 'France', 'and', 'Italy', 'had', 'indicated', 'they', 'would', 'support', 'the', 'Commission', 'proposal', 'which', 'would', 'lead', 'to', 'a', 'tax', 'initially', 'of', '330', 'Ecus', 'per', 'tonne', 'during', 'the', '1987', '/', '88', 'price', 'round', '.']\n" ] } ], "source": [ "from nltk.corpus import reuters\n", "documents=reuters.fileids()\n", "train_docs = list(filter(lambda doc: doc.startswith(\"train\"), documents));\n", "test_docs = list(filter(lambda doc: doc.startswith(\"test\"), documents));\n", "print(str(len(train_docs)) + \" total train documents\");\n", "print(str(len(test_docs)) + \" total test documents\");\n", "print(train_docs[0:10])\n", "print(reuters.words(train_docs[10])[0:len(reuters.words(train_docs[10]))])" ] }, { "cell_type": "code", "execution_count": 57, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "# Some of the code fragments below on LDA for topic modeling is adapted from https://radimrehurek.com/gensim/models/ldamodel.html\n", "\n", "from gensim.corpora.dictionary import Dictionary\n", "from gensim.test.utils import common_corpus\n", "import gensim\n", "from gensim import corpora, models\n", "\n", "import random" ] }, { "cell_type": "code", "execution_count": 58, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['alarming', 'problem', 'loom', 'Iran', 'rapidly', 'advance', 'nuclear', 'programme', 'Israel', 'threaten', 'military', 'action', 'America', 'seek', 'diplomatic', 'solution', 'Anton', 'La', 'Guardia', 'Economist', 'diplomatic', 'editor', 'write', 'international', 'crisis', 'pose', 'Al', 'Monitor', 'publication', 'cover', 'Middle', 'East', 'monitor', 'negotiation', 'revive', 'nuclear', 'deal', '2015', 'fiendish', 'dilemma', 'french', 'president', 'Nicolas', 'Sarkozy', 'encapsulate', 'iranian', 'bomb', 'bombing', 'Iran', 'Iran', 'nuclear', 'weapon', 'situation', 'way', 'bad', 'past', 'country', 'close', 'able', 'nuke', 'expert', 'David', 'Albright', 'breakout', \"time'—the\", 'time', 'need', 'bomb', 'worth', 'highly', 'enrich', 'uranium', '—', 'month', 'Mr', 'Albright', 'book', 'detailed', 'account', 'iranian', 'programme', 'draw', 'year', 'inspection', 'International', 'Atomic', 'Energy', 'Agency', 'trove', 'iranian', 'document', 'obtain', 'israeli', 'intelligence', 'problem', 'credibility', 'american', 'diplomacy', 'damage', 'Donald', 'Trump', 'repudiation', 'nuclear', 'deal', 'successor', 'Joe', 'Biden', 'try', 'revive', 'Iran', 'interested', 'Robert', 'Malley', 'America', 'special', 'envoy', 'Iran', 'discuss', 'impasse', 'recent', 'interview', 'Iran', 'claim', 'seek', 'nuclear', 'energy', 'civilian', 'purpose', 'trouble', 'technology', 'use', 'low', 'enriched', 'uranium', 'fuel', 'nuclear', 'power', 'station', 'use', 'highly', 'enrich', 'uranium', 'weapon', 'ultimate', 'aim', 'Iran', 'regime', 'attach', 'great', 'national', 'pride', 'mastery', 'nuclear', 'technology', 'moon', 'shoot', 'iranian', 'official', 'accord', 'Channel', 'memoir', 'William', 'Burns', 'head', 'CIA', 'diplomat', 'helped', 'negotiate', 'nuclear', 'deal']\n" ] } ], "source": [ "# Below is a module which can be used as a possible solution for ungraded task 6.1 \n", "# Note: Most of the text_scrubber code is from https://towardsdatascience.com/text-normalization-with-spacy-and-nltk-1302ff430119\n", "# The punctuation removal module in there was inadequate to my liking, and I replaced it with something more robust\n", "\n", "def text_scrubber(text):\n", " import string \n", " doc = nlp(text)\n", " \n", "# Tokenization and lemmatization \n", " lemma_list = []\n", " for token in doc:\n", " lemma_list.append(token.lemma_)\n", " \n", " # Filter the stopwords\n", " filtered_sentence =[] \n", " for word in lemma_list:\n", " lexeme = nlp.vocab[word]\n", " if lexeme.is_stop == False:\n", " filtered_sentence.append(word) \n", " \n", " # Filter the punctuations \n", " for punc in string.punctuation:\n", " filtered_sentence=list(filter(lambda a: a != punc, filtered_sentence))\n", " \n", " return filtered_sentence\n", " \n", "print(text_scrubber(EE1))" ] }, { "cell_type": "code", "execution_count": 59, "metadata": { "scrolled": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[['CHINA', 'SOYBEAN', 'OUTPUT', 'SLIGHTLY', 'USDA', 'REPORT', 'China', 'soybean', 'crop', 'year', 'forecast', 'mln', 'tonnes', 'slightly', 'mln', 'estiamted', 'year', 'Agriculture', 'Department', 'officer', 'Peking', 'field', 'report', 'report', 'dated', 'April', 'Chinese', 'imports', 'year', 'projected', '300', '000', 'tonnes', 'unchanged', 'year', 'level', 'Exports', 'forecast', 'increase', 'mln', 'tonnes', '800', '000', 'tonnes', 'exported', 'year', 'report', 'Imports', 'soybean', 'oil', 'estimated', '200', '000', 'tonnes', 'unchanged', 'year'], ['DATA', 'MEASUREMENT', 'CORP', 'DMCB', '4TH', 'QTR', 'Shr', 'cts', 'cts', 'Net', '516', '063', '328', '468', 'Revs', 'mln', 'mln', 'NOTE', 'Shrs', 'reflect', 'stock', 'split']]\n" ] } ], "source": [ "# Prepare the initial set of documents to be used for LDA topic modeling\n", "docs=[[y for y in reuters.words(x) if len(text_scrubber(y))>0 and len(y)>2] for x in random.sample(train_docs, 100)]\n", "print(random.sample(docs,2))" ] }, { "cell_type": "code", "execution_count": 60, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Numer of tokens: 3176\n", "Some random tokens: [('discipline', 2249), ('478', 2021), ('soybeans', 846), ('IMPORT', 2405), ('housing', 635), ('metals', 1891), ('Reagan', 552), ('volatily', 1862), ('holders', 1045), ('delay', 88), ('violent', 2283), ('October', 1259), ('inquiries', 2165), ('estimation', 1575), ('member', 139), ('options', 402), ('somebody', 2593), ('Federal', 870), ('wonderful', 3157), ('Terms', 1358)]\n" ] } ], "source": [ "dct = Dictionary(docs)\n", "common_corpus = [dct.doc2bow(text) for text in docs]\n", "lda = models.ldamodel.LdaModel(common_corpus, num_topics=20)\n", "print(\"Numer of tokens:\", len(dct.token2id))\n", "print(\"Some random tokens:\", random.sample(list(dct.token2id.items()),20))\n", "inv_map = {v: k for k, v in dct.token2id.items()} \n", "# In theory there's an id2token function, but I had problem with it" ] }, { "cell_type": "code", "execution_count": 61, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[(1, 0.14542003), (2, 0.14289911), (4, 0.042802583), (6, 0.20522758), (8, 0.06020278), (9, 0.018474184), (10, 0.121667735), (12, 0.081962936), (13, 0.030592296), (17, 0.14429606)]\n", "[(0, 0.10591578), (1, 0.52794284), (2, 0.31601062)]\n", "[(1, 0.08655172), (8, 0.09062548), (12, 0.24896422), (13, 0.33639774), (17, 0.10311288), (19, 0.09310416)]\n" ] } ], "source": [ "# Let's look at the topic distribution of some documents\n", "new_docs=[text_scrubber(EE1),text_scrubber(EE2),text_scrubber(EE3)]\n", "new_corpus = [dct.doc2bow(text) for text in new_docs]\n", "topic_prob=[lda[new_corpus[i]] for i in range(len(new_docs))] # topic probability distribution\n", "for x in topic_prob:\n", " print(x)" ] }, { "cell_type": "code", "execution_count": 62, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[('mln', 0.017560491), ('year', 0.013100874), ('bpd', 0.0078046345), ('1987', 0.0055634426), ('pct', 0.005427841), ('beet', 0.004666399), ('market', 0.0043878434), ('land', 0.0041444087), ('cane', 0.004132074), ('farmers', 0.0039663226)]\n" ] } ], "source": [ "most_likely_topic=sorted(topic_prob[0], key=lambda x: x[1], reverse=True)[0][0]\n", "print([(inv_map[int(x[0])], x[1]) for x in lda.show_topic(most_likely_topic, topn=10)])" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "![LDA-simplex](pics/lda-space.png)\n", "Image source: Above mentioned YouTube video" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Few practicalities to consider\n", "\n", "- The suitability of the training corpus\n", "- Correct guess, or, more pragmatically, a proper exploration of the number of topics" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Named entities " ] }, { "cell_type": "code", "execution_count": 63, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "('Iran', 'GPE')\n", "('Israel', 'GPE')\n", "('America', 'GPE')\n", "('Anton La Guardia', 'PERSON')\n", "('Al-Monitor', 'PERSON')\n", "('the Middle East', 'LOC')\n", "('2015', 'DATE')\n", "('French', 'NORP')\n", "('Nicolas Sarkozy', 'PERSON')\n", "('Iranian', 'NORP')\n", "('Iran', 'GPE')\n", "('Iran', 'GPE')\n", "('One', 'CARDINAL')\n", "('David Albright', 'PERSON')\n", "('just one month', 'DATE')\n", "('Albright', 'PERSON')\n", "('Iranian', 'NORP')\n", "('years', 'DATE')\n", "('the International Atomic Energy Agency', 'ORG')\n", "('Iranian', 'NORP')\n", "('Israeli', 'NORP')\n", "('American', 'NORP')\n", "('Donald Trump’s', 'PERSON')\n", "('Joe Biden', 'PERSON')\n", "('Iran', 'GPE')\n", "('Robert Malley', 'PERSON')\n", "('America', 'GPE')\n", "('Iran', 'GPE')\n", "('Iran', 'GPE')\n", "('Iran', 'GPE')\n", "('one', 'CARDINAL')\n", "('Iranian', 'NORP')\n", "('The Back Channel”', 'WORK_OF_ART')\n", "('William Burns', 'PERSON')\n", "('CIA', 'ORG')\n" ] } ], "source": [ "#doc1 = nlp(EE1)\n", "for ent in doc1.ents:\n", " print((ent.text, ent.label_))" ] }, { "cell_type": "code", "execution_count": 64, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "'Countries, cities, states'" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# label explanation\n", "spacy.explain(\"GPE\")" ] }, { "cell_type": "code", "execution_count": 65, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/html": [ "
An alarming problem looms once more: \n", "\n", " Iran\n", " GPE\n", "\n", " is rapidly advancing its nuclear programme; \n", "\n", " Israel\n", " GPE\n", "\n", " is threatening military action against it; and \n", "\n", " America\n", " GPE\n", "\n", " is seeking a diplomatic solution. \n", "\n", " Anton La Guardia\n", " PERSON\n", "\n", ", The Economist’s diplomatic editor, wrote about the international crisis this poses. \n", "\n", " Al-Monitor\n", " PERSON\n", "\n", ", a publication that covers \n", "\n", " the Middle East\n", " LOC\n", "\n", ", has been monitoring the negotiations to revive a nuclear deal from \n", "\n", " 2015\n", " DATE\n", "\n", ". It makes for a fiendish dilemma that the former \n", "\n", " French\n", " NORP\n", "\n", " president, \n", "\n", " Nicolas Sarkozy\n", " PERSON\n", "\n", ", encapsulated thus: `an \n", "\n", " Iranian\n", " NORP\n", "\n", " bomb or the bombing of \n", "\n", " Iran\n", " GPE\n", "\n", "'. \n", "\n", " Iran\n", " GPE\n", "\n", " doesn't yet have a nuclear weapon. But the situation is in many ways worse than in the past. The country is closer than ever to being able to make a nuke. \n", "\n", " One\n", " CARDINAL\n", "\n", " expert, \n", "\n", " David Albright\n", " PERSON\n", "\n", ", puts the `breakout time'—the time needed to make one bomb’s worth of highly enriched uranium—at \n", "\n", " just one month\n", " DATE\n", "\n", ". Mr \n", "\n", " Albright\n", " PERSON\n", "\n", "’s book is one of the most detailed accounts of the \n", "\n", " Iranian\n", " NORP\n", "\n", " programme, drawing on \n", "\n", " years\n", " DATE\n", "\n", " of inspections by \n", "\n", " the International Atomic Energy Agency\n", " ORG\n", "\n", " and a trove of \n", "\n", " Iranian\n", " NORP\n", "\n", " documents obtained by \n", "\n", " Israeli\n", " NORP\n", "\n", " intelligence. Another problem is that the credibility of \n", "\n", " American\n", " NORP\n", "\n", " diplomacy has been damaged by \n", "\n", " Donald Trump’s\n", " PERSON\n", "\n", " repudiation of the nuclear deal. His successor, \n", "\n", " Joe Biden\n", " PERSON\n", "\n", ", is trying to revive it but \n", "\n", " Iran\n", " GPE\n", "\n", " doesn’t seem to be interested. \n", "\n", " Robert Malley\n", " PERSON\n", "\n", ", \n", "\n", " America\n", " GPE\n", "\n", "'s special envoy on \n", "\n", " Iran\n", " GPE\n", "\n", ", discusses the impasse in a recent interview. \n", "\n", " Iran\n", " GPE\n", "\n", " claims it seeks nuclear energy only for civilian purposes. The trouble is that the technology used to make low-enriched uranium fuel for nuclear power stations is also used to make highly-enriched uranium for weapons. Whatever its ultimate aim, \n", "\n", " Iran\n", " GPE\n", "\n", "’s regime attaches great national pride to its mastery of nuclear technology: “our moon shot” is how \n", "\n", " one\n", " CARDINAL\n", "\n", " \n", "\n", " Iranian\n", " NORP\n", "\n", " official put it, according to “\n", "\n", " The Back Channel”\n", " WORK_OF_ART\n", "\n", ", a memoir by \n", "\n", " William Burns\n", " PERSON\n", "\n", ", the head of the \n", "\n", " CIA\n", " ORG\n", "\n", " who, as a diplomat, helped negotiate the nuclear deal.
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "spacy.displacy.render(doc1, style=\"ent\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### spaCy entities:\n", "\n", "|Entity type| Description.|\n", "| --- | --- |\n", "|PERSON| People, including fictional.|\n", "|NORP| Nationalities or religious or political groups.|\n", "|FAC| Buildings, airports, highways, bridges, etc.|\n", "|ORG| Companies, agencies, institutions, etc.|\n", "|GPE| Countries, cities, states.|\n", "|LOC| Non-GPE locations, mountain ranges, bodies of water.|\n", "|PRODUCT| Objects, vehicles, foods, etc. (Not services.)|\n", "|EVENT| Named hurricanes, battles, wars, sports events, etc.|\n", "|WORK_OF_ART| Titles of books, songs, etc.|\n", "|LAW| Named documents made into laws.|\n", "|LANGUAGE| Any named language.|\n", "|DATE| Absolute or relative dates or periods.|\n", "|TIME| Times smaller than a day.|\n", "|PERCENT| Percentage, including ”%“.|\n", "|MONEY| Monetary values, including unit.|\n", "|QUANTITY| Measurements, as of weight or distance.|\n", "|ORDINAL| “first”, “second”, etc.|\n", "|CARDINAL| Numerals that do not fall under another type.|\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Other associated tasks\n", "- Relationship extraction/Entity association\n", "- Co-reference resolution\n", "- Word (sense) disambiguation" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Recommended reading: Sandia report surveying Entity-Relation Extraction Tools " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "##### Ungraded task 6.2: \n", "\n", "Using the Kaggle spam dataset [Enron1], build a pipeline to train and classify spam emails, and benchmark the performance of your classifier. " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Mulling over ML mechanics" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "### Lifecycle of ML modeling\n", "\n", "\"modelcycle\"" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Model training, tuning and evaluation \n", "\n", "> How well does the model do with data not seen during fitting?\n", "> - for data which has already been seen, a memory based model would be always \"perfect\"\n", " \n", "\"bigpic\"" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Cross validation\n", "Variants: \n", "- K-fold\n", "- Stratified: Each fold maintains proportional representation of classes\n", " * sklearn.model_selection.StratifiedKFold\n", "- Leave one out\n", "\n", "\"bigpic\"" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Validation curve\n", "\n", "\"validation\n", "\n", "> In this plot (see source for details and source-code) we see the training scores and validation scores of an SVM for different values of the kernel parameter $\\gamma$, from which we can idenitfy the regions of under-fitting and over-fitting. " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Data leakage\n", "\n", "> Leakage is essentially the introduction of information about the data mining target, which should not be legitimately available to mine from. \n", "> - This may lead to very good performance during the model tuning and evaluation, and yet, lead to poor performance in production environment\n", "> * Recommeded reading: Leakage in Data Mining:\n", "Formulation, Detection, and Avoidance by Kaufman et al. " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "#### Holdout data for evaluation\n", "Separate from the data used in cross-validation\n", "\n", "\"bigpic\"" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Accuracy\n", "Limitations of accuracy as a metric\n", "\n", "
\n", "\"classifier
\n", "Image source: Adapted from/edited over an example of t-SNE manifold learning for dimensionality reduction using sklearn's breast cancer dataset
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Confusion matrix\n", "Note: These confusion matrices are NOT for the breast cancer data.\n", "\n", "![Confusion matrix examples](pics/confusionmatrixexamples.png)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Image adapted from Wikipedia | False positive and negative\n", ":-------------------------:|:-------------------------:\n", "\"bigpic\" |
False positive: An error in binary classification, where a specific classification label is assigned to a test subject, while it in fact does not belong to said class.
e.g., If a person is tested positive for Covid-19 infection, even if the person is in fact not infected.




False negative: When the classifier determines that a test subject does not have a particular label, while it in fact belongs to said class.
e.g., If a fraudulent credit card transaction is considered legitimate and thus not prevented.
" ] }, { "cell_type": "code", "execution_count": 66, "metadata": { "scrolled": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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awHAAb125am7LuOpuy7j6bsu4+sD98tz7YvTj37zT/Yb+jOOPP3qreaN/ef/6PLVH7Bu/Uebp81duILjzv0zR5x2NYO+8zs+/WxjY1Y3L+qRTGUKRtXlNQO+Afw706ZrmeYN2xvZFkcffTQvv/wyr776KhdffPFW89u2bcu///1vXnjhBaZNm8bpp5++eV67du248847mTlzJjNmzKBfPzUuZsuUKVPo3bs3PXv25Pe///1W8+fPn89hhx1G69atueaaa7aaX1VVxUEHHcTxxx/fCLXNj+qr+WK0TK1x974pwy01i6ql+Lri0XHAs5lO8UGOr+Yzs2OA64By4FZ33/ovXYHptFM7zv324Rzy7TF8+tlGxv3mLL75tQM5+6QB/Py6+3hu5kJOPe4Qvn/6IH4z9iHmvbmCI77ze6qqNrHzjm15+p+X88jTs6mq2pTvXSkqJx97MGd+6zAu+vVdW0xfvvo9npr+Ol123twXmsrKKi686h9c97PT6F3RhXXvf0zTJsXfhSdO5/Jgjbv3jbHcEGCmu68O46vNrJO7rzSzTsA7YfoyoFvKel2BFXErky/FFr/Kysq45pprOO6441i+fDlPP/00Dz30EPPnz9+8zDnnnMP8+fM56aST6NChAy+//DITJkxg48aN/OEPf+Cxxx7jtNNOo2nTprRq1SqPe1M8qqqquOiii5g8eTJdu3alf//+DB06lF69vujG0759e/785z9z//3311rG9ddfz957782HH37YWNXOiyzdGqE+8Si15T2tnLVMxenkVaiaNCmnRfOmlJeX0apFM1a9+z577tKR52YuBGDqS/M57og+AGz4bOPmxKl586a464A8Fw7pswfbt906uP/y+v/y0/O/QerZqyenvU7PPTrTuyJq2W3fbjvKy4u8kdZycpqvZl+CScDI8HokcH/K9OFm1tzMugMVwEsN3KOcKsb41bdvXxYtWsRbb73Fxo0bueeeexg6dOhWy7Vu3RqA7bbbjvfee4/KykratGnDV77yFcaPj7rEbdy4kffff79R61+spk2bxh577MHuu+9Os2bNOPnkk3nggQe2WKZjx4707duXpk2bbrX+smXLePjhhznrrLMaq8p5k6X4NQ2oMLPuoXV9OFGMqrmtdsDhfBHH0srlX5D6dvIqCCvffZ/r73yc1x64ivkPj+GDjzfwxIvzmb9o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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "# Example code to get the confusion matrix using ConfusionMatrixDisplay\n", "# Using previously used dataset and model\n", "predictions = model3.predict(cv3.transform(X_test))\n", "# We are reusing the logistic regression model with 300 dimensions embedding of features\n", "cm_notnorm = confusion_matrix(y_test, predictions)\n", "cm_norm = confusion_matrix(y_test, predictions, normalize=\"true\")\n", "fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))\n", "fig.suptitle('Confusion matrix - Absolute numbers & Normalized respectively')\n", "ConfusionMatrixDisplay(cm_notnorm).plot(cmap=plt.cm.Blues, ax=ax1)\n", "ConfusionMatrixDisplay(cm_norm).plot(cmap=plt.cm.Greys, ax=ax2)\n", "#ConfusionMatrixDisplay.from_predictions(y_test,predictions,normalize=\"true\",cmap=plt.cm.Greys)" ] }, { "cell_type": "code", "execution_count": 67, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "data": { "text/plain": [ "array([[0.74753222, 0.25246778],\n", " [0.97268901, 0.02731099],\n", " [0.01440663, 0.98559337],\n", " ...,\n", " [0.06684778, 0.93315222],\n", " [0.99675985, 0.00324015],\n", " [0.94421511, 0.05578489]])" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Instead of the predictions as-is, one can obtain the probability for an individual sample to belong to a given class \n", "# By default, a threshold of 0.5 is used by the predict() function\n", "model3.predict_proba(cv3.transform(X_test))" ] }, { "cell_type": "code", "execution_count": 68, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "# However, we can use the predict_proba() to customize the threshold\n", "y_pred_03 = (model3.predict_proba(cv3.transform(X_test))[:,1] >= 0.3).astype(bool)\n", "y_pred_07 = (model3.predict_proba(cv3.transform(X_test))[:,1] >= 0.7).astype(bool)" ] }, { "cell_type": "code", "execution_count": 69, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Threshop 0.3\n", " precision recall f1-score support\n", "\n", " 0 0.92 0.79 0.85 1039\n", " 1 0.80 0.93 0.86 961\n", "\n", " accuracy 0.86 2000\n", " macro avg 0.86 0.86 0.86 2000\n", "weighted avg 0.87 0.86 0.86 2000\n", "\n", "Threshop 0.5\n", " precision recall f1-score support\n", "\n", " 0 0.89 0.86 0.88 1039\n", " 1 0.85 0.89 0.87 961\n", "\n", " accuracy 0.87 2000\n", " macro avg 0.87 0.87 0.87 2000\n", "weighted avg 0.87 0.87 0.87 2000\n", "\n", "Threshop 0.7\n", " precision recall f1-score support\n", "\n", " 0 0.85 0.91 0.88 1039\n", " 1 0.89 0.83 0.86 961\n", "\n", " accuracy 0.87 2000\n", " macro avg 0.87 0.87 0.87 2000\n", "weighted avg 0.87 0.87 0.87 2000\n", "\n" ] } ], "source": [ "# Classification report for customized thresholds\n", "from sklearn.metrics import classification_report\n", "print(\"Threshop 0.3\\n\", classification_report(y_test,y_pred_03))\n", "print(\"Threshop 0.5\\n\", classification_report(y_test,predictions))\n", "print(\"Threshop 0.7\\n\", classification_report(y_test,y_pred_07))" ] }, { "cell_type": "code", "execution_count": 70, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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pUmf16y21fW5eZWgd+VkM2sO/CfB9SgAmNn3zKxDWIRtDR+u7bPwDrCPhRMaNNG9wLfMbLgFk3XsbsHECF0s+F6iU8Oi4nOC332DU3+7+3qC66OuD7d3KMEJivtqWf0h4BQzO8aCSUp+ScaxSyPeCxEpMSpyRKQuvyS4sBgIrkEATiE4g70F+A/gFHffHNH+biW40HkzwcXic3J83ncJznK/bF/OIjUxXDaW4OL7lQSTJDxEcMYZgjPOcwkKiyUEF37XKrym4FsEF9a/CVSE+4Xg4vQ/EQxXWkdwUfflObY9ez+vErzvfwNWA9lfpngu8Ho4PGocQU9J9ja2A6cSXI+0meDi7rHuvqopbWqkXwCHAx8Aj7Hre3o9QdGx1cKZ4epjZgOBHxK0v5LgTL1Tf0Ga6dcE14+8ALxI8Hv+dY7PBcDdq4rGTgTXkFW5laZ9XqvU+bkJr1f7N4LrVDaE+8+cbW0EsMLMPgJuA0bXNuwu/J1PA9aG73mn7HUaEhYkowiKzXcJenauJjh+KCPIg40Ek1kcF7Y7F2MIJpnYSDAE8Gfh9T7Z+19BMOHD/QQnGt6nCe+FiJSeqllOREREREREioJ6ckREREREpKioyBERERERkaKiIkdERERERIqKihwRERERESkqKnJERERERKSoqMgREREREZGioiJHRERERESKioocEREREREpKipyRERERESkqKjIERERERGRoqIiR0REREREioqKHBERERERKSoqckREREREpKioyBERERERkaKiIkdERERERIqKihwRERERESkqKnJERERERKSoqMgREREREZGioiJHRERERESKioocEREREREpKipyRERERESkqKjIERERERGRoqIiR0REREREioqKHBERERERKSoqckREREREpGDMbISZvWJma8zs2lqW721mj5jZC2a2wMwOaWibKnJEEsjMvAm3OYVut4gkj/JERKLQxCxpME/MrBkwARgJ9AXGmFnfrNV+DCxz90OBscBtDbVXRY5IQplZo25A+0K3WUSSSXkiIlFobJbkmCdDgDXuvtbdtwPTgVFZ6/QFngJw91XAAWa2b30bVZEjklBNCBERkVopT0QkCk0schrSGVifcb8ifCzTcuDbYRuGAN2ALvVtVEWOiIiIiIjEpb2ZLcq4XZy1vLZKyLPu3wDsbWbLgMuBpcDO+nZa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NX7h8qphsI26xk9FjkhCxRAkmvJVpESpyBGRKMSVJXFc46ciRyShNOWriERFRY6IRCFNWaIiRySB4vhW4bi6g0Uk2eL8lnIRKR1pyxIVOSIJpSlfRSQqaTr7KiLJlaYsUZEjklBpChIRSTbliYhEIU1ZoiJHJKHSFCQikmzKExGJQpqyREWOSALF9Q3lIlJ6lCciEoW0ZYmKHJGESlOQiEiyKU9EJAppyhIVOSIJlaYgEZFkU56ISBTSlCUqckQSKk1BIiLJpjwRkSikKUtU5IgkVJqCRESSTXkiIlFIU5ak5xt9CuDoo49mxowZzJw5k/PPP3+X5WPHjmXatGlMmzaNBx54gIULF9KmTRsAxowZwwMPPMCDDz7I2Wfv8qXyUou///3vHH300RxxxBH8/ve/32X5Qw89xNChQxk6dCgnn3wyK1asqF525ZVX0rdvX4499th8Njk2VRf3NeYmyXbiiSeydOlSXnjhBa666qpdlrdp04YHH3yQ559/noULF3LuuedWL2vbti333nsvS5YsYfHixQwZMiSfTU+luXPn0q9fP/r06cN//dd/7bJ81apVfP3rX6dVq1bccsstuyyvrKxk8ODBnHbaaXlobbyUJ8Vl+PDhrFq1itWrV3PNNdfssnyvvfZixowZLF++nH/+85/069evetldd93FO++8w4svvpjPJqfOnDlz6N27Nz179uSGG27YZbm7c8UVV9CzZ08OPfRQlixZUr3stttu45BDDqFfv37ceuut1Y8/+OCD9OvXj7KyMhYtWpSPlxG5pmRJIfMk1iLHzEaY2StmtsbMro1zX1ErKyvjmmuu4fLLL+eMM85gxIgRdO/evcY6U6dOZcyYMYwZM4bx48ezZMkStm3bRo8ePTj99NMZO3Yso0eP5utf/zpdu3Yt0CtJh8rKSq699lruv/9+nn76aR555BFeeeWVGut069aNv/zlL8ybN48f/vCHNQ4UR48ezfTp0/Pd7FilJUTyJe15csstt3D66aczcOBAzjzzTA4++OAa61x88cWsWrWKI488kpEjR/Kb3/yG5s2bA/Db3/6WJ598ksMPP5wjjzxyl78NqamyspIrr7ySv/71ryxfvpw///nPrFy5ssY67dq143e/+x3//u//Xus2/vCHP+zyO0oz5cmX0p4lEyZMYOTIkfTt25cxY8bQp0+fGuv8+Mc/ZtmyZfTv35+xY8dy2223VS+bMmUKI0aMyHezU6WyspJLL72Uxx9/nJUrVzJt2rRd8uPxxx9n9erVrF69mkmTJvGDH/wAgJdeeok777yTBQsWsHz5ch599FFWr14NwCGHHMKMGTNSfzJWRQ5gZs2ACcBIoC8wxsz6xrW/qB1yyCFUVFSwYcMGdu7cydy5cxk6dGid6w8fPpw5c+YA0L17d1588UU+++wzKisrWbx4MSeccEKeWp5OS5YsoXv37hxwwAG0aNGC0047rfr9rDJ48GD22msvAAYOHMhbb71Vveyoo46qXlYs0hIi+ZD2PBk0aBBr167l9ddfZ8eOHTz00EOccsopu6zXqlUrAPbcc0/ef/99du7cSevWrfmXf/kX7rnnHgB27NjBBx98kNf2p83ChQvp0aMHBx54IC1atOCss87ir3/9a411OnbsyKBBg6oLyUwVFRU8/vjjXHDBBflqcuyUJ4G0Z8mQIUNYs2YN69atY8eOHUyfPp1Ro0bVWKdv37489dRTALzyyisccMABdOzYEYCnn36a9957L+/tTpMFCxbQs2fP6vwYPXo0M2fOrLHOzJkzGTt2LGbGkUceydatW3nrrbd4+eWXOfLII2nZsiXl5eUcd9xxPPLIIwD06dOH3r17F+IlRUpFTmAIsMbd17r7dmA6MKqB5yRGhw4dePvtt6vvb9q0qToksu2+++4cffTR1aHy2muvcfjhh9O2bVt23313jjnmGPbdd9+8tDut3n77bTp16lR9v1OnTjXe/2z3339/0ReOaQmRPEl1nnTq1ImKiorq+xs2bGD//fevsc7EiRPp3bs3r732GgsWLODqq6/G3enevTubN2/mjjvu4Nlnn2XChAm0bNky3y8hVTZs2ECXLl2q73fu3JmNGzfm/PyrrrqK66+/nrKy4hnRrTypluos6dy5M+vXr6++X1FRQefOnWuss3z5cr797W8DwcnBbt261fh7kPpt2LChxuibLl26sGHDhpzWOeSQQ5g/fz5btmzhk08+Yfbs2TV+X8VARU6gM5D5m60IH0uF2n4p7l7rusceeyzLly9n27ZtAKxbt44pU6Zw++23M378eF599VUqKytjbW/a1fXe1uaZZ57h/vvv5yc/+UmMLZKEKfo8+eY3v8mLL75Ijx49OOqoo7jlllto3bo1zZo1Y8CAAdx5550cffTR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uPv5kTdARAoihmv8NPxVpATFdGwSy0lYFTkiCaUznyISFQ1/FZEoxHVsEsdJWBU5IglU6G8JFpHiEUeeaPirSOlJ27GJihwRERFpNA1/FZEkU5EjklBpOlsiIsmmPBGRKKQpSyKfOD/t5syZQ+/evenZsyc33HDDLsvdnSuuuIKePXty6KGHsmTJEgBeeeUVBgwYUH1r06YNt956KwBXX301Bx98MIceeiinn346W7duzeMrSo/hw4ezatUqVq9ezTXXXLPL8r322osZM2awfPly/vnPf9KvXz8AdtttN/75z3+ybNkyXnrpJX7+85/nueXxiOMbyqVwGsqWVatWcdRRR7Hbbrtx00031Vh2wQUX0LFjRw455JB8NTf1GsqTNm3aMGvWrOrcOP/886uXXXHFFbz44ou89NJLXHnllXlsdXyUJ8XjySef5LDDDqN///7cfPPNuyx/5ZVXOOGEE9hnn3247bbbqh9/9dVXOfroo6tvnTp1YsKECflseioNHTqUf/zjHzzzzDNceumluyxv3bo1d999N0888QRPPfUUZ511FhAcmzz66KPVj1911VX5bnosGpslhcyT2IocM5tsZpvM7KW49hG1yspKLr30Uh5//HFWrlzJtGnTWLmy5veaPf7446xevZrVq1czadIkfvCDHwDQu3dvli1bxrJly1i8eDEtW7bk9NNPB+DEE0/kpZde4oUXXuCggw7i+uuvz/trS7qysjImTJjAyJEj6du3L2PGjKFPnz411vnxj3/MsmXL6N+/P2PHjq0O788//5wTTjihusAcMWIERxxxRG27SZW0hEg+pDFPMuWSLe3ateP3v/89P/rRj3Z5/vnnn8+cOXPy1dzUyyVPLr30UlauXMmAAQMYOnQoN998M82bN6dfv37867/+K0OGDKF///6ccsop9OzZs0CvJDrKky+lOU8qKyu56qqrmDFjBgsXLuShhx5i1apVNdZp164dv/3tb7niiitqPH7QQQfx7LPP8uyzz/L000+zxx578K1vfSufzU+dsrIyfv3rX3Puuedy/PHHM2rUKHr16lVjnfPOO4/Vq1czbNgwzjzzTH7605/SvHlzPv/8c8466yyGDRvG8OHDGTp0KIcffniBXkl0VOQEpgAjYtx+5BYsWEDPnj058MADadGiBaNHj2bmzJk11pk5cyZjx47FzDjyyCPZunUrb731Vo11nnrqKXr06EG3bt0AGDZsGOXlwcjAI488koqKivy8oBQZMmQIa9asYd26dezYsYPp06czatSoGuv07duXp556CgjOVB1wwAF07NgRgI8//hiA5s2b07x5c9yzv64hfdISInkyhZTlSaZcsqVjx44MHjyY5s2b7/L8Y489lnbt2uWruamXS564O61btwagVatWvPfee+zcuZM+ffrw/PPP8+mnn1JZWck//vGP6hNWaaY8qWEKKc2TRYsWceCBB9K9e3datGjBGWecwaOPPlpjnQ4dOjBw4MBas6TKvHnz6N69O1/72tfibnKqDRgwgNdff50333yTHTt2MHPmTIYNG1ZjHXdnzz33BGDPPfdk69at7Ny5E4BPPvkEgPLycsrLy0vy2KQoixx3nw+8F9f247Bhwwa6dv1y2v8uXbqwYcOGRq8zffp0xowZU+s+Jk+ezMiRIyNsdXHo3Lkz69d/+eXZFRUVdO7cucY6y5cv59vf/jYAgwcPplu3bnTp0gUIzrYsXbqUTZs28eSTT7JgwYL8NV5il8Y8yZRLbkh0csmT8ePH06dPHzZu3MiLL77IlVdeibvz0ksvVReVe+yxByeddFKN352kX5rz5K233qrxWe7cufMuJ1pz8dBDD3HmmWdG2bSitP/++9d4f99++23233//GutMmTKFXr16sXjxYv72t7/x05/+tLqYKSsrY+7cuSxfvpynn36apUuX5rX9pU7X5GSorcLOrkAbWmf79u3MmjWr1vC47rrrKC8v55xzzomgtcWltko/+72+4YYb2HvvvVm6dCmXX345S5curT5b8sUXX3DYYYfRpUsXhgwZUn29Tlql6UyJNCyXbJHo5JInw4cPZ9myZXTq1IkBAwYwfvx4WrduzapVq7jxxht58sknmTNnDsuXL6/OmbRSnhSPKLJk+/btzJ49uyh6KAsh+3cwdOhQVqxYwcCBAxk+fDi//vWvadWqFRAcmwwfPpzBgwczYMAAevfuXYgmR6YpWVKUPTm5MrOLzWyRmS169913C9qWLl267HL2r1OnTo1a5/HHH+fwww9n3333rfG8e+65h0cffZT77rtP/4HUoqKiYpcz3Rs31vzy7A8//JALLriAww47jLFjx9KhQwfWrVtXY50PPviAefPmMWJEKkci1JCWEEmKJGVJtlyyRaKTS558//vfZ8aMGQC89tprrFu3joMPPhgIetwHDhzIcccdx3vvvcfq1avz1/iYKE8aJzNPNm/eXOjmVOvUqVONXuANGzaw3377NWobTzzxBAMGDKge7i11e+utt2r03Oy33368/fbbNdY566yzePzxxwF4/fXXWb9+/S7X8W3bto3nnnuOoUOHxt7muKnIaQR3n+Tug9x9UIcOHQralsGDB7N69WrWrVvH9u3bmT59OqeeemqNdU499VSmTp2Ku/P888/Ttm3bGn8A06ZN22Wo2pw5c7jxxhuZNWsWLVu2zMtrSZuFCxfSq1cvDjjgAJo3b87o0aOZNWtWjXXatm1bPcb4oosuYv78+Xz44Ye0b9+etm3bArD77rvzzW9+c5cLMdMoLSGSFEnKkmy5ZItEJ5c8efPNN/nGN74BBNdD9e7dm7Vr1wLBNQ0AXbt25dvf/jbTpk3L7wuIgfKkcTLzpH379oVuTrWBAwfy2muv8frrr7N9+3YefvhhTj755EZt46GHHuI73/lOTC0sLsuXL6d79+507dqV5s2bM2rUKJ588ska62zYsIFjjjkGgPbt29OjRw/eeOMN2rVrR5s2bYDg2OSYY45hzZo1eX8NUUtTkaPvyclQXl7O+PHjGT58OJWVlVxwwQX069ePiROD7zYbN24cJ510ErNnz6Znz560bNmSu+++u/r5n3zyCU8++SR33HFHje1edtllfP7555x44olAMPlA1TYlUFlZyWWXXcbcuXNp1qwZkydPZuXKlVxyySUA3HHHHfTp04epU6dSWVnJypUrufDCC4FgzOw999xDs2bNKCsr44EHHuCxxx4r5MuJhA40ikcu2fL2228zaNAgtm3bRllZGbfeeisrV66kTZs2jBkzhnnz5rF582a6dOnCL37xi+rPv+wqlzz51a9+xZQpU3jhhRcwM6655hq2bNkCwMMPP8w+++zDjh07uPTSS4ti2n/lSXEoLy/npptu4rTTTuOLL77g3HPPpU+fPtx1110AXHjhhbzzzjsce+yxfPjhh5SVlXH77bezcOFC2rRpwyeffMLf//73GlNLS90qKyv5yU9+wn333UdZWRl//vOfefXVV/ne974HwL333sttt93GLbfcwt/+9jcAfvOb3/D+++/Tp08ffve739GsWTPMjEcffbR68qQ0S1OWWFwzPZjZNGAo0B54B/iZu99V33MG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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "# Confusion matrices (normalized) for customized thresholds\n", "cm_norm_03 = confusion_matrix(y_test, y_pred_03, normalize=\"true\")\n", "cm_norm_07 = confusion_matrix(y_test, y_pred_07, normalize=\"true\")\n", "fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(14, 5))\n", "fig.suptitle('Normalized confusion matrix for various thresholds')\n", "ax1.title.set_text('Threshold 0.3')\n", "ax2.title.set_text('Threshold 0.5')\n", "ax3.title.set_text('Threshold 0.7')\n", "ConfusionMatrixDisplay(cm_norm_03).plot(cmap=plt.cm.Greys, ax=ax1)\n", "ConfusionMatrixDisplay(cm_norm).plot(cmap=plt.cm.Greys, ax=ax2)\n", "ConfusionMatrixDisplay(cm_norm_07).plot(cmap=plt.cm.Greys, ax=ax3)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### On prediction probabilities\n", "\n", "- Probabilistic, e.g., Naïve Bayes \n", "\n", "- Non-probabilsitic, e.g., k-Nearest Neighbors (KNN), SVM\n", " - \"probabilities\" may be inferred, e.g., based on distance from decision boundaries\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Trade-off: Precision & Recall \n", "\n", "Relationship: Selected and relevant elements | Precision and Recall\n", ":-------------------------:|:-------------------------:\n", "\"bigpic\" | \"Sampling\"\n", "Image adapted from https://en.wikipedia.org/wiki/Precision_and_recall" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "- When trying to detect malignant tumors, will you prioritize precision or recall?\n", "\n", "- When trying to detect fraudulent credit-card transactions in real-time, will you prioritize precision or recall?\n", "\n", "- When making recommendations for jobs, what will give a person a better user experience?\n", " * Recall earlier discussions\n", " * Data Jujitsu" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Precision recall curve" ] }, { "cell_type": "code", "execution_count": 71, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "precision: [0.4805 0.45368421 0.42444444 0.39235294 0.35875 0.32133333\n", " 0.28357143 0.23769231 0.18583333 0.14454545 0.108 0.08333333\n", " 0.05875 0.05142857 0.04166667 0.032 0.0275 0.01666667\n", " 0.02 0.02 1. ] \n", "\n", " recall: [1. 0.89698231 0.7950052 0.69406868 0.59729448 0.50156087\n", " 0.41311134 0.32154006 0.23204995 0.16545265 0.11238293 0.0780437\n", " 0.04890739 0.03746098 0.02601457 0.01664932 0.01144641 0.00520291\n", " 0.00416233 0.00208117 0. ]\n" ] } ], "source": [ "# Precision recall curve\n", "from sklearn.metrics import precision_recall_curve\n", "from sklearn.metrics import PrecisionRecallDisplay\n", "predictions_prob=[x[0] for x in model3.predict_proba(cv3.transform(X_test))]\n", "precision, recall, _ = precision_recall_curve(y_test, predictions_prob)\n", "print(\"precision:\",precision[::100],\"\\n\\n\", \"recall:\",recall[::100])" ] }, { "cell_type": "code", "execution_count": 72, "metadata": { "scrolled": false, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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0aJF1bY/66yz+N3vfscvf/lLLr74Yjp16lTn8T7++GNef/318un4+Pjy92PGjGH//v20adOm/Kr5448/ZsOGn34VR48eJScnhy+//JL//Oc/AIwfP77Sfrp27crQoUMBWLp0KUuXLuX0008HIDc3lx9//JGRI0dy2223ceeddzJp0iRGjhxJcXExERERXHfddUycOLFaXX5tn1WZiy++GIBBgwaRnp5e7dz37t1LYmJi+XRhYSGLFy/m6aefJjY2liFDhrB06VImTpwIwBtvvMGXX35J8+bNef7552nVqlWl/Z1yyimkpqbW9XGXc0rcldXUomfcuHGsXLmS4cOHk5iYyLBhw8qTB8Arr7xCSUkJM2fO5I033mDatGmAU2rZs8d7T5QaA969WdwR2FVhOsM1r6phIrJGRD4QkRq/xUVkuoisEpFVBw8e9EasPlPTF0dNZs2axYsvvkh+fj5Dhw5l06ZNbvdbW5PCZcuWsWPHDk477TTuu+8+AEpLS1mxYgWpqamkpqaye/duYmNj64wvOjq60vHuuuuu8u23bNnCtddeS69evVi9ejX9+vXjrrvu4sEHHyQ0NJRvv/2WSy65hHfeeYfx48d79BmUKbvSDwkJobi4+gDekZGRldrUL1myhOzsbPr160dSUhJffvkl8+fPL18+depUUlNT+eabb5g8eXK1/dWnRJCQkEBWVlZ5XBkZGXTo0KHG87j77rtJTU3lo48+QlXp2bNnpeUhISFMnTqVBQsWlM8rKCggMjLSzSdkgsGBnONe27c3E0FN30pVv2W+A7qq6gDgL8A7Ne1IVV9Q1RRVTal45deYxcXFER8fX16s/8c//sGoUaOIj48nNjaWr7/+GqDSVXxFW7dupV+/ftx5552kpKSwadMmYmNjycnJqXH9cePG8eyzz5ZPHzlypNLyyMhI5syZw7x58zh8+HC19cuugEeMGMGbb74JOFf9VfdT5vzzz+fll18ub+Gye/duDhw4wJ49e4iKiuLKK6/ktttu47vvviM3N5fs7GwuuOAC5syZU+1qu7bPylO9evWqVFKYP38+L774Iunp6aSnp7N9+3aWLl1KXl6eR/srKxHU9GrZsmWldUWEMWPG8NZbbwHw2muvcdFFF1XbZ0lJCZmZmQCkpaWRlpbGuHHjUFW2bNkCOMl14cKF9O7du3y7H374gb59+3r8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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "PrecisionRecallDisplay.from_estimator(model3,cv3.transform(X_test),y_test)\n", "# What's the ideal point on/shape of the precision recall curve?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### $F$-score\n", "\n", "- Harmonic mean of precision and recall: $F_1=2 \\cdot \\frac{precision \\cdot recall}{precision + recall}$\n", "- If recall is considered $\\beta$ times as important as precision: $F_{\\beta} = (1+\\beta^2) \\cdot \\frac{precision \\cdot recall}{(\\beta^2 \\cdot precision) + recall}$\n", "\n", "Recall: We used it in the Network Science module, to quantify the quality of clusters" ] }, { "cell_type": "code", "execution_count": 73, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " precision recall f1-score support\n", "\n", " 0 0.89 0.86 0.88 1039\n", " 1 0.85 0.89 0.87 961\n", "\n", " accuracy 0.87 2000\n", " macro avg 0.87 0.87 0.87 2000\n", "weighted avg 0.87 0.87 0.87 2000\n", "\n" ] } ], "source": [ "print(classification_report(y_test,predictions))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Macro and Micro-averages\n", "\n", "\n", "* Macro: \n", " * Metric is computed independently for each class. \n", " * Each class is given equal weight when averaging. \n", " * Classes with small population have disproportionate influence\n", "\n", "* Micro: Each instance is given equal weight, and the metric is computed across all samples. \n", " * In the event of class-imbalance, size of classes have proportional influence\n", " " ] }, { "cell_type": "code", "execution_count": 74, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.8729491796718687\n", "0.8729999999999999\n" ] } ], "source": [ "# We are using a perfectly balanced data, so we don't expect to see much differences in this example\n", "# But here's how to compute the macro/micro metrics, using an average attribute.\n", "# Check manual for a few other choices, e.g. weighted\n", "print(f1_score(y_test, predictions, average='macro'))\n", "print(f1_score(y_test, predictions, average='micro'))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Receiver operating characteristic (ROC) & Area Under Curve (AUC)\n", "Etymology: Method's origins in operators of military radar receivers \n", "\n", "> The ROC curve plots the true positive rate (TPR), a.k.a., Recall or Sensitivity, along Y-axis, and the false positive rate (FPR) along X-axis, by varying decision thresholds. \n", "> - Determining the ROC in the multi-class case is non-trivial\n", "\n", "> ROC aides discard suboptimal models\n", "> ![ROC-zoomed.png](pics/ROCZoom.png)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "> AUC statistic is used for model comparison\n", "\n", "
\"ROC/AUC\"
\n", "Image source: Wikipedia article on ROC
" ] }, { "cell_type": "code", "execution_count": 75, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "from sklearn.metrics import roc_curve, auc\n", "# following code is adapted from \n", "# https://scikit-learn.org/stable/auto_examples/model_selection/plot_roc.html\n", "y_score = model3.decision_function(cv3.transform(X_test))\n", "# Compute ROC curve and ROC area for each class\n", "fpr, tpr, _ = roc_curve(y_test, y_score)\n", "roc_auc = auc(fpr, tpr)" ] }, { "cell_type": "code", "execution_count": 76, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "plt.figure()\n", "plt.plot(fpr, tpr, color='dodgerblue',\n", " lw=4, label='AUC = %0.3f' % roc_auc)\n", "plt.plot([0, 1], [0, 1], color='firebrick', lw=2, linestyle='--')\n", "plt.xlim([0, 1.01])\n", "plt.ylim([0, 1.01])\n", "plt.xlabel('False Positive Rate')\n", "plt.ylabel('True Positive Rate')\n", "plt.title('Receiver operating characteristic')\n", "plt.legend(loc=\"lower right\")\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 77, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['accuracy', 'adjusted_mutual_info_score', 'adjusted_rand_score', 'average_precision', 'balanced_accuracy', 'completeness_score', 'explained_variance', 'f1', 'f1_macro', 'f1_micro', 'f1_samples', 'f1_weighted', 'fowlkes_mallows_score', 'homogeneity_score', 'jaccard', 'jaccard_macro', 'jaccard_micro', 'jaccard_samples', 'jaccard_weighted', 'max_error', 'mutual_info_score', 'neg_brier_score', 'neg_log_loss', 'neg_mean_absolute_error', 'neg_mean_absolute_percentage_error', 'neg_mean_gamma_deviance', 'neg_mean_poisson_deviance', 'neg_mean_squared_error', 'neg_mean_squared_log_error', 'neg_median_absolute_error', 'neg_root_mean_squared_error', 'normalized_mutual_info_score', 'precision', 'precision_macro', 'precision_micro', 'precision_samples', 'precision_weighted', 'r2', 'rand_score', 'recall', 'recall_macro', 'recall_micro', 'recall_samples', 'recall_weighted', 'roc_auc', 'roc_auc_ovo', 'roc_auc_ovo_weighted', 'roc_auc_ovr', 'roc_auc_ovr_weighted', 'top_k_accuracy', 'v_measure_score']\n" ] } ], "source": [ "# measures supported in sklearn\n", "from sklearn.metrics import SCORERS\n", "print(sorted(list(SCORERS.keys())))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Multi-class data\n", "\n", "\n", "- Some classifiers can natively support multiple classes\n", " - Check more details at https://scikit-learn.org/stable/modules/multiclass.html\n", "- Some classifiers can only handle binary classes natively\n", " - They can be re-purposed for multi-class classification.\n", " * One versus Rest: N classifiers \n", " * Caution: An implicit source of imbalance\n", " * One versus One: ${N \\choose 2}$ classifiers\n", "\n", "One versus Rest | One versus One\n", ":-------------------------:|:-------------------------:\n", "\"OVR\" | \"OVO\"" ] }, { "cell_type": "code", "execution_count": 78, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "{False: 5, True: 145}" ] }, "execution_count": 78, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Scikit-learn allows to choose, e.g., SVC uses decision_function_shape{‘ovo’, ‘ovr’}, default=’ovr’\n", "# An alternative is to explicitly use the multiclass library \n", "from sklearn.multiclass import OneVsRestClassifier, OneVsOneClassifier\n", "from sklearn.preprocessing import StandardScaler\n", "from sklearn.svm import LinearSVC\n", "from sklearn import datasets\n", "iris_X, iris_y = datasets.load_iris(return_X_y=True)\n", "iris_X = StandardScaler().fit_transform(iris_X)\n", "# Caution: I have not used train/test splits in this example\n", "OvR=OneVsRestClassifier(LinearSVC(random_state=0)).fit(iris_X, iris_y).predict(iris_X)\n", "OvO=OneVsOneClassifier(LinearSVC(random_state=0)).fit(iris_X, iris_y).predict(iris_X)\n", "unique, counts = np.unique(OvR==OvO, return_counts=True)\n", "dict(zip(unique, counts))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Grid search\n", "Exploring the parameter space to identify good/optimal parameters\n", "- Parameter choices depend on the algorithm being used \n", "- See Scikit-learn examples for more details and sophisticated use cases. " ] }, { "cell_type": "code", "execution_count": 79, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "GridSearchCV(estimator=SVC(),\n", " param_grid={'C': range(1, 11, 2), 'kernel': ('linear', 'rbf')})" ] }, "execution_count": 79, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# A very basic example of Grid search \n", "from sklearn.ensemble import RandomForestClassifier \n", "from sklearn.model_selection import GridSearchCV\n", "iris = datasets.load_iris()\n", "iris_X, iris_y = datasets.load_iris(return_X_y=True)\n", "parameters = {'kernel':('linear', 'rbf'), 'C':range(1,11,2)}\n", "# Remember: Parameter choices depend on the algorithm being used\n", "svc = SVC()\n", "clf = GridSearchCV(estimator=svc, param_grid=parameters)\n", "clf.fit(iris_X, iris_y)" ] }, { "cell_type": "code", "execution_count": 80, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['mean_fit_time', 'std_fit_time', 'mean_score_time', 'std_score_time', 'param_C', 'param_kernel', 'params', 'split0_test_score', 'split1_test_score', 'split2_test_score', 'split3_test_score', 'split4_test_score', 'mean_test_score', 'std_test_score', 'rank_test_score']\n" ] } ], "source": [ "results=clf.cv_results_\n", "# What all is available in the results?\n", "print(list(results.keys()))" ] }, { "cell_type": "code", "execution_count": 81, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([0.98 , 0.96666667, 0.97333333, 0.98 , 0.98 ,\n", " 0.98666667, 0.97333333, 0.98666667, 0.97333333, 0.98 ])" ] }, "execution_count": 81, "metadata": {}, "output_type": "execute_result" } ], "source": [ "results['mean_test_score']" ] }, { "cell_type": "code", "execution_count": 82, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([ 3, 10, 7, 3, 3, 1, 7, 1, 7, 3])" ] }, "execution_count": 82, "metadata": {}, "output_type": "execute_result" } ], "source": [ "results['rank_test_score']" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "#### Model tuning and evaluation wrap-up\n", "\n", "- Our discussion was anchored around supervised learning, and for Classification task in particular\n", " * Metrics for Regression are simpler, e.g., r2 score, mean absolute error, etc\n", " * For unsupervised learning, e.g., Clustering, some of the measures we saw here, e.g., F-score can be repurposed, if (a big IF!) the \"ground truth\" is known. \n", "- While many measures exist and several/all of them can be used to understand the general behaviour of the models, final evaluation and optimization may need to be use-case driven.\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Transformations\n", "- Revisting representation phase of the ML-lifecycle\n", " - We have already discussed some basics: Data cleaning, removal of samples with missing values, syntactic conversion of information so that the algorithms can \"consume\" the data (e.g., CountVectorizer) \n", " - Standardization: Normalization, scaling, etc.\n", " * See sklearn.preprocessing\n", " * StandardScaler: Standardize features by removing the mean and scaling to unit variance.\n", " * MinMaxScaler: Transform features by scaling each feature to a given range." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Transformations\n", "- Revisting representation\n", " - Data embedding/dimensionality reduction: Principal Component Analysis (PCA), Linear discriminant analysis (LDA), manifold, etc.\n", " \n", "Recommended reading: Blog showcasing multiple dimensionality reduction techniques. " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Philosophical tangent: PCA vs LDA \n", "PCA | LDA\n", ":-------------------------:|:-------------------------:\n", "\"bigpic\" | \"Sampling\"\n", "Image source https://sebastianraschka.com/. See also scikit-learn PCA & LDA usage example." ] }, { "cell_type": "code", "execution_count": 83, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "# The following example of using PCA, Standardization and make_pipeline is adapted from \n", "# https://scikit-learn.org/stable/auto_examples/preprocessing/plot_scaling_importance.html#sphx-glr-auto-examples-preprocessing-plot-scaling-importance-py\n", "# It has been made available under License: BSD 3 clause by\n", "# Tyler Lanigan and Sebastian Raschka \n", "\n", "from sklearn.preprocessing import StandardScaler, MinMaxScaler\n", "from sklearn.decomposition import PCA\n", "from sklearn.naive_bayes import GaussianNB\n", "from sklearn import metrics\n", "from sklearn.datasets import load_wine\n", "from sklearn.pipeline import make_pipeline\n", "RANDOM_STATE = 42\n", "FIG_SIZE = (10, 4)" ] }, { "cell_type": "code", "execution_count": 84, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "features, target = load_wine(return_X_y=True)\n", "# 2:1 Train-Test split\n", "X_train_wine, X_test_wine, y_train_wine, y_test_wine = train_test_split(features, target,\n", " test_size=0.33,\n", " random_state=RANDOM_STATE) \n", "# Fit the raw data and predict using GNB following PCA.\n", "unscaled_clf = make_pipeline(PCA(n_components=2), GaussianNB())\n", "unscaled_clf.fit(X_train_wine, y_train_wine)\n", "pred_test2 = unscaled_clf.predict(X_test_wine)\n", "# Using PCA with 3 components\n", "unscaled_clf = make_pipeline(PCA(n_components=3), GaussianNB())\n", "unscaled_clf.fit(X_train_wine, y_train_wine)\n", "pred_test3 = unscaled_clf.predict(X_test_wine)" ] }, { "cell_type": "code", "execution_count": 85, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "PCA (2 components) + GNB \n", " precision recall f1-score support\n", "\n", " 0 0.95 1.00 0.98 20\n", " 1 0.78 0.75 0.77 24\n", " 2 0.60 0.60 0.60 15\n", "\n", " accuracy 0.80 59\n", " macro avg 0.78 0.78 0.78 59\n", "weighted avg 0.79 0.80 0.79 59\n", "\n", "PCA (3 components) + GNB \n", " precision recall f1-score support\n", "\n", " 0 1.00 1.00 1.00 20\n", " 1 0.88 0.92 0.90 24\n", " 2 0.86 0.80 0.83 15\n", "\n", " accuracy 0.92 59\n", " macro avg 0.91 0.91 0.91 59\n", "weighted avg 0.91 0.92 0.91 59\n", "\n" ] } ], "source": [ "print(\"PCA (2 components) + GNB \\n\", metrics.classification_report(y_test_wine, pred_test2))\n", "print(\"PCA (3 components) + GNB \\n\", metrics.classification_report(y_test_wine, pred_test3))" ] }, { "cell_type": "code", "execution_count": 86, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Standardization + PCA (2 components) + GNB \n", " precision recall f1-score support\n", "\n", " 0 1.00 0.95 0.97 20\n", " 1 0.96 1.00 0.98 24\n", " 2 1.00 1.00 1.00 15\n", "\n", " accuracy 0.98 59\n", " macro avg 0.99 0.98 0.98 59\n", "weighted avg 0.98 0.98 0.98 59\n", "\n" ] } ], "source": [ "# Fit to data and predict using a pipeline of scaling/standardization, PCA and GNB.\n", "std_clf = make_pipeline(StandardScaler(), PCA(n_components=2), GaussianNB())\n", "# try using MinMaxScaler and see what you get!\n", "std_clf.fit(X_train_wine, y_train_wine)\n", "pred_test_std = std_clf.predict(X_test_wine)\n", "print(\"Standardization + PCA (2 components) + GNB \\n\", metrics.classification_report(y_test_wine, pred_test_std))" ] }, { "cell_type": "code", "execution_count": 87, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "PC 1 without scaling:\n", " [ 1.77738063e-03 -8.13532033e-04 1.41672133e-04 -5.43218358e-03\n", " 1.96719103e-02 1.04099788e-03 1.54504422e-03 -1.15638097e-04\n", " 6.52261761e-04 2.26846944e-03 1.61421529e-04 7.81011292e-04\n", " 9.99784964e-01]\n", "\n", "PC 1 with scaling:\n", " [ 0.14733424 -0.25027499 -0.01252058 -0.23440896 0.15738948 0.39369045\n", " 0.41565632 -0.27414911 0.33265958 -0.10517746 0.29234204 0.38195327\n", " 0.28245765]\n" ] } ], "source": [ "# Extract PCA from pipeline\n", "pca = unscaled_clf.named_steps['pca']\n", "pca_std = std_clf.named_steps['pca']\n", "\n", "# Show first principal components\n", "print('\\nPC 1 without scaling:\\n', pca.components_[0])\n", "print('\\nPC 1 with scaling:\\n', pca_std.components_[0])\n", "\n", "# Use PCA without and with scale on X_train data for visualization.\n", "X_train_transformed = pca.transform(X_train_wine)\n", "scaler = std_clf.named_steps['standardscaler']\n", "X_train_std_transformed = pca_std.transform(scaler.transform(X_train_wine))" ] }, { "cell_type": "code", "execution_count": 88, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=FIG_SIZE)\n", "for l, c, m in zip(range(0, 3), ('blue', 'red', 'green'), ('^', 's', 'o')):\n", " ax1.scatter(X_train_transformed[y_train_wine == l, 0],\n", " X_train_transformed[y_train_wine == l, 1],\n", " color=c, label='class %s' % l, alpha=0.5, marker=m)\n", "for l, c, m in zip(range(0, 3), ('blue', 'red', 'green'), ('^', 's', 'o')):\n", " ax2.scatter(X_train_std_transformed[y_train_wine == l, 0],\n", " X_train_std_transformed[y_train_wine == l, 1],\n", " color=c, label='class %s' % l, alpha=0.5, marker=m) \n", "ax1.set_title('Training dataset after PCA')\n", "ax2.set_title('Standardized training dataset after PCA')\n", "for ax in (ax1, ax2):\n", " ax.set_xlabel('1st principal component')\n", " ax.set_ylabel('2nd principal component')\n", " ax.legend(loc='upper right')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "#### Ungraded task 6.3\n", "\n", "Consider the Iris dataset from sklearn. \n", "Build and evaluate classifiers by following the various principles discussed in this module, e.g., taking into account class imbalance (if any), difference in scales of features, number of dimensions, choice of classifier algorithms and parameters there-in. \n", "\n", "Share your code along with a summary of the classification report (and any other measures and tools, e.g. plotting the results from grid search) achieved by the \"best\" model you can train. \n", "\n", "> To get started: from sklearn.datasets import load_iris " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "
\n", " That's it folks!
\n", "\"Do\n", "
\n" ] } ], "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.8.5" } }, "nbformat": 4, "nbformat_minor": 4 }