https://kimfetti.github.io/Kimberly Fessel's Blog2022-04-03T21:54:49+00:00Kimberly Fessel is Lead Data Scientist at Metis. Her enthusiasm for data storytelling often leads her toward better math, better visuals, and better science!Kimberly FesselJekyllhttps://kimfetti.github.io/mathematics/data/accuracy-precision-recall/Accuracy, Precision, and Recall — Never Forget Again!2022-04-03T00:00:00+00:00KFessel<em>Designing an effective classification model requires an upfront selection of an appropriate classification metric. This posts walks you through an example of three possible metrics (accuracy, precision, and recall) while teaching you how to easily remember the definition of each one.</em><center>
<iframe width="818" height="500" src="//www.youtube.com/embed/qWfzIYCvBqo" frameborder="0" allowfullscreen=""></iframe>
</center>
<hr />
<p>To design an effective supervised machine learning model, data scientists must first select appropriate metrics to judge their model’s success. But choosing a useful metric often proves more challenging than anticipated, especially for classification models that have a slew of different metric options.</p>
<p>Accuracy remains the most popular classification metric because it’s easy to compute and easy to understand. Accuracy comes with some serious drawbacks, however, particularly for imbalanced classification problems where one class dominates the accuracy calculation.</p>
<p>In this post, let’s review accuracy but also define two other classification metrics: precision and recall. I’ll share an easy way to remember precision and recall along with an explanation of the precision-recall tradeoff, which can help you build a robust classification model.</p>
<h2 id="model-and-data-setup">Model and Data Setup</h2>
<p>To make this study of classification metrics more relatable, consider building a model to classify apples and oranges on a flat surface such as the table shown in the image below.</p>
<center>
<img src="https://kimfetti.github.io/images/OA_training_data.jpg" alt="Apples and oranges arranged on a table with most of the apples on the right side" width="700" />
</center>
<p><br /></p>
<p>Most of the oranges appear on the left side of the table, while the apples mostly show up on the right. We could, therefore, create a classification model that divides the table down its middle. Everything on the left side of the table will be considered an orange by the model, while everything on the right side will be considered an apple.</p>
<center>
<img src="https://kimfetti.github.io/images/OA_precision_recall_header.png" alt="Left side identified as the orange side and right side as the apple side of the model" width="700" />
</center>
<h2 id="what-is-accuracy">What is accuracy?</h2>
<p>Once we’ve built a classification model, how can we determine if it’s doing a good job? Accuracy provides one way to judge a classification model. To calculate accuracy just count up all of the correctly classified observations and divide by the total number of observations. This classification model correctly classified 4 oranges along with 3 apples for a total of 7 correct observations, but there are 10 fruits overall. This model’s accuracy is 7 over 10, or 70%.</p>
<center>
<img src="https://kimfetti.github.io/images/OA_accuracy.png" alt="Accuracy calculated from example apple-orange model as 70%" width="700" />
</center>
<p><br /></p>
<p>While accuracy proves to be one of the most popular classification metrics because of its simplicity, it has a few major flaws. Imagine a situation where we have an imbalanced dataset; that is, what if we have 990 oranges and only 10 apples? One classification model that achieves a very high accuracy predicts that all observations are oranges. The accuracy would be 990 out of 1000, or 99%, but this model completely misses all of the apple observations.</p>
<p>Furthermore, accuracy treats all observations equally. Sometimes certain kinds of errors should be penalized more heavily than others; that is, certain types of errors may be more costly or pose more risk than others. Take predicting fraud for example. Many customers would likely prefer that their bank call them to check up on a questionable charge that is actually legitimate (a so-called “false positive” error) than allow a fraudulent purchase to go through (a “false negative”). Precision and recall are two metrics that can help differentiate between error types and can still prove useful for problems with class imbalance.</p>
<h2 id="precision-and-recall">Precision and Recall</h2>
<p>Both precision and recall are defined in terms of just one class, oftentimes the positive—or minority—class. Let’s return to classifying apples and oranges. Here we will calculate precision and recall specifically for the apple class.</p>
<p>Precision measures the quality of model predictions for one particular class, so for the precision calculation, zoom in on just the apple side of the model. You can forget about the orange side for now.</p>
<p>Precision equals the number of correct apple observations divided by all observations on the apple side of the model. In the example depicted below, the model correctly identified 3 apples, but it classified 5 total fruits as apples. The apple precision is 3 out of 5, or 60%. To remember the definition of precision, note that preci<strong>SI</strong>on focuses on only the apple <strong>SI</strong>de of the model.</p>
<center>
<img src="https://kimfetti.github.io/images/OA_precision.jpg" alt="Precision calculated as 60% for the apple class from example apple-orange model" width="700" />
</center>
<p><br /></p>
<p>Recall, on the other hand, measures how well the model did for the actual observations of a particular class. Now check how the model did specifically for all the actual apples. For this, you can pretend like all of the oranges don’t exist. This model correctly identified 3 out of 4 actual apples; recall is 3 over 4, or 75%. Remember this simple mnemonic: rec<strong>ALL</strong> focuses on <strong>ALL</strong> the actual apples.</p>
<center>
<img src="https://kimfetti.github.io/images/OA_recall.jpg" alt="Recall calculated as 75% for the apple class from example apple-orange model" width="700" />
</center>
<h2 id="precision-recall-tradeoff">Precision-Recall Tradeoff</h2>
<p>So what are the benefits of measuring precision and recall instead of sticking with accuracy? These metrics certainly allow you to emphasize one specific class since they are defined for one class at a time. That means that even if you have imbalanced classes, you can measure precision and recall for your minority class, and these calculations won’t get dominated by the majority class observations. But it turns out that there’s also a nice tradeoff between precision and recall.</p>
<p>Some classification models, such as logistic regression, not only predict which class each observation belongs to but also predict the probability of being in a particular class. For example, the model may determine that a specific fruit has 80% probability of being an apple and 20% probability of being an orange. Models like these come with a decision threshold that we can adjust to divide the classes.</p>
<p>Let’s say you’d like to improve the precision of your model because it’s very important to avoid falsely claiming that an actual orange is an apple (false positive). You can just move the decision threshold up, and precision gets better. For our apple-orange model, that means shifting the model line to the right. In the example image, the updated model boundary yields perfect precision of 100% since all predicted apples are actually apples. When we do this, however, recall will likely decrease because moving the threshold up leaves out actual apples in addition to the erroneous oranges. Here, recall dropped to 50%.</p>
<div class="row">
<div class="large-6 columns">
<img src="https://kimfetti.github.io/images/OA_precision_boundaryRight.jpg" alt="With the decision threshold increased, precision increased to 100% for the apple class" width="450" />
</div>
<div class="large-6 columns">
<img src="https://kimfetti.github.io/images/OA_recall_boundaryRight.jpg" alt="With the decision threshold increased, recall decreased to 50% for the apple class" width="450" />
</div>
</div>
<p><br /></p>
<p>Okay, what if we want to improve recall? We could make our decision threshold lower by moving our model line to the left. We now capture more actual apples on the apple side of our model, but as we do this, our precision likely decreases since more oranges sneak into the apple side as well. With this update, recall improved to 100% but recall declined to 50%.</p>
<div class="row">
<div class="large-6 columns">
<img src="https://kimfetti.github.io/images/OA_recall_boundaryLeft.jpg" alt="With the decision threshold decreased, recall increased to 100% for the apple class" width="450" />
</div>
<div class="large-6 columns">
<img src="https://kimfetti.github.io/images/OA_precision_boundaryLeft.jpg" alt="With the decision threshold decreased, precision decreased to 50% for the apple class" width="450" />
</div>
</div>
<p><br /></p>
<p>Monitoring and selecting an appropriate precision-recall tradeoff allows us to prioritize certain types of errors, either false positives or false negatives, as we adjust the decision threshold of our model.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Precision and recall offer new ways to judge classification model predictions as opposed to the standard accuracy computation. With apple precision and recall, we focus in on the apple class. High precision assures that what our model says is an apple actually is an apple (preci<strong>SI</strong>on = apple <strong>SI</strong>de), but recall prioritizes correctly identifying all of the actual apples (rec<strong>ALL</strong> = <strong>ALL</strong> apples).</p>
<p>Precision and recall allow us to distinguish between different types of errors, and there’s also a great tradeoff between precision and recall because we can’t blindly improve one without often sacrificing the other. The balance between precision and recall can also help us build more robust classification models. In fact, practitioners often measure and try to improve something called the F1-score, which is the harmonic average between precision and recall, when building a classification model. This ensures that both metrics stay healthy and that the dominant class doesn’t overwhelm the metric like it generally does with accuracy.</p>
<p>Choosing an appropriate classification metric is a critical early step in the data science design process. For example, if you want to be sure not to miss a fraudulent transaction, you’ll likely prioritize recall for cases of fraud. Though in other situations, accuracy, precision, or F1-score may be more appropriate. Ultimately, your choice of metric should be intimately linked to the goal of your project, and once it’s determined, that metric of choice should drive your model development and selection process.</p>
2022-04-03T00:00:00+00:00https://kimfetti.github.io/python/course-report-python-ds/Python for Data Science: An Interview with Course Report2020-09-15T00:00:00+00:00KFessel<em>Python is one of the most popular computer programming languages in the world. Find out how Python is used for data science in interview with Course Report.</em><!--more-->
<p>In a recent interview with <a href="https://www.coursereport.com/">Course Report</a>, I discussed the basics of Python and how Python is used for data science. Python serves as an all-purpose programming language, so data scientists, engineers, analysts, and web developers alike utilize Python to build end-to-end projects, ready for launch into production. Python also has incredibly simple syntax, which makes it a great first programming language for beginners. We chat about these topics and many more in the video!</p>
<p>You can also check out a write up of our interview on the <a href="https://www.coursereport.com/blog/how-is-python-used-for-data-science-metis">Course Report blog</a>.</p>
2020-09-15T00:00:00+00:00https://kimfetti.github.io/python/datetime/delorean-datetime-manipulation/Delorean for Datetime Manipulation2020-07-25T00:00:00+00:00KFessel<em>Working with dates and times in Python can lead to frustration, heartache, and, ironically, lost time – but it doesn’t have to! This brief demo introduces Delorean, a library constructed to make datetime manipulation in Python easier. </em><!--more-->
<p>This year’s pandemic necessitated different conference formats for data science professionals. The organizers of PyOhio decided to ask speakers to create 5- or 10-minute pre-recorded talks to be streamed continuously while participants discussed the content in a live chat session. The format was a success! And I am proud to have created this video all about the Python library Delorean.</p>
<p>Delorean makes working with datetimes in Python much less of a burden. Its simple syntax allows users: to do datetime arithmetic, to handle time zone shifts, to convert datetimes into human language like “3 days ago,” and to generate equally spaced datetime intervals.</p>
<p>Check out my video for a look at Delorean (along with many, many <em>Back to the Future</em> references) or watch the <a href="https://www.youtube.com/watch?v=OGmzRIgDgOY&list=PL2k6bbM_wgjtGSzPXzUzP3AfVO-o4imbB">full PyOhio 2020 conference playlist on YouTube</a>.</p>
2020-07-25T00:00:00+00:00https://kimfetti.github.io/mathematics/applications/gini-use-cases/Measuring Statistical Dispersion with the Gini Coefficient2020-06-05T00:00:00+00:00KFessel<em>The Gini coefficient is a good general-purpose measure of statistical dispersion. Long since popular in the field of economics, this metric can be leveraged much more broadly to explore data from nearly any discipline. The following post includes a thorough mathematical explanation of the Gini coefficient as well as a few non-standard use cases.</em><center>
<iframe width="900" height="550" src="//www.youtube.com/embed/nFbAnwIYle4" frameborder="0" allowfullscreen=""></iframe>
</center>
<hr />
<p>If you work with data long enough, you are bound to discover that a dataset’s mean rarely–if ever–tells you the full data story. As a simple example, each of the following groups of people have the same <strong>average pay</strong> of $100:</p>
<ul>
<li>100 people who make $100 each</li>
<li>50 people who make $150 each and 50 people who make $50</li>
<li>1 person who makes $10,000 and 99 people who make nothing</li>
</ul>
<p>The primary difference, of course, is the way that money is distributed among the people, also known as the <a href="https://en.wikipedia.org/wiki/Statistical_dispersion">statistical dispersion</a>. Perhaps the most popular measurement of statistical dispersion is standard deviation or variance; however, you can leverage other metrics, such as the Gini coefficient, to obtain a new perspective.</p>
<p><a href="https://en.wikipedia.org/wiki/Gini_coefficient">The Gini coefficient</a>, also known as the Gini index or the Gini ratio, was introduced in 1912 by Italian statistician and sociologist Corrado Gini. Analysts have historically used this value to study income or wealth distributions; in fact, despite being developed over 100 years ago, <a href="https://www.bbc.com/news/blogs-magazine-monitor-31847943">the United Nations still uses the Gini coefficient</a> to understand monetary inequities in their annual ranking of nations. But the Gini coefficient may be utilized much more broadly! After a more thorough mathematical explanation, let’s apply the Gini coefficient to a few non-standard use cases that do not involve international economies: baby names and healthcare pricing.</p>
<h2 id="defining-gini">Defining Gini</h2>
<p>The first step in understanding the Gini coefficient requires a discussion about the Lorenz curve, a graph developed by Max Lorenz for visualizing income or wealth distribution. To trace out the Lorenz curve, begin by taking the incomes of a population and sorting them from smallest to largest. Then build a line plot where the \(x\)-values represent the percentage of people seen thus far and the \(y\)-values represent the cumulative proportion of wealth attributed to this percentage of people. For example, if the poorest 30% of the population holds 10% of a population’s wealth, the curve should pass through the scaled \(x,y\) coordinates (0.3, 0.1). Note also that if wealth is distributed evenly among all members of a population, the Lorenz curve follows a straight line, \(x=y\). See the figure below for an illustration of a hypothetical Lorenz curve along with the line of equality.</p>
<div class="row">
<div class="large-6 columns">
<img src="https://kimfetti.github.io/images/gini_explanation.png" alt="The areas surrounding the Lorenz curve define the Gini coefficient: A/(A+B)" width="350" />
</div>
<div class="large-6 columns">
<img src="https://kimfetti.github.io/images/gini_animation.gif" alt="The Gini coefficient increases as the inequality gap widens." width="350" />
</div>
</div>
<p><br /></p>
<p>The Gini coefficient measures how much a population’s Lorenz curve deviates from perfect equality or how much a set of data diverges from equal values. The Gini coefficient typically ranges from zero to one<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>, where</p>
<ul>
<li>zero represents perfect equality <em>(e.g. everyone has an equal amount)</em> and</li>
<li>one represents near perfect inequality <em>(e.g. one person has all the money)</em>.</li>
</ul>
<p>For all situations in between, the Gini coefficient \(G\) is defined as
\[G = \frac{A}{A + B}\]
where \(A\) signifies the region enclosed between the line of perfect equality and the Lorenz curve, as indicated in the figure above, while \(A + B\) represents the total triangular area.</p>
<p>Each of the three situations discussed in the introduction produce an average of $100 per person. The Gini coefficient, however, varies greatly for each scenario as seen in the figure below.</p>
<p><img src="https://kimfetti.github.io/images/gini_compare.png" alt="Gini coefficient increases with wealth inequality." width="1000" /></p>
<h2 id="gini-in-python">Gini in Python</h2>
<p>To calculate a dataset’s Gini coefficient with Python, you have the option of computing the shaded area \(A\) with something like <code class="language-plaintext highlighter-rouge">scipy</code>’s <a href="https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.quad.html">quadrature</a> routine. If this style of numerical integration proves slow or too complicated for applications at scale, you can utilize an alternative, <a href="https://en.wikipedia.org/wiki/Gini_coefficient#Definition">equivalent definition of the Gini coefficient</a>.</p>
<blockquote>
<p>The Gini coefficient may also be expressed as half of the data’s <a href="https://en.wikipedia.org/wiki/Mean_absolute_difference#Relative_mean_absolute_difference">relative mean absolute difference</a>, a normalized form of the average absolute difference among all pairs of observations in the dataset.
\[ G = \frac{\sum\limits_i \sum\limits_j |x_i - x_j|}{2\sum\limits_i\sum\limits_j x_j}\]</p>
</blockquote>
<p>The calculation simplifies further if the data consist of only positive values as it becomes <a href="https://www.statsdirect.com/help/default.htm#nonparametric_methods/gini.htm">unnecessary to evaluate all possible pairs</a>. Sorting the datapoints in ascending order and assigning a positional index \(i\) yields
\[G = \frac{\sum\limits_i (2i - n - 1)x_i}{n\sum\limits_i x_i}, \]
which is even speedier to compute.</p>
<p>The best Python implementation of the Gini coefficient that I’ve found comes from <a href="https://github.com/oliviaguest/gini/blob/master/gini.py">Olivia Guest</a>. I will subsequently leverage her vectorized <code class="language-plaintext highlighter-rouge">numpy</code> routine to calculate Gini in the case studies that follow.</p>
<h2 id="case-1-baby-names">Case #1: Baby Names</h2>
<p>So far we have mostly addressed the Gini coefficient in the context of its original field of economics. This metric generalizes, however, to provide insight whenever statistical dispersion plays a critical role. I will now illustrate two atypical applications to demonstrate how using the Gini coefficient augments the workflow of exploratory data analysis.</p>
<p>The Social Security Administration of the United States (SSA) <a href="https://www.ssa.gov/oact/babynames/limits.html">hosts public records</a> on the names given to US babies for research purposes. Aggregating these data for children born since 1950, I discovered that 18 out of the top 20 most popular names more commonly associate with male children. So where are the females?</p>
<center>
<img src="https://kimfetti.github.io/images/popular_names.png" alt="Most popular names given to US babies since 1950" width="500" />
</center>
<p>Slightly <a href="https://www.npr.org/sections/health-shots/2015/03/30/396384911/why-are-more-baby-boys-born-than-girls">more male babies are actually born each year</a>, and certainly more male babies have been registered with the SSA (53% male vs 47% female); nonetheless, I was still surprised to see such a large proportion of male names in my quick popularity chart. Digging into the data further, I found that even though fewer females appear in the data, there have been consistently more unique female names each year.</p>
<center>
<img src="https://kimfetti.github.io/images/unique_names.png" alt="Number of unique names for male and female babies since 1950" width="700" />
</center>
<p><br /></p>
<p>Statistical dispersion appears to play a significant role. To put it back in financial terms, some male names like the ones on my top 20 list are just extremely “wealthy.” (The most popular name, “Michael,” accounts for over 3% of all male children born since 1950.) These ultra-popular masculine names likely pass down from generation to generation. Females babies, on the other hand, are distributed more widely across a variety of names, so extra names share in the “wealth” of female children. We can verify this theory by returning to the Gini coefficient.</p>
<p>Consider how female children disperse across each name. Some names in the dataset account for only 5 babies<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup> since 1950, while “Jennifer” represents nearly 1.5 million individuals. Tallying up all females born with each name since 1950 and sorting the names from least to most popular, we find the Gini coefficient to be 0.96, implying a huge disparity in the most popular versus the most unique names.</p>
<p>Male names exhibit a very similar Lorenz curve but with a little more skew, registering a Gini coefficient of 0.97. The difference between male and female coefficients appears insignificant, but consider an alternative viewpoint. Instead of aggregating across time, calculate a yearly Gini coefficient for each gender. Plotting both the female and male Gini coefficients for each year since 1950 demonstrates a clear and persistent pattern where the male coefficient presents consistently higher.<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup> Thus male names experience more statistical dispersion than female monikers. Also of note, the Gini values for both genders have ticked downward since the 1990s, indicating a trending preference toward more diverse naming conventions.</p>
<center>
<img src="https://kimfetti.github.io/images/gini_names.png" alt="The male Gini coefficient tracks consistently higher throughout time" width="700" />
</center>
<p><br /></p>
<p>In a final look at this dataset, let’s examine popularity trends for individual names over time. Now utilize Gini by grouping the female data by name and calculating the Gini coefficient as it pertains to yearly frequencies; that is, for any given name, sort each year of the dataset by that name’s least to most popular year in order to compute Gini. Names with lower Gini coefficients demonstrate similar levels of popularity throughout the entire time span, while higher coefficients imply uneven popularity levels. The figure below compares popularity trends for the names “Scarlett” and “Miriam.” Both names represent about 60,000 female babies in the dataset; however, the sharp increase in babies named “Scarlett” generates a large Gini coefficient while “Miriam” sees a low Gini value since the name has consistently been given to roughly 1,000 babies every year since 1950.</p>
<center>
<img src="https://kimfetti.github.io/images/scarlett_vs_miriam.png" alt="The popularity of female names Miriam and Scarlett over time with Gini coeffients" width="900" />
</center>
<p><br /></p>
<h2 id="case-2-healthcare-prices">Case #2: Healthcare Prices</h2>
<p>Now shift to <a href="https://www.cms.gov/Research-Statistics-Data-and-Systems/Statistics-Trends-and-Reports/Medicare-Provider-Charge-Data/Inpatient2017">this 2017 healthcare pricing dataset</a> hosted by the Centers for Medicare and Medicaid Services, a federal agency of the United States. These data, aggregated as procedural averages for individual hospitals, include the charges and eventual payments for over 500 separate inpatient procedures for Medicare patients. I applied Gini coefficient calculations to determine which, if any, procedures require better billing standardization. The underlying basis for my analysis boils down to this: the higher the Gini coefficient, the greater the disparity in what different hospitals charge for a given procedure. Procedures with large Gini values could then necessitate regulation or more transparent cost details.</p>
<p>The procedure, or diagnosis related group (DRG), with the highest Gini coefficient in this dataset<sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">4</a></sup> is labeled as, “Alcohol/Drug Abuse or Dependency w Rehabilitation Therapy.” This perhaps elicits little surprise given that rehabilitation therapies vary widely both in terms of treatment length and illness severity; we probably expect a wide range in what assorted hospitals charge. In fact, all diagnoses with the largest Gini coefficients, such as coagulation disorders and psychoses, can vary in severity. Procedural charges that show the most uniformity among the hospitals, on the other hand, mostly describe one-time cardiac events such as value replacement, percutaneous surgeries, or observation for chest pain.</p>
<center>
<table width="800">
<caption>Gini coefficients among average hospital charges per diagnosis related group (DRG)</caption>
<colgroup>
<col span="1" style="width: 50%;" />
<col span="1" style="width: 50%;" />
</colgroup>
<thead>
<tr>
<th><center>Highest Gini</center></th>
<th><center>Lowest Gini</center></th>
</tr>
</thead>
<tbody>
<tr>
<td>Alcohol/Drug Abuse or Dependence w Rehabilitation Therapy</td>
<td>Aortic and Heart Assist Procedures except Pulsation Balloon w MCC</td>
</tr>
<tr>
<td>Coagulation Disorders</td>
<td>Angina Pectoris</td>
</tr>
<tr>
<td>Alcohol/Drug Abuse or Dependence, Left AMA</td>
<td>Cardiac Valve & Oth Maj Cardiothoracic Proc w/o Card Cath w/o CC/MCC</td>
</tr>
<tr>
<td>Psychoses</td>
<td>Heart Transplant or Implant of Heart Assist System w MCC</td>
</tr>
<tr>
<td>Other Respiratory System Diagnoses w MCC</td>
<td>Perc Cardiovasc Proc w/o Coronary Artery Stent w/o MCC</td>
</tr>
</tbody>
</table>
</center>
<p>So what about billing regulation? Do we need more safeguards in place to be sure hospitals are charging similar amounts for similar procedures? Well, more cost transparency certainly doesn’t hurt, especially for treatments that range in duration or intensity, but let’s go back to the dataset. In addition to the information about the amounts hospitals charge, the data also contain <a href="https://www.cms.gov/Research-Statistics-Data-and-Systems/Statistics-Trends-and-Reports/Medicare-Provider-Charge-Data/Downloads/Inpatient_Outpatient_FAQ.pdf">the total payments that the hospitals actually received</a>. Applying the same type of analysis to the payments received yields much lower Gini values. In fact, the Gini coefficient is lower for the average payments received than the hospital charges, for <em>every single procedure</em>. This curious insight signals that the contracts in place for Medicare payments <em>already</em> do quite a lot to moderate and regularize procedural costs.<sup id="fnref:5" role="doc-noteref"><a href="#fn:5" class="footnote" rel="footnote">5</a></sup></p>
<center>
<img src="https://kimfetti.github.io/images/gini_health.png" alt="Comparison of Gini coeffients for total payments vs hospital charges" width="600" />
</center>
<h2 id="conclusion">Conclusion</h2>
<p>The Gini coefficient continues to provide insight over 100 years after its inception. As a good general-purpose measure of statistical dispersion, Gini can be used broadly to explore and understand data from nearly any discipline. Currently, the most popular metric for understanding data spread is likely standard deviation; however, there are <a href="https://stats.stackexchange.com/questions/210829/difference-is-summary-statistics-gini-coefficient-and-standard-deviation/211595">several key differences</a> between standard deviation and the Gini coefficient. Firstly, standard deviation retains the scale of your data. You report the standard deviation of US incomes in dollars, while you might give the standard deviation of temperatures in degrees Celsius. The Gini coefficient, however, has no measurement unit, also called scale invariance. Secondly, standard deviation is unbounded in that it can be any non-negative value, but Gini typically ranges between zero and one. Gini’s scale invariance and strict bounds make comparing statistical dispersion between two dissimilar data sources much easier. Lastly, standard deviation and the Gini coefficient judge statistical dispersion through different lenses. Gini reaches its maximum value for a non-negative dataset if it contains one positive and the rest zeros. Standard deviation reaches its maximum if half the data live at the extreme maximum and the other half register at the extreme minimum.</p>
<p><a href="https://www.scientificamerican.com/article/ask-gini/">Certain limitations</a> apply to the Gini coefficient despite its many benefits. Like other summary statistics, Gini condenses information thereby losing the granularity of the original dataset. Gini is also many-to-one, which means various different distributions map to the same coefficient. The Gini coefficient proves to be quite sensitive to outliers such that a singular extreme datapoint (large or small) can increase Gini dramatically. Yet, economists have also criticized the Gini coefficient for being <a href="https://www.bbc.com/news/blogs-magazine-monitor-31847943">undersensitive to wealth changes in upper and lower echelons</a>. Researchers have go on to introduce several alternative metrics to study different aspects of income inequality, such as the <a href="https://en.wikipedia.org/wiki/Income_inequality_metrics#Palma_ratio">Palma ratio</a>, which explicitly captures financial fluctuations for the richest 10% and the poorest 40% of a population.</p>
<p>No matter which metric you choose to understand statistical dispersion, building data intuition certainly goes beyond simple estimates of the mean or median. The Gini coefficient, long since popular in the field of economics, provides excellent insight about the spread of data regardless of your chosen subject area. As demonstrated in this post, Gini could be tracked over time, calculated for specific segments of your data, or used to detect processes requiring better price standardization. Its applications are limitless, and it might just be the missing component of your EDA toolkit.</p>
<hr />
<p><a href="https://github.com/kimfetti/Blog/blob/master/gini_coefficient.ipynb">Check out this code on GitHub!</a></p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:1" role="doc-endnote">
<p>The Gini coefficient is strictly non-negative, \(G \geq 0\), as long as the mean of the data is assumed positive. Gini can theoretically be greater than one if some data values are negative, which occurs in the context of wealth if some people contribute negatively in the form of debts owed. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>The Social Security Administration does not include names that are given to fewer than 5 babies per gender per state due to privacy reasons; therefore, five children for one given female name since 1950 signifies the absolute minimum allowed. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:3" role="doc-endnote">
<p>The Gini values displayed in the yearly figure are less than the aggregate because popular names tend to stay popular year after year thus bolstering naming inequality and increasing the Gini coefficient. <a href="#fnref:3" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:4" role="doc-endnote">
<p>Some diagnosis related groups (DRGs) occur at as few as one hospital for the entire year. I have filtered the dataset down to procedures that are documented by at least 50 hospitals to avoid high variance issues. <a href="#fnref:4" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:5" role="doc-endnote">
<p>The payments hospitals receive are strictly less than the amounts they charge. Decreasing a dataset’s mean while holding its standard deviation fixed <a href="https://repository.upenn.edu/gse_grad_pubs/6/">actually <em>increases</em> the Gini coefficient</a>. Here we observe just the opposite effect so statistical dispersion must be lessened in the payments received. <a href="#fnref:5" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
2020-06-05T00:00:00+00:00https://kimfetti.github.io/data/web%20scraping/realpython-podcast-web-scraping/Web Scraping in Python: Real Python Podcast2020-06-05T00:00:00+00:00KFessel<em>Do you want to get started with web scraping using Python? Find out more in this Real Python podcast.</em><!--more-->
<p>I recently sat down with Christopher Bailey at the Real Python Podcast to discuss web scraping as well as my <a href="https://www.youtube.com/watch?v=RUQWPJ1T6Zc">PyCon 2020 tutorial</a>: “It’s Officially Legal so Let’s Scrape the Web.” In this podcast we talk about web scraping tools and techniques, HTML basics and data cleaning, as well as a recent change to the legal landscape regarding scraping.</p>
<p>Check out the YouTube video above or listen to the podcast at <a href="https://realpython.com/podcasts/rpp/12/">Real Python</a>.</p>
2020-06-05T00:00:00+00:00https://kimfetti.github.io/data/web%20scraping/python-web-scraping/Let's Scrape the Web: PyCon 2020 Video Tutorial2020-05-04T00:00:00+00:00KFessel<em>Developing web scraping skills allows you to save time and to broaden your access to data. This tutorial covers web scraping with Python from the basics of HTML to the full scraping pipeline.</em><!--more-->
<p>Web scraping empowers you to write computer programs to collect data from websites automatically and recent legal rulings support your right to do so. This tutorial covers the breadth and depth of web scraping: from HTML basics through pipeline methods to compile entire datasets. My video provides step-by-step instructions on utilizing Python libraries like <code class="language-plaintext highlighter-rouge">requests</code> and <code class="language-plaintext highlighter-rouge">BeautifulSoup</code> as well as links to supplementary tutorial resources in the form of Google Colab or Jupyter notebooks.</p>
<p>Check out the supplementary materials via Google Colab (<a href="https://bit.ly/pycon2020_scrapingbasics">Scraping Basics</a> and <a href="https://bit.ly/pycon2020_scrapingwiki">Scraping Wikipedia</a>) or on <a href="https://github.com/kimfetti/Conferences/tree/master/PyCon_2020">GitHub</a>.</p>
2020-05-04T00:00:00+00:00https://kimfetti.github.io/nlp/spacy-for-the-win/Level Up: spaCy NLP for the Win2020-02-21T00:00:00+00:00KFessel<em>spaCy provides an easy-to-use framework for getting started with NLP. This post covers the basics of spaCy and highlights its functionality on a small corpus of restaurant reviews..</em><!--more-->
<p>Natural language processing (NLP) is a branch of artificial intelligence in which computers extract information from written or spoken human language. This field has experienced a massive rise in popularity over the years, not only among academic communities but also in industry settings. Because unstructured text makes up so much of the data we collect today (e.g. emails, text messages, and even this blog post), many practitioners regularly use NLP at the workplace and require straightforward tools to reliably parse through substantial amounts of documents. The open-source library spaCy meets these exact demands by processing text quickly and accurately, all within a simplified framework.</p>
<p><a href="https://explosion.ai/blog/introducing-spacy">Released in 2015</a>, spaCy was initially created to help small businesses better leverage NLP. Its practical design offers users a streamlined approach for accomplishing necessary NLP tasks, and it assumes a more pragmatic stance toward NLP than traditional libraries like NLTK, which were developed with a more research-focused, exploratory intention. spaCy can be quite flexible, however, as it allows more experienced users the option of customizing just about any of its tools. spaCy is considered a Python package, but the “Cy” in spaCy indicates that Cython powers many of the underlining computations. This makes spaCy incredibly fast, even for more complicated processes. I will illustrate a selection of spaCy’s core functionality in this post and will end by implementing these techniques on sample restaurant reviews.</p>
<p>Please continue to the <a href="https://opendatascience.com/level-up-spacy-nlp-for-the-win/">ODSC blog</a> to read my full post covering this introduction to spaCy.</p>
2020-02-21T00:00:00+00:00https://kimfetti.github.io/mathematics/course-report-math-ds/Math for Data Science: An Interview with Course Report2020-02-17T00:00:00+00:00KFessel<em>Math skills are critical for a successful career in data science. Find out why in this interview with Course Report.</em><!--more-->
<p>I recently sat down with <a href="https://www.coursereport.com/">Course Report</a> to discuss the math needed to become a data scientist. Blending coding skills with mathematics lies at the heart of data science, so understanding fundamental math concepts is critical for a successful career within the field. Linear algebra, calculus, probability, and statistics are the four math disciplines that fuel the bulk of data science. In this interview, I discuss the role each topic plays in data science; I also work through an example problem from all four subjects.</p>
<p>Please continue to the <a href="https://www.coursereport.com/blog/math-for-data-science-with-metis">Course Report blog</a> for a write-up of the interview.</p>
<!--
image:
thumb: CourseReport_Thumb.png
homepage: CourseReport_Feb2020.png
title: CourseReport_Feb2020.png
caption: "Photo by CP. Image constructed by Course Report."
caption_url: "https://www.coursereport.com/"
-->
2020-02-17T00:00:00+00:00https://kimfetti.github.io/visualizations/puzzles/down-and-up/Down and Up: A Puzzle Illustrated with D3.js2020-01-05T00:00:00+00:00KFessel<em>Math puzzles provide great amusement for some people, but many others approach them with dread--especially during interviews. Such trepidation may be unwarranted, however, because a simple visual--like the ones illustrated in this post--could be all you need to find a solution.</em><head>
<script src="https://d3js.org/d3.v4.min.js"></script>
<!--Multiple button functions-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.3.0/d3.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<style>
input {
border: none;
color: white;
padding: 8px 16px;
margin: 4px 2px;
cursor: pointer;
}
input[name=paintButton] {
background-color: #271B77;
font-weight: bold;
}
input[name=danceButton] {
background-color: #6BA450;
font-weight: bold;
}
input[name=resetButton] {
background-color: #ADADB0;
margin-top: 15px;
}
</style>
</head>
<!-- Begin Post -->
<p>On a recent vacation my husband and I happened upon an entertainment shop that was well stocked with board games, dice, playing cards, etc. We quickly found an item that both of us, absolute nerds that we are, deemed an essential purchase: a book by Boris A. Kordemsky called <a href="https://www.amazon.com/Moscow-Puzzles-Mathematical-Recreations-Recreational/dp/0486270785/">The Moscow Puzzles: 359 Mathematical Recreations</a>. No, we didn’t spend our entire vacation solving all 359, but we did bring the book home with us and have continued working through them–often over a glass of wine in the evenings.</p>
<p>One particular puzzle recently caught my attention for several reasons. I’ll come back to those reasons in a bit, but for now, the problem is called “Down and Up” and it goes like this:</p>
<blockquote>
<p>Suppose you have two pencils pressed together and held vertically. One inch of the pencil on the left, measuring from its lower end, is smeared with paint. The right pencil is held steady while you slide the left pencil down 1 inch, continuing to press the two pencils together. You then move the left pencil back up and return it to its former position, all while keeping the two pencils touching. You continue these actions until you have moved the left pencil down and up 5 times each. Assume the paint does not dry or run out during this process. <b>How many inches of each pencil are smeared with paint after your final movement?</b></p>
</blockquote>
<p>Take a minute to solve this problem before proceeding if you’d like–spoilers ahead!</p>
<h2 id="first-thoughts">First Thoughts</h2>
<p>When I first heard this problem, I initially thought that perhaps the paint is not smeared to the right pencil at all and perhaps only one inch of paint appears on the left pencil throughout the entire process. (Did you also expect this?) But the <em>second</em> time I read through the problem I started to visualize what might actually be happening. The solution became much more clear as soon as I tried to make a mental picture of the process. Since my husband was solving the problem with me, I made him this sketch to share what I was thinking:</p>
<center>
<img src="https://kimfetti.github.io/images/pencil_sketch.png" alt="Initial ideas as a sketch" width="550" />
</center>
<p><br /></p>
<p>I managed to distinctly envision the situation, arrive at a solution, and communicate my thought process just with this simple sketch. For many math puzzles a rough picture provides all you need find the answer, but if my crude drawing hasn’t fully conveyed the solution to you, no worries. Let’s dive in a bit more methodically with a much nicer illustration.</p>
<p><img style="float: right; padding: 30px;" src="https://kimfetti.github.io/images/pencil_initial.gif" alt="Paint is spread to both pencils immediately" width="500" /></p>
<h2 id="problem-setup">Problem Setup</h2>
<p>From the problem directions, we know that initially only the left pencil is smeared with paint. Recall though that the left pencil presses directly against the right. This means paint immediately transfers to the right pencil as they are squeezed together. So both pencils are smeared with one inch of paint even before any of the five down-up movements occur.</p>
<p><br />
<br />
<br /></p>
<h2 id="solving-and-illustrating-the-full-problem">Solving and Illustrating the Full Problem</h2>
<p>The problem gets a little more complicated as the left pencil moves down and up, but returning to a visual interpretation once again helps immensely. Also feel free to reread the problem statement at any point to regain your bearings.</p>
<p>Both pencils are currently smeared with one inch of paint. Then the left pencil moves down one inch while both pencils continue pressing together. Can you envision what happens when the left pencil moves down? Yes! A clean portion of the left pencil makes contact with the bottom of the right pencil; therefore, another inch of paint transfers over to the left.</p>
<p>The left pencil now lingers one inch lower than the right. One inch of the right pencil is smeared with paint, but paint covers <em>two inches</em> of the left pencil. The left pencil moves up in the next step of the problem, coming back to its original position. So the two pencils realign, but what happens to the paint? Since the left pencil continually makes contact with the right, paint smears over to the right pencil and coats two inches of both pencils at the end of the first down-and-up cycle.</p>
<p>The four remaining cycles proceed similarly, with paint transferring first to the left pencil and then to the right. <b>Finally after five rounds of movements, both pencils are smeared with a total of six inches of paint: an initial inch plus five more inches, one for each of the down-up cycles.</b></p>
<p>This problem ultimately hinges on the ability to translate the problem statement into an explanatory visual. To further contextualize this solution, I created an interactive figure with D3.js. Below both pencils start with one inch of paint as described in the problem setup. Use the “Move Pencil” button to convince yourself of the answer I provided.</p>
<p><em>Note: these pencils are six fictitious inches long. After the fifth movement, the pencils reach equilibrium in that paint completely covers them. Hit the “Reset” button at any time to start over.</em></p>
<p><br /></p>
<div style="width: 100%; padding-bottom: 15px" id="pencilContainer">
<div style="float: left; width: 10%; height: 400; padding-left: 5%;">
<input name="paintButton" type="button" value="Move Pencil" onclick="movePencil(); addPaint(1,800); addPaint(2,2000); incrUnits();" />
<br />
<input name="resetButton" type="button" value="Reset" onclick="removePaint()" />
</div>
</div>
<script>
var pencilColor = "#F0C446";
var paintColor = "#271B77";
var pencilData = [1, 2];
var width = $("div#pencilContainer").width();
var height = 400;
var svg = d3.select("div#pencilContainer").append("svg")
.attr("width", width*.6)
.attr("height", height)
.style('transform', 'translate(40%, 0%)');
var objects = svg.append("g");
var pencils = objects.selectAll("g")
.data(pencilData)
.enter()
.append("g")
.attr("id", function(d, i) { return i; })
.attr("transform", function(d, i) {return "translate(" + i*50 + ",0)"; });
var rects = pencils.append("rect")
.attr("x", 50)
.attr("y", 50)
.attr("width", 50)
.attr("height", 300)
.attr("fill", pencilColor)
.style("fill-opacity", .7)
.style("stroke-width",".2em")
.style("stroke", pencilColor);
var triangles = pencils.append("path")
.attr('d', function(d, i) {
var x = 0, y = 50;
return 'M ' + (50+x) + ' ' + y + ' l ' + y/2 + ' ' + -y + ' l ' + y/2 + ' ' + y + ' z';
})
.attr("fill", pencilColor)
.style("fill-opacity", .4)
.style("stroke-width",".2em")
.style("stroke", pencilColor);
var tips = pencils.append("path")
.attr('d', function(d, i) {
var x = 12.5, y = 25;
return 'M ' + (50+x) + ' ' + y + ' l ' + y/2 + ' ' + -y + ' l ' + y/2 + ' ' + y + ' z';
})
.style("fill-opacity", .7)
.style("stroke-width",".2em")
.style("stroke", "#393731");
var paint = pencils.append("rect")
.attr("x", 50)
.attr("y", 300)
.attr("width", 50)
.attr("height", 50)
.attr("fill", paintColor)
.style("fill-opacity", 0.9)
.style("stroke-width",".2em")
.style("stroke", paintColor);
var paintUnits = 1;
var text = svg.append("text");
text
.attr("x", 225)
.attr("y", 50)
.attr("font-size",22);
text.append("tspan")
.text("Paint:");
var paintText = text.append("tspan")
.attr("dx", 10)
.style("fill", paintColor)
.attr("font-weight", "bold")
.text(paintUnits + " Inch");
function movePencil() {
d3.select("g").selectAll("*")
.filter(function (d) { return d == 1; })
.transition()
.duration(750)
.attr("transform", "translate(0,25)")
.on("end",function() {
d3.select(this)
.transition()
.delay(750)
.attr("transform", "translate(0,0)")
});
}
function addPaint(pencilNumber, delay) {
d3.select("g").selectAll("*")
.filter(function(d) { return d == pencilNumber; })
.filter(function(d,i) { return i == 4; })
.transition()
.delay(delay)
.attr("height", function(d) {
return Math.min(paintUnits*50 + 50, 300);
})
.attr("y", function(d) {
return Math.max(300 - 50*paintUnits, 50);
});
}
function incrUnits() {
paintUnits++;
paintText.transition()
.delay(2400)
.text( Math.min(paintUnits, 6) + " Inches");
}
function removePaint() {
paint
.transition()
.duration(500)
.attr("y", 300)
.attr("height", 50);
paintUnits = 1;
paintText.transition()
.delay(250)
.text( paintUnits + " Inch");
}
</script>
<h2 id="backstory-and-problem-extensions">Backstory and Problem Extensions</h2>
<p>Earlier I mentioned this problem caught my eye for several reasons. The first reason is exactly what we have been discussing. I marveled at how tricky the problem sounds initially as opposed to how simple it becomes as soon as you construct an appropriate mental image of the situation.</p>
<p>The second reason this puzzle piqued my interest is its history. As explained in Kordemsky’s book, Leonid Mikhailovich Rybakov, a Soviet mathematician who lived in the early 20th Century, created this “Down and Up” problem. I deeply appreciate math problems that pervade through many time periods and geographies. Solving such puzzles allows me to feel more connected to the past and to other mathematicians around the globe.</p>
<p>Finally, this problem sparked my curiosity because Rybakov first thought it up when returning home from a successful duck hunt. Kordemsky encourages readers to contemplate why this could be the case but goes on to explain in his “Answers” section. From <em>The Moscow Puzzles</em> book:</p>
<blockquote>
<p>Looking at his boots, Leonid Mikhailovich noticed that their entire lengths were muddied where they usually rub each other while he walks.<br />
“How puzzling,” he thought, “I didn’t walk in any deep mud, yet my boots are muddied up to the knees.” <br />
Now you understand the origin of the puzzle.</p>
</blockquote>
<p>Just as the paint smeared the entire length of both pencils, Rybakov’s boots were covered from tip to top because mud had transferred from one boot to the other as he walked.</p>
<p>I continued to think about how this concept might apply to other situations, and I came up with one amusing but slightly unpleasant example. Consider two lines of contra dancers in which the first dancer in the first line unfortunately feels unwell. If this dancer’s sickness is highly communicable, she will, of course, pass along her malady to her dance partner who is positioned across from her. Sometimes in contra dancing participants exchange dance partners by shifting the two lines laterally. Regrettably, when this happens the newly infected dancer will pass the disease back across the line, and eventually the entire group of dancers become ill. Try out my widget below to see this application in action.</p>
<p><br /></p>
<div style="width: 100%; padding-bottom: 15px" id="contraContainer">
<div style="float: left; width: 10%; height: 400; padding-left: 5%;">
<input name="danceButton" type="button" value="Dance!" onclick="moveBlushers('left', 0); sickBlusher(); moveBlushers('center', 2500); sickGrinner();" />
<br />
<input name="resetButton" type="button" value="Reset" onclick="makeWell()" />
</div>
</div>
<script>
var blushEmoji = "https://kimfetti.github.io/images/emoji_blush.png";
var grinEmoji = "https://kimfetti.github.io/images/emoji_grin.png";
var sickEmoji = "https://kimfetti.github.io/images/emoji_sick.png";
var contraData = [1, 2, 3, 4, 5];
var w = $("div#contraContainer").width();
var h = 200;
var canvas = d3.select("div#contraContainer").append("svg")
.attr("width", w*.75)
.attr("height", h)
.style('transform', 'translate(30%, 0%)');
var blushGroup = canvas.append("g")
.attr("id", "blushers");
var blushers = blushGroup.selectAll("image")
.data(contraData)
.enter()
.append("image")
.attr('xlink:href', function (d, i) {
if (i == 0) {
return sickEmoji;
}
else {
return blushEmoji;
}
})
.attr("x", function (d, i) { return w/75+d*(w/10); })
.attr("y", 0)
.attr('width', w/13)
.attr('height', w/13);
var grinGroup = canvas.append("g")
.attr("id", "grinners");
var grinners = grinGroup.selectAll("image")
.data(contraData)
.enter()
.append("image")
.attr('xlink:href', grinEmoji)
.attr("x", function (d, i) { return w/75+d*(w/10); })
.attr("y", 100)
.attr('width', w/14)
.attr('height', w/14);
var sickNum = 1;
function moveBlushers(pos, delay) {
if (sickNum == 1) { return; }
else {
d3.select("#blushers")
.selectAll("image")
.transition()
.delay(delay)
.duration(1000)
.attr("transform", function(d) {
if (pos=="left") { return "translate(" + -w/10 +", 0)"; }
else if (pos=="center") { return "translate(0, 0)"; }
});
};
}
function sickBlusher() {
{
if (sickNum == 1) { return; }
else { delay = 1200; }
}
d3.select("#blushers")
.selectAll("image")
.filter( function (d) { return d == sickNum; })
.transition()
.delay(delay)
.style("opacity", 0)
.attr("xlink:href", sickEmoji)
.transition()
.duration(800)
.ease(d3.easeLinear)
.style("opacity", 1);
}
function sickGrinner() {
{
if (sickNum == 1) { delay = 300; }
else { delay = 3300; }
}
d3.select("#grinners")
.selectAll("image")
.filter( function (d) { return d == sickNum; })
.transition()
.delay(delay)
.style("opacity", 0)
.on("end", function() {
d3.select(this)
.transition()
.duration(800)
.ease(d3.easeLinear)
.style("opacity", 1)
.attr("xlink:href", sickEmoji)
.attr("width", w/13)
.attr("height", w/13)
});
sickNum++;
}
function makeWell() {
d3.select("#blushers")
.selectAll("image")
.attr('xlink:href', function (d, i) {
if (i == 0) { return sickEmoji; }
else { return blushEmoji; }
})
.attr("width", w/13)
.attr("height", w/13);
d3.select("#grinners")
.selectAll("image")
.attr("xlink:href", grinEmoji)
.attr("width", w/14)
.attr("height", w/14);
sickNum = 1;
}
</script>
<h2 id="conclusion">Conclusion</h2>
<p>I hope you have enjoyed this discussion on one of my new favorite math puzzles along with these illustrative D3 visuals. Making a mental image of a math puzzle is not always easy, but it can be invaluable when solving problems like these–especially if you are a visual learner like myself. The next time you feel stuck on an interview question, check to see if sketching or imagining the physical setup of the problem helps. For me it often does.</p>
<p>I also hope you have enjoyed learning a little about the backstory behind this puzzle. Some of the world’s best math puzzles were created long ago, so I believe looking to the past when attempting to sharpen our minds benefits us greatly. Furthermore, expanding this kind of problem to new applications, like I did with the contra dancers, helps solidify core concepts and builds intuition for future brainteasers. It also makes math problems more enjoyable because you relate them to your own life. So now it’s your turn – can you think of any other “Down and Up” scenarios?</p>
<table>
<tbody>
<tr>
<td>Check out my D3 code on GitHub!</td>
<td> </td>
<td><a href="https://github.com/kimfetti/Blog/blob/master/pencil_paint.html">Pencils and Paint</a></td>
<td> </td>
<td><a href="https://github.com/kimfetti/Blog/blob/master/contra.html">Contra Dancers</a></td>
</tr>
</tbody>
</table>
2020-01-05T00:00:00+00:00https://kimfetti.github.io/data/web%20scraping/gather-youtube-data/How to Gather Data from YouTube2019-11-12T00:00:00+00:00KFessel<em>You can mine YouTube's massive content library for many different types of data. This post provides instructions for obtaining the videos themselves, the video transcripts, as well as YouTube search results.</em><p>Since its 2005 inception, YouTube has entertained, educated, and inspired more than <a href="https://biographon.com/youtube-stats/">one billion people</a>. It now ranks as the <a href="https://www.alexa.com/siteinfo/youtube.com">2nd most visited website</a> on the planet, and its users upload 300 hours of video content every minute. YouTube clearly dominates as the world’s premier source of <a href="https://www.youtube.com/watch?v=_OBlgSz8sSM">cute baby moments</a>, <a href="https://www.youtube.com/watch?v=vq8G81oOHhY">epic sports fails</a>, and <a href="https://www.youtube.com/watch?v=AS7_6Uv_Bn0">hilarious cat videos</a>, but its vast troves of content can also be leverage to strengthen a wide variety of data science projects. In this post, I share how you can gain access to three types of YouTube data: the videos themselves for use in computer vision tasks, the video transcripts for natural language processing (NLP), and video search results for hybrid machine learning efforts.</p>
<p>Please continue to the <a href="https://www.thisismetis.com/blog/how-to-gather-data-from-youtube">Metis blog</a> to read my full post covering data collection from YouTube.</p>
2019-11-12T00:00:00+00:00