{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Analyzing Tabular Omics Data using Pandas DataFrames\n", "\n", "\n", "\n", "## Working With A Feature Table of Microbial Counts\n", "\n", "\n", "In this jupyter notebook we will do some basic graphing of a feature table of microbes by samples. We'll work with tabular data representing one of the microbiome change scenarios from the previous section. \n", "\n", "Here is the scenario in cartoon form:\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Representing Tabular Data in Text Form with `.csv` or `.tsv` files \n", "\n", "First, we need some data to work with. The data in a table like the one above - tabular data - can be represented in text files by using a letter or other character to mark where each column ends. This special character that marks the boundaries between columns is called a 'delimiter'. It's critical that whatever delimiter is chosen doesn't show up in the cells of the table itself, or else programs that read the file may become confused about where each entry in the table begins and ends. Therefore, most delimiters are chosen to be single characters that don't show up in the raw data. Common delimiters for tabular data saved as text files are either commas (`\",\"`) or tabs (`\"\\t\"` in python). Files that use a comma delimiter are often called `.csv` or comma-separated values files. Those that use tabs are called `.tsv` or tab-separated values files. Tab-separated values files commonly use `.tsv` or `.txt` file extensions. \n", "\n", "Personally, I usually prefer to use tab-separated values files where possible, because it's convenient if commas can still appear in tables (sometimes in 'Notes' sections) without messing up your ability to read the table into python. In contrast, I rarely need to represent tabs in my raw data. However, both `.csv` and `.tsv` files are used very commonly in bioinformatics." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Download the raw data\n", "\n", "A sample tab-separated values data file representing the table up above is available from GitHub. You can either download it by hand and save it into the same folder where your code is running, or you can use python code to do this automatically. If you are running the script in Google Colab, you should use the automatic download method." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Option 1: Download the data by hand**.\n", "Click on the link to the GitHub page for the raw data [here](https://github.com/zaneveld/full_spectrum_bioinformatics/blob/master/content/07_tabular_omics_data/resources/scenario1_otus_pandas.txt). Annoyingly, there isn't an obvious 'Download' button for data files stored on GitHub. However, you can still download the data. To do this, right-click (Windows) or two-finger click (MacOSX) on the 'Raw' button on the right side of the menu of the GitHub page, then pick 'Save Link as...'. Finally, when the save window pops up, carefully select the folder where you want to save the data. Typically, this will be the same as the directory from which you are running your Jupyter notebook." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Option 2: Download the data directly using the `urlretrieve` function in python**." ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "('scenario_1_otus_pandas.tsv', )" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#Import the urlretrieve function\n", "from urllib.request import urlretrieve\n", "\n", "#Save the looooong web address (url) of our data in a python string \n", "genome_url = 'https://raw.githubusercontent.com/zaneveld/full_spectrum_bioinformatics/master/content/07_tabular_omics_data/resources/scenario1_otus_pandas.txt'\n", "\n", "#Set the name of the file where we want to save the data\n", "#Note we can save the file under whatever name we want (e.g. I changed the extension from .txt to .tsv)\n", "genome_file_name = 'scenario_1_otus_pandas.tsv'\n", "\n", "#Download the data \n", "urlretrieve(genome_url, genome_file_name)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Checking that the raw data is present in our current directory\n", "\n", "As a first step, let's check that we have 'scenario_1_otus_pandas.tsv' in our current working directory. The `listdir` function in the builtin `os` module returns a list of all contents of a specified directory on your computer.\n", "\n", "It can be useful to run it prior to trying to open files if you need to remember filenames. Let's import the `listdir` function and quickly check that our data is there..." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Directory contents: ['scenario_1_otus_pandas.tsv', 'analyzing_tabular_omics_data_in_pandas.ipynb', 'resources', 'scenario_1_otus_pandas.txt', 'simulating_microbiome_sampling_depth.ipynb', 'tabular_omics_data.ipynb', '.ipynb_checkpoints']\n" ] } ], "source": [ "from os import listdir\n", "print(\"Directory contents:\",listdir())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Troubleshooting Missing Files: using `getcwd` to figure out where we are and move data there by hand\n", "\n", "In this case, the scenario 1 data file seems to be present. If it wasn't we could always download it by hand (see above) and then move it to the folder where we are doing our analysis by hand. If we couldn't remember which folder we were running our Jupyter notebook from, we could always double check that with getcwd function from the `os` module, as shown below:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "We are currently working in folder: /Users/zaneveld/Dropbox/Zaneveld_Lab_Organization/Projects/Full_Spectrum_Bioinformatics/full_spectrum_bioinformatics/content/07_tabular_omics_data\n" ] } ], "source": [ "from os import getcwd\n", "\n", "print(\"We are currently working in folder:\",getcwd())\n", "\n", "#Next we would copy our data file and move it to the folder represented by the path down below:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Loading our data file into a `DataFrame` in python " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Great. Now that we've seen that the data is available, let's load it into python. The [pandas](https://pandas.pydata.org/pandas-docs/stable/getting_started/10min.html#min) module in python is an extremely popular and widely used tool for representing tabular data in special data structures known as `DataFrames`. These `DataFrames` are based on a similar data structure in the R programming language. Basically, you can think of them as tables, with the ability to have labelled rows and columns. You can do things like look up particular rows or columns, find all the table entries that match some criteria (e.g. everything >0), or do math operations to columns of the table.\n", "\n", "First, we need to load up our data. The `read_csv` function from `pandas` that will let us load our sample data into a `DataFrame` object. Despite the name, the `read_csv` function can read both comma-separated values files and tab-separated values files, you just need to use it's `sep` (short for separator) parameter to specify the delimiter used in your file if it isn't a comma.\n", "\n", "Let's import the `read_csv` function, and use it to load our data, setting the `sep` parameter to \"\\t\" (tab) since our file is a tab-separated values file." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "from pandas import read_csv\n", "\n", "#Load the text version of the table (a csv file) into python using pandas\n", "feature_table = read_csv('scenario_1_otus_pandas.tsv',sep=\"\\t\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Once we've seen that the table loaded, let's work on figuring out how pandas is representing it inside python. We'll use the type() function to work out what type of object our feature table is:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "pandas.core.frame.DataFrame" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(feature_table)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It looks like our table of data has been loaded as a pandas `DataFrame`. `DataFrame` objects serve as a convenient and very powerful way to represent tabular data. They represent those data as a table with row and column labels. Subsets of the data along a row or column can be pulled out as pandas Series objects.\n", "\n", "To examine the feature table in a Jupyter notebook, we can simply type the name of the variable that holds it on it's own line:\n" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
OTU_IDpatient1patient2patient3patient4patient5patient6patient7patient8patient9patient10patient11patient12
0OTU1342204440322
1OTU2413413334114
2OTU3142142221441
3OTU4230120123021
4OTU5000000142234
\n", "
" ], "text/plain": [ " OTU_ID patient1 patient2 patient3 patient4 patient5 patient6 \\\n", "0 OTU1 3 4 2 2 0 4 \n", "1 OTU2 4 1 3 4 1 3 \n", "2 OTU3 1 4 2 1 4 2 \n", "3 OTU4 2 3 0 1 2 0 \n", "4 OTU5 0 0 0 0 0 0 \n", "\n", " patient7 patient8 patient9 patient10 patient11 patient12 \n", "0 4 4 0 3 2 2 \n", "1 3 3 4 1 1 4 \n", "2 2 2 1 4 4 1 \n", "3 1 2 3 0 2 1 \n", "4 1 4 2 2 3 4 " ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "feature_table" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Setting the row labels\n", "\n", "An important feature of pandas DataFrames is their index column. This serves as a set of unique row labels for each row in your data. Because we didn't specify an index column when we loaded our data we have to set it manually. We can do so with the dataframe's set_index method." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "#Use OTU ID column to label each row\n", "feature_table = feature_table.set_index('OTU_ID')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we view the dataframe again, we should notice that the left hand column of numbers has dissapeared, and our rows are now correctly labelled by microbe" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Working with data in a pandas DataFrame\n", "\n", "Now that are data is loaded into a pandas `DataFrame`, let's explore how we can work with our table of microbiome data. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Accessing column data\n", "\n", "We might want to access the rows or columns of our pandas data directly so that we can do calculations. A nice tutorial on this can be found here: https://www.shanelynn.ie/select-pandas-dataframe-rows-and-columns-using-iloc-loc-and-ix/.\n", "\n", "In brief, we can select a column by indexing into the pandas DataFrame object using a column name. I currently have the patients as columns, so we could access them with `feature_table[\"patient1\"]`" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "OTU_ID\n", "OTU1 3\n", "OTU2 4\n", "OTU3 1\n", "OTU4 2\n", "OTU5 0\n", "Name: patient1, dtype: int64\n" ] } ], "source": [ "#Access a column \n", "print(feature_table[\"patient1\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "However, this way of selecting columns in pandas is a bit special-purpose - it doesn't always extend in the simplest way to rows for example." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Try it yourself**: try accessing a column that doesn't exist. Try something ridiculous like `print(feature_table[\"zeppelin_sales\"])`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### A consistent way to access row or column data in pandas\n", "\n", "An alternative way to index into a pandas DataFrame is by using the .loc indexer (accessed by the name of your dataframe and then .loc)\n", "\n", "Note that this is not called like a function (so not 'df.loc('whatever')'), but more a way of indexing (closer to how you would call it if loc were a dict that was a property of the dataframe).\n", "\n", "When using .loc, we specify what rows we want, then what columns we want. We can use the colon character to indicate 'all'. In this way we can do row and column selection using exactly the same syntax, which is nice for those of us who don't like to remember too many things.\n", "\n", "(More info on this here: https://brohrer.github.io/dataframe_indexing.html)\n", "\n", "#### Select a single column using `.loc`\n", "\n", "Here's how we can use the DataFrame loc property to select a column by name:" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Select all of the patient1 column:\n", "OTU_ID\n", "OTU1 3\n", "OTU2 4\n", "OTU3 1\n", "OTU4 2\n", "OTU5 0\n", "Name: patient1, dtype: int64\n" ] } ], "source": [ "#Recall that : means all, and we specify rows,columns when using .loc\n", "print(\"Select all of the patient1 column:\")\n", "selected_column = feature_table.loc[:,'patient1']\n", "print(selected_column)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Cool! So we see that we now get the count of all microbes in patient1's sample. However, this data type looks kinda funky. That's because it is a pandas Series object. It therefore doesn't print in the same way as either a pandas DataFrame or a python list. We'll talk more about that in a minute. For now, let's continue to explore how to select data using .loc.\n", "\n", "#### Select a row from a pandas DataFrame with `.loc`\n" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Select the OTU1 row:\n", "patient1 3\n", "patient2 4\n", "patient3 2\n", "patient4 2\n", "patient5 0\n", "patient6 4\n", "patient7 4\n", "patient8 4\n", "patient9 0\n", "patient10 3\n", "patient11 2\n", "patient12 2\n", "Name: OTU1, dtype: int64\n" ] } ], "source": [ "print(\"\\nSelect the OTU1 row:\")\n", "selected_row = feature_table.loc['OTU1',:]\n", "print(selected_row)\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Select a single entry in our table using `.loc` by specifying the row and column names\n", "\n", "We can combine these types of indices to access the value of a single cell" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Select one cell by specifying row and column:\n", "3\n" ] } ], "source": [ "print(\"\\nSelect one cell by specifying row and column:\")\n", "selected_row_and_column = feature_table.loc['OTU1','patient1']\n", "print(selected_row_and_column)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that we can also use variables to hold our strings for the names of rows or columns to be select. This can be useful if dynamically determining which data to grab in more complex code. Here's a simple example:" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Select one cell by specifying row and column:\n", "3\n" ] } ], "source": [ "print(\"\\nSelect one cell by specifying row and column:\")\n", "row_name = 'OTU1'\n", "column_name = 'patient1'\n", "selected_row_and_column = feature_table.loc[row_name,column_name]\n", "print(selected_row_and_column)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Testing what we get back when we select a pandas column or row.\n", "\n", "We said up above that these pandas Series objects we got back from selecting row or columns of a dataframe don't look quite like either lists or DataFrames. In this case we know the result is a Series, but in cases like this where we don't already know the type of an object we can use the builtin type() function to check the type of any object in python. " ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "feature_table['patient1'] is an object of type: \n" ] } ], "source": [ "selected_column = feature_table.loc[:,'patient1']\n", "selected_column_type = type(selected_column)\n", "\n", "#WHAT IS THIS? Print the answer to screen\n", "print(\"\\nfeature_table['patient1'] is an object of type:\", selected_column_type)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Great, so we've now proven to ourselves that this is a pandas Series object. We can now do some Googling to find out more about this data type.\n", "\n", "For example, this Beyond Data Science blog post has more in-depth information about pandas series objects: https://towardsdatascience.com/pandas-series-a-lightweight-intro-b7963a0d62a2. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Do math to a Series object \n", "\n", "In general, mathematical operations done to a `Series` object are applied to all the individual elements of that `Series`. So if you add 1 to a particular `Series`, pandas will add 1 to each number in that series Additionally, many built-in functions that apply to lists, such as `sum`, also work on pandas `Series` objects.\n", "\n", "Here's an example: a common thing we need to do to microbiome data is to convert it to log scale. This is helpful for plotting microbes with very different abundances (e.g. 3 and 3,000). If all our data were positive numbers, we could do this by importing the `log` function (the one in the numpy package works best with Series objects), and then running it on our data series. There's a problem though: some of our numbers are zero, and the log of zero is undefined. One common strategy is to add a *pseudocount* of 1 to all samples. This is an approximation, but it is commonly used to allow for calculation of logs in large datasets.\n", "\n", "Let's try adding 1 to all numbers, then taking the log of one column of our microbiome data.\n", "\n" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Log(patient1 data): OTU_ID\n", "OTU1 1.386294\n", "OTU2 1.609438\n", "OTU3 0.693147\n", "OTU4 1.098612\n", "OTU5 0.000000\n", "Name: patient1, dtype: float64\n" ] } ], "source": [ "#numpy is a common package for working with arrays\n", "#it has lots of math functions that also work well\n", "#with pandas series objects\n", "from numpy import log\n", "\n", "#Select the patient1 column of our DataFrame\n", "OTU1_data = feature_table.loc[:,\"patient1\"]\n", "\n", "log_patient1_data = log(patient1_data +1)\n", "\n", "print(\"Log(patient1 data):\", log_patient1_data)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Getting a list out of a pandas Series object\n", "\n", "Let's say we don't want to work with the data as a series, but instead to convert it to a list. We can do that using the builtin list() function.\n", " " ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[3, 4, 1, 2, 0]\n" ] } ], "source": [ "patient1_data = list(feature_table.loc[:,\"patient1\"])\n", "print(patient1_data)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Getting a numpy array object out of a pandas Series object\n", "\n", "an alternative way of getting numeric data out of a pandas Series object is by calling its .values property, which returns a numpy array of the data.\n", "\n", "NOTE: values is a *property* (data stored in the object) not a *method* (function associated with the object. The main reason this matters is because if you call .values() with parentheses by accident, you will get an error" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Data as a numpy array: [3 4 1 2 0]\n" ] } ], "source": [ "patient1_data_as_array = feature_table.loc[:,\"patient1\"].values\n", "print(\"Data as a numpy array:\",patient1_data_as_array)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Filter rows of a pandas dataframe by column values\n", "\n", "Let's say we want just the patients *without* OTU5 or *without* OTU4. In that case we can use a condition within our .loc selection. A vertical bar | should be read as 'or'. " ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
patient1patient2patient3patient4patient5patient6patient10
OTU_ID
OTU13422043
OTU24134131
OTU31421424
OTU42301200
OTU50000002
\n", "
" ], "text/plain": [ " patient1 patient2 patient3 patient4 patient5 patient6 patient10\n", "OTU_ID \n", "OTU1 3 4 2 2 0 4 3\n", "OTU2 4 1 3 4 1 3 1\n", "OTU3 1 4 2 1 4 2 4\n", "OTU4 2 3 0 1 2 0 0\n", "OTU5 0 0 0 0 0 0 2" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "columns_to_grab = (feature_table.loc['OTU5',:] == 0) | (feature_table.loc['OTU4',:] == 0)\n", "\n", "feature_table.loc[:,columns_to_grab]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that the above feature table now has only columns that have a 0 count in their entry in the OTU5 or OTU4 row. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Rendering DataFrames as HTML\n", "\n", "In a Jupyter Notebook, DataFrames can be rendered simpy by typing the variable name holding them on it's own line. However, if working outside of Jupyter notebooks it can be useful to know how to generate HTML versions of these tables where needed. This is shown below:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
patient1patient2patient3patient4patient5patient6patient7patient8patient9patient10patient11patient12
OTU_ID
OTU1342204440322
OTU2413413334114
OTU3142142221441
OTU4230120123021
OTU5000000142234
" ], "text/plain": [ "" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#Converting it to HTML to show it\n", "feature_table_to_show = feature_table.to_html()\n", "\n", "#Show the HTML\n", "from IPython.display import HTML\n", "feature_table_as_html = HTML(feature_table_to_show)\n", "feature_table_as_html" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Styling Pandas dataframes \n", "\n", "Pandas dataframes can be [styled](https://pandas.pydata.org/pandas-docs/stable/user_guide/style.html) in several ways to highlight values of interest. We can use this styling to provide a quick heatmap-like coloring to a pandas table:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
patient1 patient2 patient3 patient4 patient5 patient6 patient7 patient8 patient9 patient10 patient11 patient12
OTU_ID
OTU1342204440322
OTU2413413334114
OTU3142142221441
OTU4230120123021
OTU5000000142234
" ], "text/plain": [ "" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#Set the feature table display style\n", "#to use a background gradient based on values.\n", "feature_table_visualization = feature_table.style.background_gradient(cmap='Blues')\n", "feature_table_visualization" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Note**: this styling won't appear on GitHub, so you may need to try it for yourself to see the coloring." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Graphing pandas DataFrames using heatmaps\n", "\n", "One of the advantages of pandas DataFrames is that they integrate well with many other commonly used visualization and statistics packages in python. If we want a true heatmap that, for example, clusters rows and columns by similarity we will need to step outside of the pandas module alone and combine it with the [Seaborn](https://seaborn.pydata.org/) graphing package. \n", "\n", "[Seaborn](https://seaborn.pydata.org/) is a graphing package built on top of [matplotlib](https://matplotlib.org/1.3.1/index.html). It integrates smoothly with pandas, and the two are commonly used together. \n", "\n", "The clustermap function in seaborn is a convenient way to make a heatmap of our data, clustered according to the similarity of rows and columns. In this chart the rows will be the different microbes, the columns will be the patients, and the color of each cell will represent the count of microbes in each patient. The order of the rows and columns will reflect the similarity of their counts." ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "%matplotlib inline\n", "from seaborn import clustermap\n", "clustermap(feature_table,cmap=\"Blues\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we don't want to cluster the data, and just want a basic heatmap, we can set the row_cluster and col_cluster parameters to False." ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "clustermap(feature_table,row_cluster=False,col_cluster=False,cmap=\"Blues\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we wanted to swap the rows and columns, we could use the pandas DataFrame method .transpose() to swap the rows and columns of the DataFrame, and then rerun the clustermap on the transposed data. We can also separately control clustering of rows and columns with the row_cluster and col_cluster parameters. Finally, we can change the color mapping or 'cmap' using the cmap paramter. " ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "feature_table_transposed = feature_table.transpose()\n", "clustermap(feature_table_transposed, row_cluster=False,col_cluster=True,cmap='Blues')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Calculating Microbiome Richness using Pandas DataFrames \n", "\n", "Next we will calculate the alpha diversity in this dataset. This is equivalent to calculating how many species are represented in each with counts > 0. (We'll leave aside for the moment important concerns about normalization)" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['patient1' 'patient2' 'patient3' 'patient4' 'patient5' 'patient6'\n", " 'patient7' 'patient8' 'patient9' 'patient10' 'patient11' 'patient12']\n" ] } ], "source": [ "#First look up the names of all the samples (so all the column names)\n", "print(feature_table.columns.values)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### A solution for calculating alpha diversity using for loops\n", "\n", "One way we might calculate alpha diversity is using for loops. The approach is:\n", "\n", "- grab each column \n", "- iterate over the rows\n", "- if a row is non-zero add 1 to the alpha diversity of that column\n", "- print (or yield) the alpha diversity for the current column before moving on to the next one.\n", "\n", "You can think of this as a'traditional' approach that doesn't rely on much of pandas special functionality other than a single step where we grab our column of interest." ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "patient1: 4\n", "patient2: 4\n", "patient3: 3\n", "patient4: 4\n", "patient5: 3\n", "patient6: 3\n", "patient7: 5\n", "patient8: 5\n", "patient9: 4\n", "patient10: 4\n", "patient11: 5\n", "patient12: 5\n" ] } ], "source": [ "adiv_by_patient = {}\n", "for patient in feature_table.columns.values:\n", " adiv = 0 \n", " patient_otus = feature_table.loc[:,patient]\n", " for otu_count in patient_otus :\n", " if otu_count > 0:\n", " adiv += 1 \n", " print(f\"{patient}: {adiv}\")\n", " adiv_by_patient[patient] = adiv\n", " \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A related solution uses conditional indexing to find all cells that have a value above 0 and set it to 1. This effectively converts the table to a presence/absence table. One can then use the built in sum function to add up the columns:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "patient1 4\n", "patient2 4\n", "patient3 3\n", "patient4 4\n", "patient5 3\n", "patient6 3\n", "patient7 5\n", "patient8 5\n", "patient9 4\n", "patient10 4\n", "patient11 5\n", "patient12 5\n", "dtype: int64" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#Convert all values above 0 to 1\n", "feature_table[feature_table >0] = 1\n", "#Sum along the columns\n", "feature_table.sum()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that this is not at all the only way to calculate this quantity. For example, if you are familiar with the numpy python library, a similar effect can be achiveved by extracting a numpy array from the feature table, using the numpy where function to set all non-zero cells to 1 and then using the numpy sum function to sum down the colums." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Conclusion\n", "\n", "Although tabular data can have many origins, the steps for analyzing it are often similar. Pandas DataFrames present a powerful and very widely used tool for analyzing tabular data in python." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exercises\n", "\n", "The exercises for this chapter will \n", "1. **Normalizing a table**. Write a function that *normalizes* a table of species counts expressed as a pandas DataFrame. To normalize the table, calculate the sum of each column (assuming the columns are the samples), and divide each entry by its column sum. For example, patient6 has values 4,3, and 2 for a total of 9 counts. Expressed as proportions these would be 4/9, 3/9, and 2/9 or ~0.444, ~0.333, and ~0.222. Hint: you will need to \n", "\n", "2. **Calculating Shannon's Diversity Index**. Shannon's Diversity Index (H) is a measure of alpha diversity in ecological communities that incorporates elements of both richness and evenness (see e.g. this [post](http://www.tiem.utk.edu/~gross/bioed/bealsmodules/shannonDI.html)). Mathematically it is straightforward to calculate: iterate over all the species in a community. One by one, multiply each species' proportion in the community by the natural log of that proportion (p * ln(p)). Sum up the result and multiply it by -1. Or if you prefer here is the same statement put into mathematical notation: \\begin{equation*}H = -\\sum_{i=1}^n p_i*ln(p_i) \\end{equation*} Write a function that calculates Shannon's Diversity Index on microbial community data expressed as a table. Check that your calculation is working correctly by comparing against a hand-calculated result. For example, patient6 has values 4,3, and 2 for a total of 9 counts. Expressed as proportions these would be 4/9, 3/9, and 2/9. So the Shannon diversity would be -1 * ((4/9)*ln(4/9) + (3/9)*ln(3/9) + (2/9)*ln(2/9)) or ~1.06.\n", "\n", "3. **Short answer:** Do you think incorporating elements of both richness and evenness in a single measure is an advantage, or would you prefer this information in separate measures? What might be a situation where one approach is preferred over the other?\n", "\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Project Ideas\n", "\n", "**Study the alpha diversity of a group over time using fossil data and pandas**. The Paleobiology Database ([paleobiodb.org](https://paleobiodb.org/#/)) let's you visualize and filter fossil data for different groups of animals over time. Filtering and then using the chart icon on the left let's you visualize alpha diversity over time for a given group. Download the raw data for your taxon of interest as a .csv file. Opening it in Excel you will notice the first ~15 rows have header info that needs to be trimmed off for pandas to read the file. After that there are many columns of data describing each fossil. Pay particular attention to the max_ma and min_ma columns: these represent the maximum and minimum number of millions of years ago that each fossil was found. Use table filtering to gather data according to some category of interest: the different groups within your taxon, fossils found on different continents, etc, and compare alpha diversity between them. Extend your method to use rarefaction (random subsampling) to normalize the number of counts between categories so that your total is not artifactually influenced by sampling depth. You can also try plotting the diversity of your different categories over time to try to understand major events (migration, meteor impacts, etc) that might have caused extinctions within your group. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## [Reading Responses & Feedback](https://docs.google.com/forms/d/e/1FAIpQLSeUQPI_JbyKcX1juAFLt5z1CLzC2vTqaCYySUAYCNElNwZqqQ/viewform?usp=pp_url&entry.2118603224=Working+with+Tabular+'Omic+data+in+Python+using+Pandas)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Further Reading\n", "\n", "[1] DataQuest intro to Pandas for Data Analysis using IGN video game reviews [link](https://www.dataquest.io/blog/pandas-python-tutorial/)\n", "\n", "[2] The Pandas API reference for DataFrames and Data Series [link](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.sum.html). This contains lists of useful methods and their documentation.\n", "\n", "\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.8" } }, "nbformat": 4, "nbformat_minor": 2 }