{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Managing textual data using *pandas*\n", "\n", "This section introduces how to prepare and manage textual data for analysis using *[pandas](http://pandas.pydata.org/)*, a Python library for working with tabular data.\n", "\n", "After reading this section, you should know:\n", "\n", "- how to import data into a *pandas* DataFrame\n", "- how to explore data stored in a *pandas* DataFrame\n", "- how to append data to a *pandas* DataFrame\n", "- how to save the data in a *pandas* DataFrame" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Importing data to *pandas*\n", "\n", "Let's start by importing the *pandas* library. \n", "\n", "Note that we can control the name of the imported module using the `as` addition to the `import` command. *pandas* is commonly abbreviated `pd`.\n", "\n", "This allows us to use the variable `pd` to refer to the *pandas* library." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "import pandas as pd" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Importing data from a single file\n", "\n", "You must often load and prepare the data yourself, either from a single file or from multiple files.\n", "\n", "Typical formats for distributing corpora include CSV files, which stands for Comma-separated Values, and JSON, which stands for JavaScript Object Notation or simple plain text files.\n", "\n", "*pandas* provides plenty of functions for [reading data in various formats](https://pandas.pydata.org/pandas-docs/stable/user_guide/io.html). You can even try importing Excel sheets!\n", "\n", "The following example shows how to load a corpus from a CSV file for processing in Python using the [SFU Opinion and Comments Corpus (SOCC)](https://github.com/sfu-discourse-lab/SOCC) (Kolhatkar et al. [2020](https://doi.org/10.1007/s41701-019-00065-w)).\n", "\n", "Let's load a part of the SFU Opinion and Comments Corpus, which contains the opinion articles from [The Globe and Mail](https://www.theglobeandmail.com/), a Canadian newspaper.\n", "\n", "We can use the `read_csv()` function from *pandas* to read files with comma-separated values, such as the SOCC corpus.\n", "\n", "The `read_csv()` function takes a string object as input, which defines a path to the input file." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "# Read the CSV file and assign the output to the variable 'socc'\n", "socc = pd.read_csv('data/socc_gnm_articles.csv')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*pandas* does all the heavy lifting and returns the contents of the CSV file in a *pandas* [DataFrame](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html), which is data structure native to *pandas*." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "pandas.core.frame.DataFrame" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Examine the type of the object stored under the variable 'socc'\n", "type(socc)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's use the `head()` method of a DataFrame to check out the first five rows in the DataFrame." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " | article_id | \n", "title | \n", "article_url | \n", "author | \n", "published_date | \n", "ncomments | \n", "ntop_level_comments | \n", "article_text | \n", "
---|---|---|---|---|---|---|---|---|
0 | \n", "26842506 | \n", "The Tories deserve another mandate - Stephen H... | \n", "http://www.theglobeandmail.com/opinion/editori... | \n", "GLOBE EDITORIAL | \n", "2015-10-16 EDT | \n", "2187.0 | \n", "1378.0 | \n", "<p>All elections are choices among imperfect a... | \n", "
1 | \n", "26055892 | \n", "Harper hysteria a sign of closed liberal minds | \n", "http://www.theglobeandmail.com/opinion/harper-... | \n", "Konrad Yakabuski | \n", "2015-08-24 EDT | \n", "1103.0 | \n", "455.0 | \n", "<p>If even a fraction of the darkness that his... | \n", "
2 | \n", "6929035 | \n", "Too many first nations people live in a dream ... | \n", "http://www.theglobeandmail.com/opinion/too-man... | \n", "Jeffrey Simpson | \n", "2013-01-05 EST | \n", "1164.0 | \n", "433.0 | \n", "<p>Large elements of aboriginal Canada live in... | \n", "
3 | \n", "19047636 | \n", "The Globe's editorial board endorses Tim Hudak... | \n", "http://www.theglobeandmail.com/opinion/editori... | \n", "GLOBE EDITORIAL | \n", "2014-06-06 EDT | \n", "905.0 | \n", "432.0 | \n", "<p>Over four days, The Globe editorial board l... | \n", "
4 | \n", "11672346 | \n", "Disgruntled Arab states look to strip Canada o... | \n", "http://www.theglobeandmail.com/news/world/disg... | \n", "Campbell Clark | \n", "2013-05-02 EDT | \n", "1129.0 | \n", "411.0 | \n", "<p>Growing discontent among Arab nations over ... | \n", "
All elections are choices among imperfect a... \n", "1
If even a fraction of the darkness that his... \n", "2
Large elements of aboriginal Canada live in... \n", "3
Over four days, The Globe editorial board l... \n", "4
Growing discontent among Arab nations over ... " ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "socc.head(5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As you can see, the DataFrame has a tabular form.\n", "\n", "The DataFrame contains several columns such as **article_id**, **title** and **article_text**, accompanied by an index for each row (**0, 1, 2, 3, 4**).\n", "\n", "The `.at[]` accessor can be used to inspect a single item in the DataFrame.\n", "\n", "Let's examine the value in the column **title** at index 123." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"How Toronto got a 'world-class,' gold-plated, half-billion-dollar empty train\"" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "socc.at[123, 'title']" ] }, { "cell_type": "markdown", "metadata": { "nbsphinx": "hidden" }, "source": [ "### Quick exercise\n", "\n", "Let's go back to the SOCC corpus stored under the variable `socc`.\n", "\n", "Who is the author (`author`) of article at index 256? \n", "\n", "How many top-level comments (`ntop_level_comments`) did the article at index 1000 receive?" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "nbsphinx": "hidden" }, "outputs": [], "source": [ "### Enter your code below this line and run the cell (press Shift and Enter at the same time)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Importing data from multiple files\n", "\n", "Another common scenario is that you have multiple files with text data, which you want to load into *pandas*.\n", "\n", "Let's first collect the files that we want to load." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[PosixPath('data/WP_1990-08-10-25A.txt'),\n", " PosixPath('data/NYT_1991-01-16-A15.txt'),\n", " PosixPath('data/WP_1991-01-17-A1B.txt')]" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Import the patch library\n", "from pathlib import Path\n", "\n", "# Create a Path object that points to the directory with data\n", "corpus_dir = Path('data')\n", "\n", "# Get all .txt files in the corpus directory\n", "corpus_files = list(corpus_dir.glob('*.txt'))\n", "\n", "# Check the corpus files\n", "corpus_files" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To accommodate our data, let's create an empty pandas DataFrame and specify its *shape* in advance, that is, the number of rows (`index`) and the names of the columns `columns`.\n", "\n", "We can determine the number of rows needed using Python's `range()` function. This function generates a list of numbers that fall within certain range, which we can use for the index of the DataFrame.\n", "\n", "In this case, we define a `range()` between `0` and the number of text files in the directory, which are stored under the variable `corpus_files`. We retrieve their number using the `len()` function, which returns the length of Python objects, if applicable.\n", "\n", "For the columns of the DataFrame, we simply create columns for filenames and their textual content by providing a list of strings to the `columns` argument." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " | filename | \n", "text | \n", "
---|---|---|
0 | \n", "NaN | \n", "NaN | \n", "
1 | \n", "NaN | \n", "NaN | \n", "
2 | \n", "NaN | \n", "NaN | \n", "
\n", " | filename | \n", "text | \n", "
---|---|---|
0 | \n", "WP_1990-08-10-25A.txt | \n", "*We Don’t Stand for Bullies': Diverse Voices ... | \n", "
1 | \n", "NYT_1991-01-16-A15.txt | \n", "U.S. TAKING STEPS TO CURB TERRORISM: F.B.I. I... | \n", "
2 | \n", "WP_1991-01-17-A1B.txt | \n", "U.S., Allies Launch Massive Air War Against T... | \n", "
\n", " | article_id | \n", "title | \n", "article_url | \n", "author | \n", "published_date | \n", "ncomments | \n", "ntop_level_comments | \n", "article_text | \n", "
---|---|---|---|---|---|---|---|---|
7797 | \n", "33441604 | \n", "Joseph Boyden, where are you from? | \n", "http://www.theglobeandmail.com/opinion/joseph-... | \n", "Hayden King | \n", "2016-12-28 EST | \n", "0.0 | \n", "0.0 | \n", "<p>Hayden King teaches in the School of Public... | \n", "
7798 | \n", "33316285 | \n", "Globe editorial: Rejoice! Congress just gave t... | \n", "http://www.theglobeandmail.com/opinion/editori... | \n", "GLOBE EDITORIAL | \n", "2016-12-13 EST | \n", "0.0 | \n", "0.0 | \n", "<p>The United States may have just elected a p... | \n", "
7799 | \n", "33009790 | \n", "Police and La Presse: Warrants not warranted | \n", "http://www.theglobeandmail.com/opinion/editori... | \n", "GLOBE EDITORIAL | \n", "2016-11-23 EST | \n", "0.0 | \n", "0.0 | \n", "<p>The discovery that the Montreal Police obta... | \n", "
7800 | \n", "32970624 | \n", "The Galloway affair: Salem comes to UBC | \n", "http://www.theglobeandmail.com/opinion/the-gal... | \n", "Margaret Wente | \n", "2016-11-22 EST | \n", "0.0 | \n", "0.0 | \n", "<p>I have a question about the Steven Galloway... | \n", "
7801 | \n", "32927142 | \n", "Justice delayed: the law of unintended consequ... | \n", "http://www.theglobeandmail.com/opinion/unreaso... | \n", "BENJAMIN PERRIN | \n", "2016-11-19 EST | \n", "0.0 | \n", "0.0 | \n", "<p>Benjamin Perrin is a law professor at the U... | \n", "
... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "
10334 | \n", "533784 | \n", "WTO action on China's rare-earth quotas makes ... | \n", "http://www.theglobeandmail.com/opinion/editori... | \n", "GLOBE EDITORIAL | \n", "2012-03-14 EDT | \n", "0.0 | \n", "0.0 | \n", "<p>The confusingly named substances known as '... | \n", "
10335 | \n", "533594 | \n", "A customer-friendly Finance Department | \n", "http://www.theglobeandmail.com/opinion/editori... | \n", "GLOBE EDITORIAL | \n", "2012-03-13 EDT | \n", "0.0 | \n", "0.0 | \n", "<p>Of the many things that frustrate the retai... | \n", "
10336 | \n", "533508 | \n", "Video raises questions about Nik Zoricic's 'fr... | \n", "http://www.theglobeandmail.com/opinion/editori... | \n", "GLOBE EDITORIAL | \n", "2012-03-12 EDT | \n", "0.0 | \n", "0.0 | \n", "<p>Officials and fans are mourning the death o... | \n", "
10337 | \n", "533504 | \n", "McGuinty can't afford misgivings about gaming | \n", "http://www.theglobeandmail.com/news/politics/m... | \n", "Adam Radwanski | \n", "2012-03-12 EDT | \n", "0.0 | \n", "0.0 | \n", "<p>Unlike so many of the other measures that m... | \n", "
10338 | \n", "533471 | \n", "In Russia, Canada should look for investment, ... | \n", "http://www.theglobeandmail.com/opinion/editori... | \n", "GLOBE EDITORIAL | \n", "2012-03-12 EDT | \n", "0.0 | \n", "0.0 | \n", "<p>As if in swift response to Prime Minister V... | \n", "
2542 rows × 8 columns
\n", "Hayden King teaches in the School of Public... \n", "7798
The United States may have just elected a p... \n", "7799
The discovery that the Montreal Police obta... \n", "7800
I have a question about the Steven Galloway... \n", "7801
Benjamin Perrin is a law professor at the U... \n", "... ... \n", "10334
The confusingly named substances known as '... \n", "10335
Of the many things that frustrate the retai... \n", "10336
Officials and fans are mourning the death o... \n", "10337
Unlike so many of the other measures that m... \n", "10338
As if in swift response to Prime Minister V... \n", "\n", "[2542 rows x 8 columns]" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "socc.loc[socc['ntop_level_comments'] == 0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This returns a total of 2542 rows where the value of the column `ntop_level_comments` is zero.\n", "\n", "For more complex views of the data, we can also combine multiple criteria using the `&` symbol, which is the Python operator for \"AND\".\n", "\n", "Note that individual criteria must be placed in parentheses `()` to perform the operation.\n", "\n", "Let's check if the first author in our result, Hayden King, wrote any other articles with zero comments." ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " | article_id | \n", "title | \n", "article_url | \n", "author | \n", "published_date | \n", "ncomments | \n", "ntop_level_comments | \n", "article_text | \n", "
---|---|---|---|---|---|---|---|---|
7797 | \n", "33441604 | \n", "Joseph Boyden, where are you from? | \n", "http://www.theglobeandmail.com/opinion/joseph-... | \n", "Hayden King | \n", "2016-12-28 EST | \n", "0.0 | \n", "0.0 | \n", "<p>Hayden King teaches in the School of Public... | \n", "
Hayden King teaches in the School of Public... " ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "socc.loc[(socc['ntop_level_comments'] == 0) & (socc['author'] == 'Hayden King')]" ] }, { "cell_type": "markdown", "metadata": { "nbsphinx": "hidden" }, "source": [ "### Quick in-class exercise\n", "\n", "How many articles with zero top-level comments were authored by the editorial team (`GLOBE EDITORIAL`)?\n", "\n", "Write out the whole command yourself instead of copy-pasting to get an idea of the syntax." ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "nbsphinx": "hidden" }, "outputs": [], "source": [ "### Enter your code below this line and run the cell (press Shift and Enter at the same time)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Extending DataFrames\n", "\n", "You can easily add information to *pandas* DataFrames.\n", "\n", "One common scenario could involve loading some data from an external file (such as a CSV or JSON file), performing some analyses and storing the results to the same DataFrame.\n", "\n", "We can easily add an empty column to the DataFrame. This is achieved using the column accessor `[]` and the Python datatype `None`.\n", "\n", "Let's add a new column named `comments_ratio` to the DataFrame `socc`." ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [], "source": [ "socc['comments_ratio'] = None" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " | article_id | \n", "title | \n", "article_url | \n", "author | \n", "published_date | \n", "ncomments | \n", "ntop_level_comments | \n", "article_text | \n", "comments_ratio | \n", "
---|---|---|---|---|---|---|---|---|---|
0 | \n", "26842506 | \n", "The Tories deserve another mandate - Stephen H... | \n", "http://www.theglobeandmail.com/opinion/editori... | \n", "GLOBE EDITORIAL | \n", "2015-10-16 EDT | \n", "2187.0 | \n", "1378.0 | \n", "<p>All elections are choices among imperfect a... | \n", "None | \n", "
1 | \n", "26055892 | \n", "Harper hysteria a sign of closed liberal minds | \n", "http://www.theglobeandmail.com/opinion/harper-... | \n", "Konrad Yakabuski | \n", "2015-08-24 EDT | \n", "1103.0 | \n", "455.0 | \n", "<p>If even a fraction of the darkness that his... | \n", "None | \n", "
2 | \n", "6929035 | \n", "Too many first nations people live in a dream ... | \n", "http://www.theglobeandmail.com/opinion/too-man... | \n", "Jeffrey Simpson | \n", "2013-01-05 EST | \n", "1164.0 | \n", "433.0 | \n", "<p>Large elements of aboriginal Canada live in... | \n", "None | \n", "
3 | \n", "19047636 | \n", "The Globe's editorial board endorses Tim Hudak... | \n", "http://www.theglobeandmail.com/opinion/editori... | \n", "GLOBE EDITORIAL | \n", "2014-06-06 EDT | \n", "905.0 | \n", "432.0 | \n", "<p>Over four days, The Globe editorial board l... | \n", "None | \n", "
4 | \n", "11672346 | \n", "Disgruntled Arab states look to strip Canada o... | \n", "http://www.theglobeandmail.com/news/world/disg... | \n", "Campbell Clark | \n", "2013-05-02 EDT | \n", "1129.0 | \n", "411.0 | \n", "<p>Growing discontent among Arab nations over ... | \n", "None | \n", "
All elections are choices among imperfect a... None \n", "1
If even a fraction of the darkness that his... None \n", "2
Large elements of aboriginal Canada live in... None \n", "3
Over four days, The Globe editorial board l... None \n", "4
Growing discontent among Arab nations over ... None " ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "socc.head(5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's populate the column with some data by calculating which percentage of the comments are top-level comments, assuming that a high percentage of top-level comments indicates comments about the article, whereas a lower percentage indicates more discussion about the comments posted.\n", "\n", "To get the proportion of top-level comments out of all comments, we must divide the number of top-level comments by the number of all comments." ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [], "source": [ "socc['comments_ratio'] = socc['ntop_level_comments'] / socc['ncomments']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Column accessors can be used very flexibly to access and manipulate data stored in the DataFrame, as exemplified by the division." ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " | article_id | \n", "title | \n", "article_url | \n", "author | \n", "published_date | \n", "ncomments | \n", "ntop_level_comments | \n", "article_text | \n", "comments_ratio | \n", "
---|---|---|---|---|---|---|---|---|---|
0 | \n", "26842506 | \n", "The Tories deserve another mandate - Stephen H... | \n", "http://www.theglobeandmail.com/opinion/editori... | \n", "GLOBE EDITORIAL | \n", "2015-10-16 EDT | \n", "2187.0 | \n", "1378.0 | \n", "<p>All elections are choices among imperfect a... | \n", "0.630087 | \n", "
1 | \n", "26055892 | \n", "Harper hysteria a sign of closed liberal minds | \n", "http://www.theglobeandmail.com/opinion/harper-... | \n", "Konrad Yakabuski | \n", "2015-08-24 EDT | \n", "1103.0 | \n", "455.0 | \n", "<p>If even a fraction of the darkness that his... | \n", "0.412511 | \n", "
2 | \n", "6929035 | \n", "Too many first nations people live in a dream ... | \n", "http://www.theglobeandmail.com/opinion/too-man... | \n", "Jeffrey Simpson | \n", "2013-01-05 EST | \n", "1164.0 | \n", "433.0 | \n", "<p>Large elements of aboriginal Canada live in... | \n", "0.371993 | \n", "
3 | \n", "19047636 | \n", "The Globe's editorial board endorses Tim Hudak... | \n", "http://www.theglobeandmail.com/opinion/editori... | \n", "GLOBE EDITORIAL | \n", "2014-06-06 EDT | \n", "905.0 | \n", "432.0 | \n", "<p>Over four days, The Globe editorial board l... | \n", "0.477348 | \n", "
4 | \n", "11672346 | \n", "Disgruntled Arab states look to strip Canada o... | \n", "http://www.theglobeandmail.com/news/world/disg... | \n", "Campbell Clark | \n", "2013-05-02 EDT | \n", "1129.0 | \n", "411.0 | \n", "<p>Growing discontent among Arab nations over ... | \n", "0.364039 | \n", "
All elections are choices among imperfect a... 0.630087 \n", "1
If even a fraction of the darkness that his... 0.412511 \n", "2
Large elements of aboriginal Canada live in... 0.371993 \n", "3
Over four days, The Globe editorial board l... 0.477348 \n", "4
Growing discontent among Arab nations over ... 0.364039 " ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "socc.head(5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As you can see, the column `comments_ratio` now stores the result of our calculation!\n", "\n", "However, we should also keep in mind that some articles did not receive any comments at all: thus we would have divided zero by zero.\n", "\n", "Let's examine these cases again by retrieving articles without comments, and use the `.head()` method to limit the output to the first five rows." ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " | article_id | \n", "title | \n", "article_url | \n", "author | \n", "published_date | \n", "ncomments | \n", "ntop_level_comments | \n", "article_text | \n", "comments_ratio | \n", "
---|---|---|---|---|---|---|---|---|---|
7797 | \n", "33441604 | \n", "Joseph Boyden, where are you from? | \n", "http://www.theglobeandmail.com/opinion/joseph-... | \n", "Hayden King | \n", "2016-12-28 EST | \n", "0.0 | \n", "0.0 | \n", "<p>Hayden King teaches in the School of Public... | \n", "NaN | \n", "
7798 | \n", "33316285 | \n", "Globe editorial: Rejoice! Congress just gave t... | \n", "http://www.theglobeandmail.com/opinion/editori... | \n", "GLOBE EDITORIAL | \n", "2016-12-13 EST | \n", "0.0 | \n", "0.0 | \n", "<p>The United States may have just elected a p... | \n", "NaN | \n", "
7799 | \n", "33009790 | \n", "Police and La Presse: Warrants not warranted | \n", "http://www.theglobeandmail.com/opinion/editori... | \n", "GLOBE EDITORIAL | \n", "2016-11-23 EST | \n", "0.0 | \n", "0.0 | \n", "<p>The discovery that the Montreal Police obta... | \n", "NaN | \n", "
7800 | \n", "32970624 | \n", "The Galloway affair: Salem comes to UBC | \n", "http://www.theglobeandmail.com/opinion/the-gal... | \n", "Margaret Wente | \n", "2016-11-22 EST | \n", "0.0 | \n", "0.0 | \n", "<p>I have a question about the Steven Galloway... | \n", "NaN | \n", "
7801 | \n", "32927142 | \n", "Justice delayed: the law of unintended consequ... | \n", "http://www.theglobeandmail.com/opinion/unreaso... | \n", "BENJAMIN PERRIN | \n", "2016-11-19 EST | \n", "0.0 | \n", "0.0 | \n", "<p>Benjamin Perrin is a law professor at the U... | \n", "NaN | \n", "
Hayden King teaches in the School of Public... NaN \n", "7798
The United States may have just elected a p... NaN \n", "7799
The discovery that the Montreal Police obta... NaN \n", "7800
I have a question about the Steven Galloway... NaN \n", "7801
Benjamin Perrin is a law professor at the U... NaN " ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "socc.loc[socc['ntop_level_comments'] == 0].head(5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For these rows, the `comments_ratio` column contains values marked as `NaN` or \"not a number\".\n", "\n", "This indicates that the division was performed on these cells as well, but the result was not a number.\n", "\n", "*pandas* automatically ignores `NaN` values when performing calculations, as show by the `.describe()` method." ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "count 7797.000000\n", "mean 0.537057\n", "std 0.205398\n", "min 0.083333\n", "25% 0.384615\n", "50% 0.485714\n", "75% 0.647059\n", "max 1.000000\n", "Name: comments_ratio, dtype: float64" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "socc['comments_ratio'].describe()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note the difference in the result for the count. Only 7797 items out of 10399 were included in the calculation." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "What if we would like to do some natural language processing and store the results in the DataFrame?\n", "\n", "Let's select articles that fall within the first quartile in terms of the ratio of original comments to all comments made (`comments_ratio`) and have received more than 200 comments (`ncomments`). " ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " | article_id | \n", "title | \n", "article_url | \n", "author | \n", "published_date | \n", "ncomments | \n", "ntop_level_comments | \n", "article_text | \n", "comments_ratio | \n", "
---|---|---|---|---|---|---|---|---|---|
2 | \n", "6929035 | \n", "Too many first nations people live in a dream ... | \n", "http://www.theglobeandmail.com/opinion/too-man... | \n", "Jeffrey Simpson | \n", "2013-01-05 EST | \n", "1164.0 | \n", "433.0 | \n", "<p>Large elements of aboriginal Canada live in... | \n", "0.371993 | \n", "
4 | \n", "11672346 | \n", "Disgruntled Arab states look to strip Canada o... | \n", "http://www.theglobeandmail.com/news/world/disg... | \n", "Campbell Clark | \n", "2013-05-02 EDT | \n", "1129.0 | \n", "411.0 | \n", "<p>Growing discontent among Arab nations over ... | \n", "0.364039 | \n", "
5 | \n", "26691065 | \n", "Fifty years in Canada, and now I feel like a s... | \n", "http://www.theglobeandmail.com/opinion/fifty-y... | \n", "SHEEMA KHAN | \n", "2015-10-07 EDT | \n", "1142.0 | \n", "376.0 | \n", "<p>'Too broken to write,' I told my editor, af... | \n", "0.329247 | \n", "
6 | \n", "25731634 | \n", "I'm Canadian - and I should have a right to vote | \n", "http://www.theglobeandmail.com/opinion/im-cana... | \n", "Donald Sutherland | \n", "2015-07-28 EDT | \n", "1021.0 | \n", "348.0 | \n", "<p>My name is Donald Sutherland. My wife's nam... | \n", "0.340842 | \n", "
8 | \n", "13647608 | \n", "A nation of $100,000 firefighters | \n", "http://www.theglobeandmail.com/opinion/a-natio... | \n", "Margaret Wente | \n", "2013-08-08 EDT | \n", "1102.0 | \n", "338.0 | \n", "<p>Everyone loves firefighters. They save live... | \n", "0.306715 | \n", "
Large elements of aboriginal Canada live in... 0.371993 \n", "4
Growing discontent among Arab nations over ... 0.364039 \n", "5
'Too broken to write,' I told my editor, af... 0.329247 \n", "6
My name is Donald Sutherland. My wife's nam... 0.340842 \n", "8
Everyone loves firefighters. They save live... 0.306715 " ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Filter the DataFrame for highly commented articles and assign the result to the variable 'talk'\n", "talk = socc.loc[(socc['comments_ratio'] <= 0.384) & (socc['ncomments'] >= 200)]\n", "\n", "# Call the variable to examine the output\n", "talk.head(5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's import spaCy, load a medium-sized language model for English and assign this model to the variable `nlp`." ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [], "source": [ "# Import the spaCy library\n", "import spacy\n", "\n", "# Note that we now load a medium-sized language model!\n", "nlp = spacy.load('en_core_web_md')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's limit processing to article titles and create a placeholder column to the DataFrame named `processed_title`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "talk['processed_title'] = None" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*pandas* warns about performing this command, because `talk` is only a slice or a _view_ into the DataFrame. \n", "\n", "Assigning a new column to **only a part of the DataFrame** would cause problems by breaking the tabular structure.\n", "\n", "We can fix the situation by creating a _deep copy_ of the slice using Python's `.copy()` method." ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [], "source": [ "talk = talk.copy()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's try creating an empty column again." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "talk['processed_title'] = None" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " | article_id | \n", "title | \n", "article_url | \n", "author | \n", "published_date | \n", "ncomments | \n", "ntop_level_comments | \n", "article_text | \n", "comments_ratio | \n", "
---|---|---|---|---|---|---|---|---|---|
2 | \n", "6929035 | \n", "Too many first nations people live in a dream ... | \n", "http://www.theglobeandmail.com/opinion/too-man... | \n", "Jeffrey Simpson | \n", "2013-01-05 EST | \n", "1164.0 | \n", "433.0 | \n", "<p>Large elements of aboriginal Canada live in... | \n", "0.371993 | \n", "
4 | \n", "11672346 | \n", "Disgruntled Arab states look to strip Canada o... | \n", "http://www.theglobeandmail.com/news/world/disg... | \n", "Campbell Clark | \n", "2013-05-02 EDT | \n", "1129.0 | \n", "411.0 | \n", "<p>Growing discontent among Arab nations over ... | \n", "0.364039 | \n", "
5 | \n", "26691065 | \n", "Fifty years in Canada, and now I feel like a s... | \n", "http://www.theglobeandmail.com/opinion/fifty-y... | \n", "SHEEMA KHAN | \n", "2015-10-07 EDT | \n", "1142.0 | \n", "376.0 | \n", "<p>'Too broken to write,' I told my editor, af... | \n", "0.329247 | \n", "
6 | \n", "25731634 | \n", "I'm Canadian - and I should have a right to vote | \n", "http://www.theglobeandmail.com/opinion/im-cana... | \n", "Donald Sutherland | \n", "2015-07-28 EDT | \n", "1021.0 | \n", "348.0 | \n", "<p>My name is Donald Sutherland. My wife's nam... | \n", "0.340842 | \n", "
8 | \n", "13647608 | \n", "A nation of $100,000 firefighters | \n", "http://www.theglobeandmail.com/opinion/a-natio... | \n", "Margaret Wente | \n", "2013-08-08 EDT | \n", "1102.0 | \n", "338.0 | \n", "<p>Everyone loves firefighters. They save live... | \n", "0.306715 | \n", "
Large elements of aboriginal Canada live in... 0.371993 \n", "4
Growing discontent among Arab nations over ... 0.364039 \n", "5
'Too broken to write,' I told my editor, af... 0.329247 \n", "6
My name is Donald Sutherland. My wife's nam... 0.340842 \n", "8
Everyone loves firefighters. They save live... 0.306715 " ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "talk.head(5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To retrieve the title for each article from the column `title`, feed it to the language model under `nlp` for processing and store the output into the column `processed_title`, we need to use the `.apply()` method of a DataFrame.\n", "\n", "As the name suggests, the `.apply()` method applies whatever is provided as input to the method to each row in the column.\n", "\n", "In this case, we pass the language model `nlp` to the `.apply()` method, essentially retrieving the titles stored as string objects in the column `title` and \"applying\" the language model `nlp` to them.\n", "\n", "We assign the output to the DataFrame column named `processed_title`." ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " | article_id | \n", "title | \n", "article_url | \n", "author | \n", "published_date | \n", "ncomments | \n", "ntop_level_comments | \n", "article_text | \n", "comments_ratio | \n", "processed_title | \n", "
---|---|---|---|---|---|---|---|---|---|---|
2 | \n", "6929035 | \n", "Too many first nations people live in a dream ... | \n", "http://www.theglobeandmail.com/opinion/too-man... | \n", "Jeffrey Simpson | \n", "2013-01-05 EST | \n", "1164.0 | \n", "433.0 | \n", "<p>Large elements of aboriginal Canada live in... | \n", "0.371993 | \n", "(Too, many, first, nations, people, live, in, ... | \n", "
4 | \n", "11672346 | \n", "Disgruntled Arab states look to strip Canada o... | \n", "http://www.theglobeandmail.com/news/world/disg... | \n", "Campbell Clark | \n", "2013-05-02 EDT | \n", "1129.0 | \n", "411.0 | \n", "<p>Growing discontent among Arab nations over ... | \n", "0.364039 | \n", "(Disgruntled, Arab, states, look, to, strip, C... | \n", "
5 | \n", "26691065 | \n", "Fifty years in Canada, and now I feel like a s... | \n", "http://www.theglobeandmail.com/opinion/fifty-y... | \n", "SHEEMA KHAN | \n", "2015-10-07 EDT | \n", "1142.0 | \n", "376.0 | \n", "<p>'Too broken to write,' I told my editor, af... | \n", "0.329247 | \n", "(Fifty, years, in, Canada, ,, and, now, I, fee... | \n", "
6 | \n", "25731634 | \n", "I'm Canadian - and I should have a right to vote | \n", "http://www.theglobeandmail.com/opinion/im-cana... | \n", "Donald Sutherland | \n", "2015-07-28 EDT | \n", "1021.0 | \n", "348.0 | \n", "<p>My name is Donald Sutherland. My wife's nam... | \n", "0.340842 | \n", "(I, 'm, Canadian, -, and, I, should, have, a, ... | \n", "
8 | \n", "13647608 | \n", "A nation of $100,000 firefighters | \n", "http://www.theglobeandmail.com/opinion/a-natio... | \n", "Margaret Wente | \n", "2013-08-08 EDT | \n", "1102.0 | \n", "338.0 | \n", "<p>Everyone loves firefighters. They save live... | \n", "0.306715 | \n", "(A, nation, of, $, 100,000, firefighters) | \n", "
... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "
1694 | \n", "30474884 | \n", "A dangerous moment in history: Can the politic... | \n", "http://www.theglobeandmail.com/opinion/can-the... | \n", "Konrad Yakabuski | \n", "2016-06-16 EDT | \n", "239.0 | \n", "50.0 | \n", "<p>As anyone trying to maintain perspective wh... | \n", "0.209205 | \n", "(A, dangerous, moment, in, history, :, Can, th... | \n", "
1735 | \n", "32088785 | \n", "Clinton shines in first debate, and not just i... | \n", "http://www.theglobeandmail.com/opinion/editori... | \n", "GLOBE EDITORIAL | \n", "2016-09-27 EDT | \n", "232.0 | \n", "49.0 | \n", "<p>For those who wondered whether Hillary Clin... | \n", "0.211207 | \n", "(Clinton, shines, in, first, debate, ,, and, n... | \n", "
2213 | \n", "30508530 | \n", "U.S. gun control: Don't look for logic after O... | \n", "http://www.theglobeandmail.com/opinion/us-gun-... | \n", "Konrad Yakabuski | \n", "2016-06-20 EDT | \n", "243.0 | \n", "40.0 | \n", "<p>The script is by now tediously formulaic. A... | \n", "0.164609 | \n", "(U.S., gun, control, :, Do, n't, look, for, lo... | \n", "
2301 | \n", "31605288 | \n", "Let's make sure Ontario's sex-ed curriculum is... | \n", "http://www.theglobeandmail.com/opinion/lets-ma... | \n", "DEBRA SOH | \n", "2016-08-30 EDT | \n", "239.0 | \n", "39.0 | \n", "<p>Debra W. Soh is a sex writer and sexual neu... | \n", "0.163180 | \n", "(Let, 's, make, sure, Ontario, 's, sex, -, ed,... | \n", "
2302 | \n", "24363093 | \n", "Dad rules when sex ed collides with religion | \n", "http://www.theglobeandmail.com/opinion/dad-rul... | \n", "MICHAEL ADAMS | \n", "2015-05-11 EDT | \n", "222.0 | \n", "39.0 | \n", "<p>Michael Adams is founder and president of t... | \n", "0.175676 | \n", "(Dad, rules, when, sex, ed, collides, with, re... | \n", "
519 rows × 10 columns
\n", "Large elements of aboriginal Canada live in... 0.371993 \n", "4
Growing discontent among Arab nations over ... 0.364039 \n", "5
'Too broken to write,' I told my editor, af... 0.329247 \n", "6
My name is Donald Sutherland. My wife's nam... 0.340842 \n", "8
Everyone loves firefighters. They save live... 0.306715 \n", "... ... ... \n", "1694
As anyone trying to maintain perspective wh... 0.209205 \n", "1735
For those who wondered whether Hillary Clin... 0.211207 \n", "2213
The script is by now tediously formulaic. A... 0.164609 \n", "2301
Debra W. Soh is a sex writer and sexual neu... 0.163180 \n", "2302
Michael Adams is founder and president of t... 0.175676 \n", "\n", " processed_title \n", "2 (Too, many, first, nations, people, live, in, ... \n", "4 (Disgruntled, Arab, states, look, to, strip, C... \n", "5 (Fifty, years, in, Canada, ,, and, now, I, fee... \n", "6 (I, 'm, Canadian, -, and, I, should, have, a, ... \n", "8 (A, nation, of, $, 100,000, firefighters) \n", "... ... \n", "1694 (A, dangerous, moment, in, history, :, Can, th... \n", "1735 (Clinton, shines, in, first, debate, ,, and, n... \n", "2213 (U.S., gun, control, :, Do, n't, look, for, lo... \n", "2301 (Let, 's, make, sure, Ontario, 's, sex, -, ed,... \n", "2302 (Dad, rules, when, sex, ed, collides, with, re... \n", "\n", "[519 rows x 10 columns]" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Apply the language model under 'nlp' to the contents of the DataFrame column 'title'\n", "talk['processed_title'] = talk['title'].apply(nlp)\n", "\n", "# Call the variable to check the output\n", "talk" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We now have the processed titles in a separate column named `processed_title`!\n", "\n", "Let's examine the first row in the DataFrame `talk`, whose index is 2." ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Too many first nations people live in a dream palace" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "talk.at[2, 'processed_title']" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "spacy.tokens.doc.Doc" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(talk.at[2, 'processed_title'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As you can see, the cell contains a spaCy _Doc_ object.\n", "\n", "Let's now define our own Python **function** to fetch lemmas for each noun in the title.\n", "\n", "Python functions are _defined_ using the command `def`, which is followed by the name of the function, in this case `get_nouns`. \n", "\n", "The input to the function is given in parentheses that follow the name of the function.\n", "\n", "In this case, we name a variable for the input called `nlp_text`. This is an arbitrary variable, which is needed for referring to whatever is being provided as input to the function. To put it simply, you can think of this variable as referring to any input that will be eventually provided to the function." ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [], "source": [ "# Define a function named 'get_nouns' that takes a single object as input.\n", "# We refer to this input using the variable name 'nlp_text'.\n", "def get_nouns(nlp_text):\n", " \n", " # First we make sure that the input is of correct type\n", " # by using the assert command to check the input type\n", " assert type(nlp_text) == spacy.tokens.doc.Doc\n", " \n", " # Let's set up a placeholder list for our lemmas\n", " lemmas = []\n", " \n", " # We begin then begin looping over the Doc object\n", " for token in nlp_text:\n", " \n", " # If the fine-grained POS tag for the token is a noun (NN)\n", " if token.tag_ == 'NN':\n", " \n", " # Append the token lemma to the list of lemmas\n", " lemmas.append(token.lemma_)\n", " \n", " # When the loop is complete, return the list of lemmas\n", " return lemmas" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now that we have defined our function, we can use the function with the `.apply()` method to collect all nouns to the column `nouns`." ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " | article_id | \n", "title | \n", "article_url | \n", "author | \n", "published_date | \n", "ncomments | \n", "ntop_level_comments | \n", "article_text | \n", "comments_ratio | \n", "processed_title | \n", "nouns | \n", "
---|---|---|---|---|---|---|---|---|---|---|---|
2 | \n", "6929035 | \n", "Too many first nations people live in a dream ... | \n", "http://www.theglobeandmail.com/opinion/too-man... | \n", "Jeffrey Simpson | \n", "2013-01-05 EST | \n", "1164.0 | \n", "433.0 | \n", "<p>Large elements of aboriginal Canada live in... | \n", "0.371993 | \n", "(Too, many, first, nations, people, live, in, ... | \n", "[dream, palace] | \n", "
4 | \n", "11672346 | \n", "Disgruntled Arab states look to strip Canada o... | \n", "http://www.theglobeandmail.com/news/world/disg... | \n", "Campbell Clark | \n", "2013-05-02 EDT | \n", "1129.0 | \n", "411.0 | \n", "<p>Growing discontent among Arab nations over ... | \n", "0.364039 | \n", "(Disgruntled, Arab, states, look, to, strip, C... | \n", "[agency] | \n", "
5 | \n", "26691065 | \n", "Fifty years in Canada, and now I feel like a s... | \n", "http://www.theglobeandmail.com/opinion/fifty-y... | \n", "SHEEMA KHAN | \n", "2015-10-07 EDT | \n", "1142.0 | \n", "376.0 | \n", "<p>'Too broken to write,' I told my editor, af... | \n", "0.329247 | \n", "(Fifty, years, in, Canada, ,, and, now, I, fee... | \n", "[class, citizen] | \n", "
6 | \n", "25731634 | \n", "I'm Canadian - and I should have a right to vote | \n", "http://www.theglobeandmail.com/opinion/im-cana... | \n", "Donald Sutherland | \n", "2015-07-28 EDT | \n", "1021.0 | \n", "348.0 | \n", "<p>My name is Donald Sutherland. My wife's nam... | \n", "0.340842 | \n", "(I, 'm, Canadian, -, and, I, should, have, a, ... | \n", "[right] | \n", "
8 | \n", "13647608 | \n", "A nation of $100,000 firefighters | \n", "http://www.theglobeandmail.com/opinion/a-natio... | \n", "Margaret Wente | \n", "2013-08-08 EDT | \n", "1102.0 | \n", "338.0 | \n", "<p>Everyone loves firefighters. They save live... | \n", "0.306715 | \n", "(A, nation, of, $, 100,000, firefighters) | \n", "[nation] | \n", "
... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "
1694 | \n", "30474884 | \n", "A dangerous moment in history: Can the politic... | \n", "http://www.theglobeandmail.com/opinion/can-the... | \n", "Konrad Yakabuski | \n", "2016-06-16 EDT | \n", "239.0 | \n", "50.0 | \n", "<p>As anyone trying to maintain perspective wh... | \n", "0.209205 | \n", "(A, dangerous, moment, in, history, :, Can, th... | \n", "[moment, history, centre, hold] | \n", "
1735 | \n", "32088785 | \n", "Clinton shines in first debate, and not just i... | \n", "http://www.theglobeandmail.com/opinion/editori... | \n", "GLOBE EDITORIAL | \n", "2016-09-27 EDT | \n", "232.0 | \n", "49.0 | \n", "<p>For those who wondered whether Hillary Clin... | \n", "0.211207 | \n", "(Clinton, shines, in, first, debate, ,, and, n... | \n", "[debate, comparison] | \n", "
2213 | \n", "30508530 | \n", "U.S. gun control: Don't look for logic after O... | \n", "http://www.theglobeandmail.com/opinion/us-gun-... | \n", "Konrad Yakabuski | \n", "2016-06-20 EDT | \n", "243.0 | \n", "40.0 | \n", "<p>The script is by now tediously formulaic. A... | \n", "0.164609 | \n", "(U.S., gun, control, :, Do, n't, look, for, lo... | \n", "[gun, control, logic] | \n", "
2301 | \n", "31605288 | \n", "Let's make sure Ontario's sex-ed curriculum is... | \n", "http://www.theglobeandmail.com/opinion/lets-ma... | \n", "DEBRA SOH | \n", "2016-08-30 EDT | \n", "239.0 | \n", "39.0 | \n", "<p>Debra W. Soh is a sex writer and sexual neu... | \n", "0.163180 | \n", "(Let, 's, make, sure, Ontario, 's, sex, -, ed,... | \n", "[sex, ed, curriculum] | \n", "
2302 | \n", "24363093 | \n", "Dad rules when sex ed collides with religion | \n", "http://www.theglobeandmail.com/opinion/dad-rul... | \n", "MICHAEL ADAMS | \n", "2015-05-11 EDT | \n", "222.0 | \n", "39.0 | \n", "<p>Michael Adams is founder and president of t... | \n", "0.175676 | \n", "(Dad, rules, when, sex, ed, collides, with, re... | \n", "[sex, ed, religion] | \n", "
519 rows × 11 columns
\n", "Large elements of aboriginal Canada live in... 0.371993 \n", "4
Growing discontent among Arab nations over ... 0.364039 \n", "5
'Too broken to write,' I told my editor, af... 0.329247 \n", "6
My name is Donald Sutherland. My wife's nam... 0.340842 \n", "8
Everyone loves firefighters. They save live... 0.306715 \n", "... ... ... \n", "1694
As anyone trying to maintain perspective wh... 0.209205 \n", "1735
For those who wondered whether Hillary Clin... 0.211207 \n", "2213
The script is by now tediously formulaic. A... 0.164609 \n", "2301
Debra W. Soh is a sex writer and sexual neu... 0.163180 \n", "2302
Michael Adams is founder and president of t... 0.175676 \n",
"\n",
" processed_title \\\n",
"2 (Too, many, first, nations, people, live, in, ... \n",
"4 (Disgruntled, Arab, states, look, to, strip, C... \n",
"5 (Fifty, years, in, Canada, ,, and, now, I, fee... \n",
"6 (I, 'm, Canadian, -, and, I, should, have, a, ... \n",
"8 (A, nation, of, $, 100,000, firefighters) \n",
"... ... \n",
"1694 (A, dangerous, moment, in, history, :, Can, th... \n",
"1735 (Clinton, shines, in, first, debate, ,, and, n... \n",
"2213 (U.S., gun, control, :, Do, n't, look, for, lo... \n",
"2301 (Let, 's, make, sure, Ontario, 's, sex, -, ed,... \n",
"2302 (Dad, rules, when, sex, ed, collides, with, re... \n",
"\n",
" nouns \n",
"2 [dream, palace] \n",
"4 [agency] \n",
"5 [class, citizen] \n",
"6 [right] \n",
"8 [nation] \n",
"... ... \n",
"1694 [moment, history, centre, hold] \n",
"1735 [debate, comparison] \n",
"2213 [gun, control, logic] \n",
"2301 [sex, ed, curriculum] \n",
"2302 [sex, ed, religion] \n",
"\n",
"[519 rows x 11 columns]"
]
},
"execution_count": 49,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Apply the 'get_nouns' function to the column 'processed_title'\n",
"talk['nouns'] = talk['processed_title'].apply(get_nouns)\n",
"\n",
"# Call the variable to examine the output\n",
"talk"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As you can see, an empty DataFrame column is actually not required for adding new data, because *pandas* creates a new column automatically through assignment, as exemplified by `talk['nouns']`."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can also easily extract information from DataFrames into Python's native data structures. \n",
"\n",
"The `tolist()` method, for instance, can be used to extract the contents of a *pandas* Series into a list."
]
},
{
"cell_type": "code",
"execution_count": 75,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[['dream', 'palace'],\n",
" ['agency'],\n",
" ['class', 'citizen'],\n",
" ['right'],\n",
" ['nation'],\n",
" [],\n",
" ['reform'],\n",
" ['leader', 'parade'],\n",
" ['pm'],\n",
" ['government', 'monopoly']]"
]
},
"execution_count": 75,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Cast pandas Series to a list\n",
"noun_list = talk['nouns'].tolist()\n",
"\n",
"# Call the variable to check the output\n",
"noun_list[:10]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"What we have now under `noun_list` is a list of lists, because each row in the `nouns` column contains a list. \n",
"\n",
"Let's loop over the list and collect the items into a single list named `final_list` using the `extend()` method of a Python list."
]
},
{
"cell_type": "code",
"execution_count": 70,
"metadata": {},
"outputs": [],
"source": [
"# Set up the placeholder list\n",
"final_list = []\n",
"\n",
"# Loop over each list in the list of lists\n",
"for nlist in noun_list:\n",
" \n",
" # Extend the final list with the current list\n",
" final_list.extend(nlist)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's briefly examine the first ten items in final list and then count the number of items in the list."
]
},
{
"cell_type": "code",
"execution_count": 71,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"['dream',\n",
" 'palace',\n",
" 'agency',\n",
" 'class',\n",
" 'citizen',\n",
" 'right',\n",
" 'nation',\n",
" 'reform',\n",
" 'leader',\n",
" 'parade']"
]
},
"execution_count": 71,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"final_list[:10]"
]
},
{
"cell_type": "code",
"execution_count": 67,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"887"
]
},
"execution_count": 67,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"len(final_list)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To plot the 10 most frequent nouns, we can cast the `final_list` into a *pandas* Series, count the occurrences of each lemma using `value_counts()` and plot the result using the `plot()` method."
]
},
{
"cell_type": "code",
"execution_count": 69,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"\n",
" \n",
"
\n",
"\n",
" \n",
" \n",
" \n",
" \n",
" filename \n",
" text \n",
" \n",
" \n",
" 0 \n",
" WP_1990-08-10-25A.txt \n",
" *We Don’t Stand for Bullies': Diverse Voices ... \n",
" \n",
" \n",
" 1 \n",
" NYT_1991-01-16-A15.txt \n",
" U.S. TAKING STEPS TO CURB TERRORISM: F.B.I. I... \n",
" \n",
" \n",
" \n",
"2 \n",
" WP_1991-01-17-A1B.txt \n",
" U.S., Allies Launch Massive Air War Against T... \n",
" \n",
" \n",
"
\n",
"\n",
" \n",
" \n",
" \n",
" \n",
" filename \n",
" text \n",
" \n",
" \n",
" 0 \n",
" True \n",
" True \n",
" \n",
" \n",
" 1 \n",
" True \n",
" True \n",
" \n",
" \n",
" \n",
"2 \n",
" True \n",
" True \n",
"