<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>MetaSnake</title><link href="https://www.metasnake.com/" rel="alternate"/><link href="https://www.metasnake.com/feeds/all.atom.xml" rel="self"/><id>https://www.metasnake.com/</id><updated>2026-11-07T00:00:00-07:00</updated><entry><title>Your Corporate Training Shouldn't Be a Game of Telephone</title><link href="https://www.metasnake.com/blog/corporate-training-telephone.html" rel="alternate"/><published>2026-11-07T00:00:00-07:00</published><updated>2026-11-07T00:00:00-07:00</updated><author><name>Matt Harrison</name></author><id>tag:www.metasnake.com,2026-11-07:/blog/corporate-training-telephone.html</id><summary type="html">&lt;p&gt;Training requirements get lost when they pass through layers of providers. Working directly with your instructor makes it easier to get the course your team needs.&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;img alt="A photographic composite of a whisper chain turning “Python training” into “Python taming,” ending with Matt holding a python." src="/static/img/blog/telephone/python-training-telephone.png"&gt;&lt;/p&gt;
&lt;p&gt;There are training companies that offer every course under the sun. What their clients might not realize is that those companies sometimes reach out to me to deliver the training.&lt;/p&gt;
&lt;p&gt;You might end up with me as your instructor either way. But how we get there makes a difference.&lt;/p&gt;
&lt;p&gt;I've taught through other providers, and it can be a decent experience. The frustrating part is getting an accurate picture of what the client needs before I walk into the classroom.&lt;/p&gt;
&lt;p&gt;You probably know the game of telephone. Someone whispers a message to the next person in line. Each person passes it along. By the time the last person says it out loud, everyone is laughing at how much it has changed.&lt;/p&gt;
&lt;p&gt;That's less funny when you've paid for training and taken your team away from their work.&lt;/p&gt;
&lt;p&gt;Here's how it happens. A manager or learning director decides the team needs training. They discuss the requirements internally and send them to their training provider. The provider checks its catalog. If nothing fits, someone drafts an outline for a course that appears to cover the request.&lt;/p&gt;
&lt;p&gt;Then they look for someone to teach it. Sometimes they go through another provider, who repeats the process before finding an instructor. By the time the request reaches me, I might have a course title, an outline, and a vague description of the audience. The people who could explain what the team actually needs are several conversations away.&lt;/p&gt;
&lt;p&gt;A great instructor can deliver a great course from that outline. It still might be the wrong course for the team.&lt;/p&gt;
&lt;p&gt;When you work directly with me, I can talk to your technical people. I can ask what they're doing, where they're struggling, and what they already know. We can work out what the training should cover together. If something is unclear, I can ask the person who knows the answer.&lt;/p&gt;
&lt;p&gt;That conversation is part of preparing the course. It helps me choose the content, examples, and depth that will be useful to your team.&lt;/p&gt;
&lt;p&gt;The providers sometimes tell me they're doing the hard work for me by managing the client relationship. I understand the appeal, but talking to the client is work I want to do. I care about delivering a great course, and those conversations give me a better chance of preparing one.&lt;/p&gt;
&lt;p&gt;It's also much less frustrating than standing in front of a class and seeing confused faces because a requirement got mistranslated along the way. Finding that out in the classroom wastes everyone's time.&lt;/p&gt;
&lt;p&gt;I understand why a company wants one provider for all its training. There's a catalog. There are boxes to check. Someone can say, "Yes, we offer that."&lt;/p&gt;
&lt;p&gt;But who are those boxes serving? Does the arrangement help your colleagues get the training they need, or does it just make the purchasing process look easier?&lt;/p&gt;
&lt;p&gt;If you want training in Python, data science, or AI, consider going directly to someone who teaches it. In my experience, you can often get a course that fits your team better and costs less. You may even get the same instructor the larger provider would have hired, with a chance to talk to them before the requirements have passed through five other people.&lt;/p&gt;
&lt;p&gt;Before you book your next course, take five minutes to look for the people who actually deliver the training. Ask whether you can talk to the instructor about your team's needs.&lt;/p&gt;
&lt;p&gt;If you'd like to have that conversation with me, &lt;a href="mailto:matt@metasnake.com?subject=Plan%20Team%20Training"&gt;get in touch&lt;/a&gt;.&lt;/p&gt;</content><category term="misc"/><category term="Python"/><category term="training"/><category term="data-science"/><category term="AI"/></entry><entry><title>Why MetaSnake Training</title><link href="https://www.metasnake.com/blog/why-metasnake-training.html" rel="alternate"/><published>2026-08-24T00:00:00-06:00</published><updated>2026-08-24T00:00:00-06:00</updated><author><name>Matt Harrison</name></author><id>tag:www.metasnake.com,2026-08-24:/blog/why-metasnake-training.html</id><summary type="html">&lt;p&gt;Why effective technical training aligns teams around shared practices, stronger judgment, and responsible AI-assisted development.&lt;/p&gt;</summary><content type="html">&lt;p&gt;There are many ways for a technical team to learn.&lt;/p&gt;
&lt;p&gt;You can leave training to individual team members. You can purchase access to an on-demand platform. You can bring in an instructor for a workshop or customized course. Each option solves a different problem.&lt;/p&gt;
&lt;p&gt;Self-study works well when one person needs to learn a narrow skill. On-demand courses provide flexibility and sacrifice depth and customization for some breadth. Live training becomes especially valuable when the problem is not just individual knowledge, but how the team works together.&lt;/p&gt;
&lt;p&gt;Put ten Python developers on a team, and you may get ten different approaches to environments, dependency management, project structure, testing, code review, and AI-assisted development. Each approach may appear reasonable in isolation. Together, they create friction.&lt;/p&gt;
&lt;p&gt;The right training should do more than teach another library or demonstrate a collection of features. It should help the team establish a shared vocabulary, a shared set of practices, and a more effective way to make technical decisions.&lt;/p&gt;
&lt;p&gt;That is the problem MetaSnake training is designed to solve.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Matt Harrison teaching a technical training workshop" src="/static/img/blog/matt-teaching-point.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Training creates a neutral environment where the most senior and the newest team members can come together and learn to speak a common language. It is a rising tide that lifts all boats. Involving everyone in the training process creates a sense of unity and shared responsibility. Senior developers have the opportunity to 
compare assumptions and share implicit knowledge. This alignment is crucial for effective collaboration and maintaining code quality.&lt;/p&gt;
&lt;p&gt;I (Matth Harrison) worked as a backend developer and data scientist and have seen the good, the bad, and the ugly of software development. &lt;/p&gt;
&lt;p&gt;Because MetaSnake has experience across a wide range of industries and applications, we can cater our training to your specific needs. 
Rather than using canned examples, we can use your code and your problems to teach the principles and practices that will help your team be more effective. &lt;/p&gt;
&lt;p&gt;Finally, perhaps the elephant in the room is AI. I've used AI for development since copying and pasting out of ChatGPT. I've trained teams that use 
different agents. I've used AI to write more code in the last year than I have in the last decade. The key is to know where to insert the human in the
loop. I have a framework for doing that that I've taught to teams building the next generation of computers to some of the largest companies in the world. &lt;/p&gt;
&lt;p&gt;Training should not leave participants with a folder full of slides and a few new commands. It should leave the team with stronger judgment, more consistent practices, and a workflow they can continue using after the course ends.&lt;/p&gt;
&lt;p&gt;If your team is struggling with inconsistent Python practices, fragile data workflows, ineffective testing, or uncontrolled AI adoption, reach out. We can discuss where the friction is occurring and whether a talk, workshop, or customized course is the right way to address it.&lt;/p&gt;</content><category term="misc"/><category term="Python"/><category term="training"/><category term="software-engineering"/><category term="AI"/></entry><entry><title>Exaggerate to Calibrate</title><link href="https://www.metasnake.com/blog/exaggerate-to-calibrate.html" rel="alternate"/><published>2026-08-13T00:00:00-06:00</published><updated>2026-08-13T00:00:00-06:00</updated><author><name>Matt Harrison</name></author><id>tag:www.metasnake.com,2026-08-13:/blog/exaggerate-to-calibrate.html</id><summary type="html">&lt;p&gt;What mountain-bike pumping teaches us about exaggerating movement, seeing the full range of possibility, and applying better software-engineering practices with AI.&lt;/p&gt;</summary><content type="html">&lt;p&gt;I've long felt that part of being a well-rounded individual is balance. For me that often means moving my body. My work tends to involve a lot of sitting (or standing) in one place. To help with my "cabin fever," I like to get outside. Often that involves some sort of "mountain activity".&lt;/p&gt;
&lt;p&gt;During winter months, skiing is my preferred activity. In the summer, I like to bike. &lt;/p&gt;
&lt;p&gt;As an educator, I'm constantly thinking of ways to improve my teaching methods and engage my students. At some point, when you participate in an activity a lot, you notice things. Where am I weak? Where can I improve? How did they do that? Why can't I do that? &lt;/p&gt;
&lt;p&gt;I've also read self-help books for improving athletic performance. Body mechanics (and awareness of said mechanics) is one of the most important aspects of improving performance. One should be aware of how their body moves. Generally, this is very hard unless you have a mirror, a video of yourself performing an action, or a coach to provide feedback. We tend to overestimate what our body is doing. Truthful awareness of real body mechanics can unlock a new skill.&lt;/p&gt;
&lt;p&gt;I'll give an example in mountain biking. There is the notion of "pumping" the bike. When I started mountain biking in the late eighties, this skill (that existed in BMX) was not discussed. Now, we have "pump tracks", a small looped track with rollers and banked turns. Ideally, you should be able to ride around a pump track without pedaling - only pumping the bike.&lt;/p&gt;
&lt;p&gt;The first time our high school mountain biking team went to a pump track, I thought "Cool, this will be easy." I proceeded to pedal (an illegal move on a pump track) and push and pull on the bike handlebars. It wasn't working. The unlock for me was pump with my legs. My attempts to pump with my arms (and pedalling) left most of my body static. I wasn't using my largest muscles to manipulate my body position and thus transfer energy to the bike. Once I realized that I needed to pump with my legs, I was able to ride the pump track without pedaling. It was a revelation.&lt;/p&gt;
&lt;figure class="article-figure"&gt;
&lt;img src="/static/img/blog/exaggeration/bike-pumping-vs-static.webp" width="1693" height="929" alt="Comic contrasting a mountain biker dramatically pumping with the legs against a rigid rider stalled on a pump track" loading="lazy" decoding="async"&gt;
&lt;figcaption&gt;Pump with your legs—or stand there looking deeply concerned.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;That's not the whole story, though. Initially, I was barely pumping my legs. I was told to exaggerate the motion. Pump all the way down as far as you can, and then all the way up. Go past where it is comfortable. Exaggerate! By exaggerating the motion, I could physically "see" that my initial leg pump was too small. Only by exaggerating the motion could I see the full range of motion and understand how to use my legs effectively. &lt;/p&gt;
&lt;p&gt;This same exaggeration technique can certainly be applied to other sports. I've used it in skiing. &lt;/p&gt;
&lt;p&gt;I'm currently teaching my daughter how to throw a forehand and backhand in (ultimate) frisbee. She tends to throw with only the forearm and wrist. By having her exaggerate the motion of her entire arm and body, she can see how much more power and control she can generate. Then she can recalibrate her throw to use the full range of motion without overdoing it.&lt;/p&gt;
&lt;p&gt;What does any of this have to do with technology? We are in a space where AI can now write most code for us. I've found that allows me to force the AI to apply all of the software engineering best-practices that I want. The geek in me rejoices! In the past, many of those best practices were often ignored or sacrificed for expediency. &lt;/p&gt;
&lt;p&gt;Don't just let AI pull your body down the hill. Exaggerate the best practices and techniques that you want to see in your application. Then you can come back and recalibrate to determine what is actually needed. &lt;/p&gt;
&lt;p&gt;If your team isn't aware of best practices, reach out. I think I can help.&lt;/p&gt;</content><category term="misc"/><category term="AI"/><category term="software-engineering"/><category term="learning"/><category term="mountain-biking"/></entry><entry><title>Python for Finance: Pandas Resample, Groupby, and Rolling</title><link href="https://www.metasnake.com/blog/python-for-finance-pandas-resample-groupby-rolling.html" rel="alternate"/><published>2023-05-31T00:00:00-06:00</published><updated>2026-08-11T00:00:00-06:00</updated><author><name>Matt Harrison</name></author><id>tag:www.metasnake.com,2023-05-31:/blog/python-for-finance-pandas-resample-groupby-rolling.html</id><summary type="html">&lt;p&gt;Use pandas resample, groupby, Grouper, and rolling operations to understand trends in time-series data through an analysis of FDIC bank failures.&lt;/p&gt;</summary><content type="html">&lt;div class="article-note"&gt;
&lt;strong&gt;Republication note:&lt;/strong&gt; I originally wrote this article for Ponder, where it was published on May 31, 2023. Ponder later removed the post following its acquisition, so I have preserved it here. The Ponder-specific code reflects the environment available when the article was written; the pandas concepts remain broadly applicable. &lt;a href="https://web.archive.org/web/20230613201128/https://ponder.io/python-for-finance-pandas-resample-groupby-and-rolling/"&gt;View the archived original.&lt;/a&gt;
&lt;/div&gt;

&lt;figure class="article-figure article-figure--hero"&gt;
&lt;img src="/static/img/blog/pandas-finance/hero.png" width="896" height="512" alt="Bank buildings and a financial time-series chart" decoding="async"&gt;
&lt;figcaption&gt;Exploring FDIC bank failures with pandas time-series tools.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Welcome back! Today we will explore how you can leverage pandas to understand trends in time-series data quickly, with a particular focus on time-series methods like &lt;code&gt;.resample&lt;/code&gt;, grouping by dates, and performing &lt;code&gt;.rolling&lt;/code&gt; operations to smooth out the results. Along the way, I might grumble a bit (I’d like to think that the grey strands in my beard are from wisdom and not fighting with a computer), but I intend to give you some superpowers.&lt;/p&gt;
&lt;p&gt;If you work with time series data, you will want to understand &lt;code&gt;.resample&lt;/code&gt;, grouping, and &lt;code&gt;.rolling&lt;/code&gt;, as they will make your life much easier.&lt;/p&gt;
&lt;p&gt;The code below preserves that original environment and demonstrates the pandas concepts as they appeared in the original post.&lt;/p&gt;
&lt;p&gt;Let’s start by picking a dataset that might be relevant considering recent news… bank failures.&lt;/p&gt;
&lt;h2&gt;Data Overview: FDIC BankFind Suite&lt;/h2&gt;
&lt;p&gt;In recent years, the banking sector in the United States has witnessed many financial institution failures, leading to substantial economic losses and systemic risks. The Federal Deposit Insurance Corporation (FDIC) bank failure data provides valuable insights into the underlying causes of these failures and helps develop effective risk management and regulatory compliance strategies. By exploring this data with the aid of the popular data analysis library, pandas, one can identify patterns and trends, prepare data for modeling, and visualize findings effectively.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://banks.data.fdic.gov/bankfind-suite/"&gt;BankFind Suite&lt;/a&gt; is a comprehensive database provided by the FDIC, which allows users to search for current and former FDIC-insured banking institutions based on name, FDIC certificate number, website, or location. This tool offers detailed information on an institution’s financial history and trends, enabling users to track the performance of individual institutions, groups of institutions, or the industry as a whole.&lt;/p&gt;
&lt;p&gt;Let’s use the Bank Failure data to explore. I will download the data from 1934 to 2023 containing over 4000 entries.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pandas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;bankfail.csv&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;
&lt;span class="go"&gt;    CERT    CHCLASS1    CITYST          COST    FAILDATE    FIN ID  NAME                    QBFASSET    QBFDEP      RESTYPE RESTYPE1    SAVR&lt;/span&gt;
&lt;span class="go"&gt;0   15426.0 NM      ALMENA, KS      16806.0 10/23/2020  10538   4104    ALMENA STATE BANK           65733.0     64941.0     FAILURE PA      DIF&lt;/span&gt;
&lt;span class="go"&gt;1   16748.0 NM      FORT WALTON BEACH, FL   7247.0  10/16/2020  10537   4103    FIRST CITY BANK OF FLORIDA      136566.0    133936.0    FAILURE PA      DIF&lt;/span&gt;
&lt;span class="go"&gt;2   14361.0 NM      BARBOURSVILLE, WV   45913.0 4/3/2020    10536   4102    THE FIRST STATE BANK            151808.0    143102.0    FAILURE PA      DIF&lt;/span&gt;
&lt;span class="go"&gt;3   18265.0 NM      ERICSON, NE     25293.0 2/14/2020   10535   4101    ERICSON STATE BANK          100879.0    95159.0     FAILURE PA      DIF&lt;/span&gt;
&lt;span class="go"&gt;4   21111.0 N       NEWARK, NJ      1946.0  11/1/2019   10534   4100    CITY NATIONAL BANK OF NEW JERSEY    120574.0    111234.0    FAILURE PA      DIF&lt;/span&gt;
&lt;span class="go"&gt;... ... ...     ...         ... ...     ... ... ...                 ...     ...     ... ...     ...&lt;/span&gt;
&lt;span class="go"&gt;4099    NaN NM      LEWISPORT, KY       NaN 8/6/1934    0   137 BANK OF LEWISPORT           81.0        68.0        FAILURE PO      BIF&lt;/span&gt;
&lt;span class="go"&gt;4100    NaN N       LIMA, MT        NaN 7/18/1934   0   135 FIRST NATIONAL BANK OF LIMA     91.0        42.0        FAILURE PO      BIF&lt;/span&gt;
&lt;span class="go"&gt;4101    NaN NM      FLORENCE, IN        NaN 7/18/1934   0   136 FLORENCE DEPOSIT BANK           105.0       69.0        FAILURE PO      BIF&lt;/span&gt;
&lt;span class="go"&gt;4102    NaN NM      EAST PEORIA, IL     NaN 5/28/1934   0   133 FON DU LAC STATE BANK           374.0       238.0       FAILURE PO      BIF&lt;/span&gt;
&lt;span class="go"&gt;4103    NaN NM      PITTSBURGH, PA      NaN 4/19/1934   0   134 BANK OF AMERICA TRUST CO.       1435.0      1064.0      FAILURE PO      BIF&lt;/span&gt;
&lt;span class="go"&gt;4104 rows × 13 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It looks like my CSV export loaded ok. However, the existing column names are a little annoying. I’m going to clean them up.&lt;/p&gt;
&lt;p&gt;Here’s some code to rename the columns, create a &lt;em&gt;city&lt;/em&gt; and &lt;em&gt;state&lt;/em&gt; column, and convert the &lt;em&gt;date&lt;/em&gt; column to a datetime type.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;colnames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;CERT&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;cert&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;  &lt;span class="s1"&gt;&amp;#39;CHCLASS1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;charter_class&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;   &lt;span class="s1"&gt;&amp;#39;CITYST&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;location&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;   &lt;span class="s1"&gt;&amp;#39;COST&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;estimated_loss&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;   &lt;span class="s1"&gt;&amp;#39;FAILDATE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;effective_date&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;   &lt;span class="s1"&gt;&amp;#39;FIN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;fin&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;   &lt;span class="s1"&gt;&amp;#39;ID&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;   &lt;span class="s1"&gt;&amp;#39;NAME&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;institution&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;   &lt;span class="s1"&gt;&amp;#39;QBFASSET&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;total_assets&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;   &lt;span class="s1"&gt;&amp;#39;QBFDEP&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;total_deposits&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;   &lt;span class="s1"&gt;&amp;#39;RESTYPE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;resolution&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;   &lt;span class="s1"&gt;&amp;#39;RESTYPE1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;transaction_type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;   &lt;span class="s1"&gt;&amp;#39;SAVR&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;insurance_fund&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;tweak_bank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FAILDATE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_datetime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FAILDATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%m/&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s1"&gt;/%Y&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                  &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CITYST&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                  &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CITYST&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                 &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;CITYST&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;colnames&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;         &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;bank&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tweak_bank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;bank&lt;/span&gt;
&lt;span class="go"&gt;    cert    charter_class   estimated_loss  effective_date  fin id  institution             total_assets    total_deposits  resolution  transaction_type    insurance_fund  city            state&lt;/span&gt;
&lt;span class="go"&gt;0   15426.0 NM      16806.0     2020-10-23  10538   4104    ALMENA STATE BANK           65733.0     64941.0     FAILURE     PA          DIF     ALMENA          KS&lt;/span&gt;
&lt;span class="go"&gt;1   16748.0 NM      7247.0      2020-10-16  10537   4103    FIRST CITY BANK OF FLORIDA      136566.0    133936.0    FAILURE     PA          DIF     FORT WALTON BEACH   FL&lt;/span&gt;
&lt;span class="go"&gt;2   14361.0 NM      45913.0     2020-04-03  10536   4102    THE FIRST STATE BANK            151808.0    143102.0    FAILURE     PA          DIF     BARBOURSVILLE       WV&lt;/span&gt;
&lt;span class="go"&gt;3   18265.0 NM      25293.0     2020-02-14  10535   4101    ERICSON STATE BANK          100879.0    95159.0     FAILURE     PA          DIF     ERICSON         NE&lt;/span&gt;
&lt;span class="go"&gt;4   21111.0 N       1946.0      2019-11-01  10534   4100    CITY NATIONAL BANK OF NEW JERSEY    120574.0    111234.0    FAILURE     PA          DIF     NEWARK          NJ&lt;/span&gt;
&lt;span class="go"&gt;... ... ...     ...     ...     ... ... ...                 ...     ...     ...     ...         ...     ...         ...&lt;/span&gt;
&lt;span class="go"&gt;4099    NaN NM      NaN     1934-08-06  0   137 BANK OF LEWISPORT           81.0        68.0        FAILURE     PO          BIF     LEWISPORT       KY&lt;/span&gt;
&lt;span class="go"&gt;4100    NaN N       NaN     1934-07-18  0   135 FIRST NATIONAL BANK OF LIMA     91.0        42.0        FAILURE     PO          BIF     LIMA            MT&lt;/span&gt;
&lt;span class="go"&gt;4101    NaN NM      NaN     1934-07-18  0   136 FLORENCE DEPOSIT BANK           105.0       69.0        FAILURE     PO          BIF     FLORENCE        IN&lt;/span&gt;
&lt;span class="go"&gt;4102    NaN NM      NaN     1934-05-28  0   133 FON DU LAC STATE BANK           374.0       238.0       FAILURE     PO          BIF     EAST PEORIA     IL&lt;/span&gt;
&lt;span class="go"&gt;4103    NaN NM      NaN     1934-04-19  0   134 BANK OF AMERICA TRUST CO.       1435.0      1064.0      FAILURE     PO          BIF     PITTSBURGH      PA&lt;/span&gt;
&lt;span class="go"&gt;4104 rows × 14 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Not bad. This is going to be great data for learning &lt;code&gt;.resample&lt;/code&gt;, &lt;code&gt;.groupby&lt;/code&gt;, and &lt;code&gt;.rolling&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Data Dictionary&lt;/h3&gt;
&lt;p&gt;Here is the description of the columns for those (like me) who aren’t subject matter experts. (All descriptions taken from &lt;a href="https://banks.data.fdic.gov/bankfind-suite/failures/help#DEFINITIONS"&gt;here&lt;/a&gt;.)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;cert – Certificate number assigned by FDIC to identify the institution&lt;/li&gt;
&lt;li&gt;charter_class – The FDIC assigns classification codes indicating an institution’s charter type (commercial bank, savings bank, or savings association), its chartering agent (state or federal government), its Federal Reserve membership status (member or nonmember), and its primary federal regulator (state-chartered institutions are subject to both federal and state supervision). These codes are:&lt;/li&gt;
&lt;li&gt;N National chartered commercial bank supervised by the Office of the Comptroller of the&lt;/li&gt;
&lt;li&gt;SM State charter Fed member commercial bank supervised by the Federal Reserve&lt;/li&gt;
&lt;li&gt;NM State charter Fed nonmember commercial bank supervised by the FDIC&lt;/li&gt;
&lt;li&gt;SA State or federal charter savings association supervised by the Office of Thrift Supervision or Office of the Comptroller of the Currency&lt;/li&gt;
&lt;li&gt;SB State charter savings bank supervised by the FDIC&lt;/li&gt;
&lt;li&gt;estimated_loss – the difference between the amount disbursed from the Deposit Insurance Fund (DIF) to cover obligations to insured depositors and the amount estimated to be ultimately recovered from the liquidation of the receivership estate. Estimated losses reflect unpaid principal amounts deemed unrecoverable and do not reflect interest that may be due on the DIF’s administrative or subrogated claims should its principal be repaid in full.&lt;/li&gt;
&lt;li&gt;effective_date – date of failure.&lt;/li&gt;
&lt;li&gt;fin – Financial institute number. Another unique identifier.&lt;/li&gt;
&lt;li&gt;id – Institution directory number&lt;/li&gt;
&lt;li&gt;name – Legal name of the institution.&lt;/li&gt;
&lt;li&gt;total_assets – The Total assets owned by the institution, including cash, loans, securities, bank premises, and other assets as of the last Call Report or Thrift Financial Report.&lt;/li&gt;
&lt;li&gt;total_deposits – Total including demand deposits, money market deposits, other savings deposits, time deposits and deposits in foreign offices as of the last Call Report.&lt;/li&gt;
&lt;li&gt;resolution – Failure stature. Failure or assistance by merging with other institution.&lt;/li&gt;
&lt;li&gt;transaction_type – Resolution type. Cat 1 – Institution’s charter survives. Cat 2 – Charter terminated. Cat 3 – Payout:&lt;/li&gt;
&lt;li&gt;A/A – Cat1. (Assistance Transactions). Assistance was provided to the acquirer, who purchased the entire institution.&lt;/li&gt;
&lt;li&gt;REP – Cat1. Re-privatization, management takeover with or without assistance at takeover, followed by a sale with or without additional assistance.&lt;/li&gt;
&lt;li&gt;P&amp;amp;A – Cat2. Purchase and Assumption, where some or all of the deposits, certain other liabilities, and a portion of the assets (sometimes all of the assets) were sold to an acquirer. It was not determined if all the deposits (PA) or only the insured deposits (PI) were assumed.&lt;/li&gt;
&lt;li&gt;PA – Cat2. Purchase and Assumption, where the insured and uninsured deposits, certain other liabilities, and a portion of the assets were sold to an acquirer.&lt;/li&gt;
&lt;li&gt;PI – Cat2. Purchase and Assumption of the insured deposits only, where the traditional P&amp;amp;A was modified so that the acquiring institution assumed only the insured deposits.&lt;/li&gt;
&lt;li&gt;IDT – Cat2. Insured deposit Transfer, where the acquiring institution served as a paying agent for the insurer, established accounts on their books for depositors and often acquired some assets as well.&lt;/li&gt;
&lt;li&gt;ABT – Cat2. Asset-backed transfer, an FSLIC transaction that is very similar to an IDT.&lt;/li&gt;
&lt;li&gt;MGR – Cat2.An institution where FSLIC took over management and generally provided financial assistance. FSLIC closed down before the institution was sold. transactions&lt;/li&gt;
&lt;li&gt;PO – Cat3 – Payout, where the insurer paid the depositors directly and placed the assets in a liquidating receivership.&lt;/li&gt;
&lt;li&gt;insurance_fund – Insurance fund.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Counts of failures by year&lt;/h2&gt;
&lt;p&gt;Let’s use pandas to find the count of failures by year.&lt;/p&gt;
&lt;p&gt;When I hear the words “by year,” I immediately think we need to group this data by year. This is like one of those word math problems that everyone hated in junior high until they understood how to convert the words to math. The same thing happens here. When your boss tells you they want “failures by year,” you should think, “I’m going to use the &lt;em&gt;year&lt;/em&gt; column in the pandas &lt;code&gt;.groupby&lt;/code&gt; method.”&lt;/p&gt;
&lt;p&gt;In this case, we don't have a &lt;code&gt;year&lt;/code&gt; column. But due to the magic of datetime columns, we can access the year through the &lt;code&gt;.dt&lt;/code&gt; accessor.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;bank&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;effective_date&lt;/span&gt;
&lt;span class="go"&gt;0      2020-10-23&lt;/span&gt;
&lt;span class="go"&gt;1      2020-10-16&lt;/span&gt;
&lt;span class="go"&gt;2      2020-04-03&lt;/span&gt;
&lt;span class="go"&gt;3      2020-02-14&lt;/span&gt;
&lt;span class="go"&gt;4      2019-11-01&lt;/span&gt;
&lt;span class="go"&gt;          ...    &lt;/span&gt;
&lt;span class="go"&gt;4099   1934-08-06&lt;/span&gt;
&lt;span class="go"&gt;4100   1934-07-18&lt;/span&gt;
&lt;span class="go"&gt;4101   1934-07-18&lt;/span&gt;
&lt;span class="go"&gt;4102   1934-05-28&lt;/span&gt;
&lt;span class="go"&gt;4103   1934-04-19&lt;/span&gt;
&lt;span class="go"&gt;Name: effective_date, Length: 4104, dtype: datetime64[ns]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bank&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bank&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;effective_date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;effective_date&lt;/span&gt;
&lt;span class="go"&gt;1934     9&lt;/span&gt;
&lt;span class="go"&gt;1935    25&lt;/span&gt;
&lt;span class="go"&gt;1936    69&lt;/span&gt;
&lt;span class="go"&gt;1937    75&lt;/span&gt;
&lt;span class="go"&gt;1938    74&lt;/span&gt;
&lt;span class="go"&gt;        ..&lt;/span&gt;
&lt;span class="go"&gt;2015     8&lt;/span&gt;
&lt;span class="go"&gt;2016     5&lt;/span&gt;
&lt;span class="go"&gt;2017     8&lt;/span&gt;
&lt;span class="go"&gt;2019     4&lt;/span&gt;
&lt;span class="go"&gt;2020     4&lt;/span&gt;
&lt;span class="go"&gt;Length: 84, dtype: int64&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is ok. I would prefer a visualization to this table of data. Let’s try a bar chart.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bank&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bank&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;effective_date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="Bank failures by year shown as a bar chart" src="/static/img/blog/pandas-finance/failures-by-year-bar.png"&gt;&lt;/p&gt;
&lt;p&gt;This is a start, but the x-axis is not happy. Just be aware that if you intend on making bar plots with pandas, it converts the index to categories. In this case, the dates are converted to strings. This makes me sad, but not every library is perfect.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/pandas-dev/pandas/issues/17001"&gt;https://github.com/pandas-dev/pandas/issues/17001&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let’s try and make a line plot instead.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bank&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bank&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;effective_date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="Bank failures by year shown as a line chart" src="/static/img/blog/pandas-finance/failures-by-year-line.png"&gt;&lt;/p&gt;
&lt;p&gt;This looks good. Line plots in pandas (unlike bar plots) respect dates in the index.&lt;/p&gt;
&lt;p&gt;Now let’s jump into grouping functionality that is time-series specific.&lt;/p&gt;
&lt;h2&gt;Using Offset Aliases with Pandas Resample&lt;/h2&gt;
&lt;p&gt;Hidden away in the pandas documentation is a mention of &lt;em&gt;offset aliases&lt;/em&gt;. (Sadly, these are not accessible from the docstrings inside of Jupyter, which is one lament I have with pandas otherwise excellent documentation).&lt;/p&gt;
&lt;p&gt;You can find them &lt;a href="https://pandas.pydata.org/docs/user_guide/timeseries.html#dateoffset-objects"&gt;here&lt;/a&gt;, or documented in my book, &lt;em&gt;Effective Pandas&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In short, &lt;code&gt;Y&lt;/code&gt;, &lt;code&gt;Q&lt;/code&gt;, &lt;code&gt;M&lt;/code&gt;, &lt;code&gt;W&lt;/code&gt;, and &lt;code&gt;D&lt;/code&gt; mean year, quarter, month, week, and day respectively. If you memorize these single-letter shortcuts, the &lt;code&gt;.resample&lt;/code&gt; method, or the &lt;code&gt;pd.Grouper&lt;/code&gt; class, you can quickly aggregate date information by different time intervals.&lt;/p&gt;
&lt;p&gt;Let's try and view failures by month using the &lt;code&gt;.resample&lt;/code&gt; method. Pandas resampling is powerful because it lets you convert time-series data with one time interval into time-series data with different time intervals. You can upsample so you have more rows over shorter intervals, or downsample so you have fewer rows over longer intervals. The key to using this method is sticking a date column into the index and then calling &lt;code&gt;.resample&lt;/code&gt; instead of &lt;code&gt;.groupby&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bank&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;effective_date&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;M&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;effective_date&lt;/span&gt;
&lt;span class="go"&gt;1934-04-30    1&lt;/span&gt;
&lt;span class="go"&gt;1934-05-31    1&lt;/span&gt;
&lt;span class="go"&gt;1934-07-31    2&lt;/span&gt;
&lt;span class="go"&gt;1934-08-31    1&lt;/span&gt;
&lt;span class="go"&gt;1934-09-30    1&lt;/span&gt;
&lt;span class="go"&gt;             ..&lt;/span&gt;
&lt;span class="go"&gt;2019-10-31    2&lt;/span&gt;
&lt;span class="go"&gt;2019-11-30    1&lt;/span&gt;
&lt;span class="go"&gt;2020-02-29    1&lt;/span&gt;
&lt;span class="go"&gt;2020-04-30    1&lt;/span&gt;
&lt;span class="go"&gt;2020-10-31    2&lt;/span&gt;
&lt;span class="go"&gt;Length: 540, dtype: int64&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notice the index in the resulting &lt;code&gt;Series&lt;/code&gt;. Each entry ends on the last day of the month. This is because we passed the &lt;code&gt;M&lt;/code&gt; (month) offset alias into the &lt;code&gt;.resample&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;I generally plot this by chaining on a call to &lt;code&gt;.plot&lt;/code&gt;. This will plot the date on the x-axis and draw the values on the y-axis.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bank&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;effective_date&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;M&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="Monthly bank failures over time" src="/static/img/blog/pandas-finance/failures-by-month.png"&gt;&lt;/p&gt;
&lt;h2&gt;Smoothing By Rougher Aggregations Using Pandas Resample&lt;/h2&gt;
&lt;p&gt;Let’s try something a little fancier. We will make a function that plots the monthly failures (which we already saw was bumpy) and then plot the yearly aggregation on top.&lt;/p&gt;
&lt;p&gt;I'll use the &lt;code&gt;.pipe&lt;/code&gt; method to refactor the plotting logic into a single function.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;matplotlib.pyplot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;plt&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subplots&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;plot_monthly_and_yearly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;M&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Monthly&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Y&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Annual&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;legend&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;

&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bank&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;effective_date&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plot_monthly_and_yearly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;        cert    charter_class   estimated_loss  fin id  institution             total_assets    total_deposits  resolution  transaction_type    insurance_fund  city            state&lt;/span&gt;
&lt;span class="go"&gt;effective_date                                                  &lt;/span&gt;
&lt;span class="go"&gt;2020-10-23  15426.0 NM      16806.0     10538   4104    ALMENA STATE BANK           65733.0     64941       FAILURE     PA          DIF     ALMENA          KS&lt;/span&gt;
&lt;span class="go"&gt;2020-10-16  16748.0 NM      7247.0      10537   4103    FIRST CITY BANK OF FLORIDA      136566.0    133936      FAILURE     PA          DIF     FORT WALTON BEACH   FL&lt;/span&gt;
&lt;span class="go"&gt;2020-04-03  14361.0 NM      45913.0     10536   4102    THE FIRST STATE BANK            151808.0    143102      FAILURE     PA          DIF     BARBOURSVILLE       WV&lt;/span&gt;
&lt;span class="go"&gt;2020-02-14  18265.0 NM      25293.0     10535   4101    ERICSON STATE BANK          100879.0    95159       FAILURE     PA          DIF     ERICSON         NE&lt;/span&gt;
&lt;span class="go"&gt;2019-11-01  21111.0 N       1946.0      10534   4100    CITY NATIONAL BANK OF NEW JERSEY    120574.0    111234      FAILURE     PA          DIF     NEWARK          NJ&lt;/span&gt;
&lt;span class="go"&gt;...     ... ...     ...     ... ... ...                 ...     ...     ...     ...         ...     ...         ...&lt;/span&gt;
&lt;span class="go"&gt;1934-08-06  NaN NM      NaN     0   137 BANK OF LEWISPORT           81.0        68      FAILURE     PO          BIF     LEWISPORT       KY&lt;/span&gt;
&lt;span class="go"&gt;1934-07-18  NaN N       NaN     0   135 FIRST NATIONAL BANK OF LIMA     91.0        42      FAILURE     PO          BIF     LIMA            MT&lt;/span&gt;
&lt;span class="go"&gt;1934-07-18  NaN NM      NaN     0   136 FLORENCE DEPOSIT BANK           105.0       69      FAILURE     PO          BIF     FLORENCE        IN&lt;/span&gt;
&lt;span class="go"&gt;1934-05-28  NaN NM      NaN     0   133 FON DU LAC STATE BANK           374.0       238     FAILURE     PO          BIF     EAST PEORIA     IL&lt;/span&gt;
&lt;span class="go"&gt;1934-04-19  NaN NM      NaN     0   134 BANK OF AMERICA TRUST CO.       1435.0      1064        FAILURE     PO          BIF     PITTSBURGH      PA&lt;/span&gt;
&lt;span class="go"&gt;4104 rows x 13 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="Monthly and annual bank failures plotted together" src="/static/img/blog/pandas-finance/monthly-and-annual-failures.png"&gt;&lt;/p&gt;
&lt;h2&gt;Resolution Type Over Time&lt;/h2&gt;
&lt;p&gt;I want to talk about one more feature of pandas: the &lt;code&gt;pd.Grouper&lt;/code&gt; class. I use this class to group by different frequencies of a date column without having to stick the date in the index and call &lt;code&gt;.resample&lt;/code&gt;. You might ask, why?&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;.resample&lt;/code&gt; method only allows us to have a single grouping. If you have played around with &lt;code&gt;.groupby&lt;/code&gt;, then you know that you can provide multiple columns or series to &lt;code&gt;.groupby&lt;/code&gt;. In this example, let's assume this word problem:&lt;/p&gt;
&lt;p&gt;What are the counts of the different resolution types by month?&lt;/p&gt;
&lt;p&gt;This is a little tricky. We have “by month,” so we want to group by month, but we also really have “size by resolution type by month.”&lt;/p&gt;
&lt;p&gt;A first stab might look like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bank&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;bank&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;effective_date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;resolution&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;effective_date  resolution&lt;/span&gt;
&lt;span class="go"&gt;1               ASSISTANCE     22&lt;/span&gt;
&lt;span class="go"&gt;                FAILURE       274&lt;/span&gt;
&lt;span class="go"&gt;2               ASSISTANCE     26&lt;/span&gt;
&lt;span class="go"&gt;                FAILURE       302&lt;/span&gt;
&lt;span class="go"&gt;3               ASSISTANCE     32&lt;/span&gt;
&lt;span class="go"&gt;                FAILURE       443&lt;/span&gt;
&lt;span class="go"&gt;4               ASSISTANCE     87&lt;/span&gt;
&lt;span class="go"&gt;                FAILURE       328&lt;/span&gt;
&lt;span class="go"&gt;5               ASSISTANCE     30&lt;/span&gt;
&lt;span class="go"&gt;                FAILURE       283&lt;/span&gt;
&lt;span class="go"&gt;6               ASSISTANCE     28&lt;/span&gt;
&lt;span class="go"&gt;                FAILURE       298&lt;/span&gt;
&lt;span class="go"&gt;7               ASSISTANCE     48&lt;/span&gt;
&lt;span class="go"&gt;                FAILURE       359&lt;/span&gt;
&lt;span class="go"&gt;8               ASSISTANCE     62&lt;/span&gt;
&lt;span class="go"&gt;                FAILURE       280&lt;/span&gt;
&lt;span class="go"&gt;9               ASSISTANCE     57&lt;/span&gt;
&lt;span class="go"&gt;                FAILURE       219&lt;/span&gt;
&lt;span class="go"&gt;10              ASSISTANCE     47&lt;/span&gt;
&lt;span class="go"&gt;                FAILURE       284&lt;/span&gt;
&lt;span class="go"&gt;11              ASSISTANCE     30&lt;/span&gt;
&lt;span class="go"&gt;                FAILURE       212&lt;/span&gt;
&lt;span class="go"&gt;12              ASSISTANCE    110&lt;/span&gt;
&lt;span class="go"&gt;                FAILURE       243&lt;/span&gt;
&lt;span class="go"&gt;dtype: int64&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This sort of works if we want to know how many banks failed in December. But we want monthly data over time. Because we also want to group by resolution, we can't use the &lt;code&gt;.resample&lt;/code&gt; method. This is where &lt;code&gt;pd.Grouper&lt;/code&gt; comes in.&lt;/p&gt;
&lt;p&gt;We provide the name of a datetime column and a frequency (this is that offset alias that we talked about above). The code looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bank&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grouper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;effective_date&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;freq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;M&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;           &lt;span class="s1"&gt;&amp;#39;resolution&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;effective_date  resolution&lt;/span&gt;
&lt;span class="go"&gt;1934-04-30      FAILURE       1&lt;/span&gt;
&lt;span class="go"&gt;1934-05-31      FAILURE       1&lt;/span&gt;
&lt;span class="go"&gt;1934-07-31      FAILURE       2&lt;/span&gt;
&lt;span class="go"&gt;1934-08-31      FAILURE       1&lt;/span&gt;
&lt;span class="go"&gt;1934-09-30      FAILURE       1&lt;/span&gt;
&lt;span class="go"&gt;                             ..&lt;/span&gt;
&lt;span class="go"&gt;2019-10-31      FAILURE       2&lt;/span&gt;
&lt;span class="go"&gt;2019-11-30      FAILURE       1&lt;/span&gt;
&lt;span class="go"&gt;2020-02-29      FAILURE       1&lt;/span&gt;
&lt;span class="go"&gt;2020-04-30      FAILURE       1&lt;/span&gt;
&lt;span class="go"&gt;2020-10-31      FAILURE       2&lt;/span&gt;
&lt;span class="go"&gt;Length: 635, dtype: int64&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;By now, you know that I want to plot this. However, tacking on &lt;code&gt;.plot&lt;/code&gt; is unsatisfying as we have a hierarchical index and this sticks both date and resolution as a tuple on the x-axis:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bank&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grouper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;effective_date&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;freq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;M&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
           &lt;span class="s1"&gt;&amp;#39;resolution&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="Unsatisfactory plot using a hierarchical index" src="/static/img/blog/pandas-finance/resolution-hierarchical-index.png"&gt;&lt;/p&gt;
&lt;p&gt;What I want to do instead is unstack the innermost index, the resolution index. The &lt;code&gt;.unstack&lt;/code&gt; method will pull out the inner index by default and stick it up into the columns. Now we have monthly dates in the index and a column for each resolution type.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bank&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grouper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;effective_date&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;freq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;M&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;           &lt;span class="s1"&gt;&amp;#39;resolution&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unstack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;        __reduced___ASSISTANCE  __reduced___FAILURE&lt;/span&gt;
&lt;span class="go"&gt;effective_date      &lt;/span&gt;
&lt;span class="go"&gt;1934-04-30  NaN         1&lt;/span&gt;
&lt;span class="go"&gt;1934-05-31  NaN         1&lt;/span&gt;
&lt;span class="go"&gt;1934-07-31  NaN         2&lt;/span&gt;
&lt;span class="go"&gt;1934-08-31  NaN         1&lt;/span&gt;
&lt;span class="go"&gt;1934-09-30  NaN         1&lt;/span&gt;
&lt;span class="go"&gt;...     ...         ...&lt;/span&gt;
&lt;span class="go"&gt;2019-10-31  NaN         2&lt;/span&gt;
&lt;span class="go"&gt;2019-11-30  NaN         1&lt;/span&gt;
&lt;span class="go"&gt;2020-02-29  NaN         1&lt;/span&gt;
&lt;span class="go"&gt;2020-04-30  NaN         1&lt;/span&gt;
&lt;span class="go"&gt;2020-10-31  NaN         2&lt;/span&gt;
&lt;span class="go"&gt;540 rows x 2 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If we plot this, we will get a line for each resolution type over time. It looks like the &lt;em&gt;FAILURE&lt;/em&gt; resolution is much more common since 1989.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;fix_cols&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;__reduced___&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bank&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grouper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;effective_date&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;freq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;M&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
           &lt;span class="s1"&gt;&amp;#39;resolution&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unstack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fillna&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fix_cols&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="Bank assistance and failure resolution types over time" src="/static/img/blog/pandas-finance/resolution-types-over-time.png"&gt;&lt;/p&gt;
&lt;p&gt;Let’s do a 12-month rolling average to smooth this out a bit.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bank&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grouper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;effective_date&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;freq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;M&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
           &lt;span class="s1"&gt;&amp;#39;resolution&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unstack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fix_cols&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fillna&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rolling&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="Twelve-month rolling average of resolution types" src="/static/img/blog/pandas-finance/resolution-rolling-average.png"&gt;&lt;/p&gt;
&lt;p&gt;Below I plot the yearly resolution size. Again, you can see that the basic shape is the same, but the yearly rolling average tells a better story.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bank&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grouper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;effective_date&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;freq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Y&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
           &lt;span class="s1"&gt;&amp;#39;resolution&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unstack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fix_cols&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fillna&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="Annual bank resolutions by type" src="/static/img/blog/pandas-finance/resolution-yearly.png"&gt;&lt;/p&gt;
&lt;p&gt;And finally, let’s look at the 12-month rolling average by resolution type.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bank&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grouper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;effective_date&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;freq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;M&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
           &lt;span class="s1"&gt;&amp;#39;transaction_type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unstack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fix_cols&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fillna&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rolling&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="Twelve-month rolling average by transaction type" src="/static/img/blog/pandas-finance/transaction-type-rolling-average.png"&gt;&lt;/p&gt;
&lt;h2&gt;Now You Have Pandas Resample, Groupby, and Rolling Superpowers&lt;/h2&gt;
&lt;p&gt;I hope that this blog post exposed you to the powerful time-series functionality in pandas, particularly &lt;code&gt;.resample&lt;/code&gt;, &lt;code&gt;.groupby&lt;/code&gt;, and &lt;code&gt;.rolling&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Folks often ask me why I use pandas to manipulate my data. Could I do this in SQL? Yes… probably. But I’ve written enough SQL in my life to know that it wouldn’t be fun for me.&lt;/p&gt;</content><category term="misc"/><category term="pandas"/><category term="finance"/><category term="time-series"/></entry><entry><title>I Wrote A Book</title><link href="https://www.metasnake.com/blog/xgboostauthor.html" rel="alternate"/><published>2023-03-27T00:00:00-06:00</published><updated>2023-03-27T00:00:00-06:00</updated><author><name>Matt Harrison</name></author><id>tag:www.metasnake.com,2023-03-27:/blog/xgboostauthor.html</id><summary type="html"/><content type="html">&lt;p&gt;&lt;strong&gt;TLDR&lt;/strong&gt; - I made over $25,000 in the two-day launch of my new self-published book, &lt;a href="https://store.metasnake.com/xgboost"&gt;Effective XGBoost&lt;/a&gt;. I discuss how that happened and if writing a book is worth the time and effort.&lt;/p&gt;
&lt;figure class='border'&gt;
&lt;img src='/static/img/xgb.png' class='img-fluid' alt='bunch of books'/&gt;
&lt;figcaption&gt;My new Effective XGBoost book walks through end-to-end classification from model creation to tuning to interpretation, to deployment.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2&gt;Why Write a Book?&lt;/h2&gt;
&lt;p&gt;Every potential author has to answer this for themself. I have written and worked as a technical editor for many books (Illustrated Guide to Python 3, Intermediate Python, Effective Pandas, Machine Learning Pocket Reference, Learning the Pandas Library, Pandas 1.x Cookbook, Tiny Python Notebook (3.5-3.10), Effective Pycharm, Hands-on Machine Learning with Scikit-Learn, Keras &amp;amp; Tensorflow, Hands-on Unsupervised Learning Using Python, and maybe a few others), so I'm aware of what is involved in bringing a book from an idea to something you can hold in your hand. I also know and &lt;a href="https://store.metasnake.com/effective-authoring"&gt;have interviewed over a dozen technical authors&lt;/a&gt; and know many other Python and data science authors. The general advice that you would make more per hour consulting is true. &lt;/p&gt;
&lt;figure class='border'&gt;
&lt;img src='/static/img/books.jpg' class='img-fluid' alt='bunch of books'/&gt;
&lt;figcaption&gt;Some of the books I have written.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Many folks write because they have the bug. Others write for credibility. Others want a book with an animal on the cover. Since transitioning from development into mostly corporate training and consulting, authoring has been great marketing for me.&lt;/p&gt;
&lt;p&gt;With self-publishing being relatively easy these days, the sole gatekeeper to writing a book is yourself. Be aware, book creation is a marathon. Don't jump in thinking it is a sprint.&lt;/p&gt;
&lt;h2&gt;You Made More in Two Days Then I Make in...&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://store.metasnake.com/xgboost"&gt;Effective XGBoost&lt;/a&gt; has been my best launch to date. After two days I had over $25,000 in sales. Perhaps this feels like bragging or an overnight success. But I've been writing books since 2011 and finally feel like I'm starting to crack the nut (or at least listen to common advice like setting up a mailing list).&lt;/p&gt;
&lt;p&gt;At this point, I have a few thousand on my mailing list, 140k followers on &lt;a href="https://www.twitter.com/__mharrison__"&gt;Twitter&lt;/a&gt;, and around 20k connections on &lt;a href="https://www.linkedin.com/in/panela/"&gt;LinkedIn&lt;/a&gt;. I've fully succumbed to the reality that I must do the marketing myself, and I've worked pretty hard (particularly on the Twitter side) to grow my audience.&lt;/p&gt;
&lt;p&gt;Also, note that I've been working on this book since the summer of 2022. Cranking out a quality book is hard work and takes a lot of time. Creating video courses is much easier and less time-consuming for me. Due to the nature of my work, I was often able to spend entire days working on the book. That was not the case when I had fulltime employment and wrote my first books. Many days I woke up early to crank out content. My back-of-the-napkin calculation is that I spent 10 hours a week over 25 weeks writing this book. That comes out to about $100/hour. &lt;/p&gt;
&lt;p&gt;If you are now itching to write a book, note that my consulting fees are slightly higher than $100 per hour. Plus, I've authored multiple books, and this book performed much better than previous launches. For comparison, &lt;em&gt;Effective Pandas&lt;/em&gt;, only did around $8,000 on its release.&lt;/p&gt;
&lt;h2&gt;Audience&lt;/h2&gt;
&lt;p&gt;Since the dawn of self-publishing, authors have touted the importance of a mailing list. I didn't have an email list when I created my first books. Bad choice, Matt! &lt;/p&gt;
&lt;p&gt;I used the Gumroad platform initially, and while the features were great for sales, that was about the end of the features. Eventually, I moved on to Podia, which includes mailing list functionality. Honestly, my mailing list-fu is lacking, but I'm continually looking to improve. I might create a Substack, but as a one-man shop, I like to keep things simple and limit platforms. The draw of Podia is that it is all in one. &lt;/p&gt;
&lt;figure class='border'&gt;
&lt;img src='/static/img/xgbsales.png' class='img-fluid' alt='bunch of books'/&gt;
&lt;figcaption&gt;Launch sales.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I have a few thousand subscribers on my mailing list right now, and they accounted for 35% of my sales.&lt;/p&gt;
&lt;p&gt;My next largest source of sales was from Twitter. (If you are wondering how I tracked this, I used Podia coupons with platform-specific codes.) I doubled down on Twitter during Covid and now have 140K followers. They accounted for around 32% of my sales. With all of the hijinks Elon has been pulling recently, having all my "eggs" in the Twitter basket is scary.&lt;/p&gt;
&lt;p&gt;LinkedIn came in around 11%, but I only have 20K followers there. I'm actively working on growing that audience. Just another thing to put in the to-do list...&lt;/p&gt;
&lt;p&gt;Around 15% of my sales aren't attributable or are from folks who didn't use a coupon. Many of my followers pay full price to support creators like me. I'm grateful to those "super fans". Some of these folks might not have figured out how to enter the coupon code at checkout. Podia can be tricky like that sometimes.&lt;/p&gt;
&lt;p&gt;Around 5% of the sales during this time were upsells. So these weren't sales of Effective XGBoost but in-cart discounts to my &lt;em&gt;Effective Pandas&lt;/em&gt; material. Podia can be tricky like that sometimes.&lt;/p&gt;
&lt;p&gt;You'll note that I haven't mentioned the elephant in the book sales business ... Amazon.&lt;/p&gt;
&lt;h2&gt;Physical Books&lt;/h2&gt;
&lt;p&gt;My initial release was only for a digital book with an option for a course and consulting. I highly recommend creating an accompanying course for your book. Around 70% of my sales included the course. Here's the math. 100 books at $50 = $5,000. Contrast that with having a course, offering 70 courses at $100 and 30 books = $7,000 + $1,500 = $8,500.&lt;/p&gt;
&lt;p&gt;Oh yeah, Amazon. Amazon accounts for a large number of sales. However, they also take a large cut. And they don't give me access to my readers.&lt;/p&gt;
&lt;p&gt;The compromise I have settled on is letting Amazon (and other long-tail providers) handle the physical book. Many prefer to read from a physical book, and Amazon does a great job pushing your book for you, especially if you can get that fly-wheel moving. However, I feed my family with my book sales and would prefer not to have a middleman for my audience's digital sales.&lt;/p&gt;
&lt;p&gt;I created both a paperback and hardback book (&lt;a href="https://amzn.to/3TRBF00"&gt;Amazon now offers these&lt;/a&gt;) and announced to my mailing list that these books were available without disclosing them to the rest of the world. I also deeply discounted it (to the point where I'm making $1/sale) as a bonus for my mailing list and a way to say "thanks" to my audience. &lt;/p&gt;
&lt;figure class='border'&gt;
&lt;img src='/static/img/xgbamz.png' class='img-fluid' alt='bunch of books'/&gt;
&lt;figcaption&gt;Amazon ranking after launch to mailing list.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;This (hopefully) kicks in the Amazon machine, as my mailing list pushed the book to the top of the lists and a rank of around 3,000 overall on Amazon.&lt;/p&gt;
&lt;p&gt;As of this post, I've bumped the price back up to normal. Amazon can take the cut of sales they bring in, but I will push my digital version and let readers know about the Amazon option if they prefer physical books.&lt;/p&gt;
&lt;p&gt;Based on the performance of &lt;em&gt;Effective Pandas&lt;/em&gt; (which has done well on Amazon), the Amazon machine can get close to Podia in terms of ongoing revenue.&lt;/p&gt;
&lt;p&gt;Note that I'm doing a full-color book on Amazon. These are expensive to print. I could probably double my Amazon income if I keep the same price but sold only a grayscale interior. However, my book has dozens of charts and accompanying code, and the color print on this batch of &lt;em&gt;Effective XGBoost&lt;/em&gt; has been excellent. (I'm thinking that Amazon upgraded the POD printers, or I've been really lucky.)&lt;/p&gt;
&lt;h2&gt;Traditional Publishing?&lt;/h2&gt;
&lt;p&gt;What about traditional publishing? Are my readers getting an inferior product? My content is not prefect. I make tpyos, like the rest of the world. But editors are also not perfect and also miss typos as well. 😉&lt;/p&gt;
&lt;p&gt;I feel like my process is decent, and having been through the process of two other publishers, I feel confident about the final outcome. I can "execute" my books via doctests or notebooks, so I know the code works. Grammarly helps with most typos these days.&lt;/p&gt;
&lt;p&gt;I recruit dozens of volunteers from my mailing list review the drafts of the book. This turns out a quality product based on feedback and experience.&lt;/p&gt;
&lt;p&gt;What about the other stuff? Layout, cover design, marketing? Yep, that is work. Consider using a publisher if you can't figure out how to do it professionally.&lt;/p&gt;
&lt;p&gt;What about distribution? A publisher does provide more distribution than just Amazon. However, Amazon is the elephant here. And I've found that after any initial promotion, the onus is solely on me to promote my book. I use Ingram Spark to reach the long tail, but the squeeze is a lot of effort for the juice when I could be doing other things.&lt;/p&gt;
&lt;h2&gt;AI and the Death of Books&lt;/h2&gt;
&lt;p&gt;When I was about 90% done with the book, ChatGPT was released. As a technologist, I jumped on this boat and was really happy using it to augment where possible. As a one-man shop, Chat (as I like to call it) is a game-changer.&lt;/p&gt;
&lt;p&gt;I won't go deep into how I used Chat here (perhaps in a different post). I will say, Chat's hallucinations are something to be aware of. Did I use Chat content in the book? Yes, however, I edited everything that Chat created. &lt;/p&gt;
&lt;p&gt;Will I use Chat in future content creation? Yes.&lt;/p&gt;
&lt;p&gt;Do I think Chat means the end of books? No. I don't feel like Chat can completely automate book creation now. I also think there is some creative direction that Chat can't create on its own.&lt;/p&gt;
&lt;p&gt;Does that mean that books won't be written by Chat? No. They already are. This isn't particularly disturbing to me because I've seen folks creating garbage books since Amazon opened the floodgates of self-publishing. You can even pick out these scam books on the charts. Shady folks sell shady stuff to make a buck and then use bots to help game the system. Alas, this is the world we live in. I feel like my audience trusts me to provide a quality product, and &lt;a href="https://store.metasnake.com/effective-pandas-book"&gt;the reviews confirm that&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Will Writing A Book Help You?&lt;/h2&gt;
&lt;p&gt;Thanks for getting this far. &lt;/p&gt;
&lt;p&gt;Should you write a book? I get this question a lot. &lt;/p&gt;
&lt;p&gt;As a corporate trainer, getting a foot in the door is much easier if you have "written the book on the subject". I know a lot of trainers, and many of them have written books... I wonder why that is? 😉&lt;/p&gt;
&lt;p&gt;For more software or data-type folks, should you write a book? Again, if you want to be able to show expertise, this is one (albeit a long one) road to accomplish that task. Having a portfolio project and being able to discuss it in detail would probably accomplish the same for most folks but take much less time.&lt;/p&gt;
&lt;p&gt;If you have a large platform or means to promote the book, it can be profitable. Note that this is a long tail game, and the news that you read about is typically the winners with outlier results.&lt;/p&gt;
&lt;p&gt;Many just have a "book inside of them" that needs to get out. Just realize that getting it out is a marathon and like most things tech, will probably take two to three times as long as you think it will.&lt;/p&gt;
&lt;p&gt;Let me know if you have any questions. I'm at &lt;a href="https://www.twitter.com/__mharrison__"&gt;@__mharrison__.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(Chat did not write this post.)&lt;/p&gt;</content><category term="misc"/><category term="bookauthor"/></entry><entry><title>Professional Pandas: Indexing with Pandas Loc</title><link href="https://www.metasnake.com/blog/professional-pandas-indexing-pandas-loc.html" rel="alternate"/><published>2023-01-13T00:00:00-07:00</published><updated>2026-08-12T00:00:00-06:00</updated><author><name>Matt Harrison</name></author><id>tag:www.metasnake.com,2023-01-13:/blog/professional-pandas-indexing-pandas-loc.html</id><summary type="html">&lt;p&gt;Master pandas loc indexing with scalars, lists, slices, Boolean arrays, indexes, functions, and a practical crime-data example.&lt;/p&gt;</summary><content type="html">&lt;div class="article-note"&gt;
&lt;strong&gt;Republication note:&lt;/strong&gt; I originally wrote this article for Ponder, where it was published on January 13, 2023. Ponder later removed the post following its acquisition, so I have preserved it here. The Ponder- and Modin-specific code reflects the environment available when the article was written; the pandas concepts remain broadly applicable. &lt;a href="https://web.archive.org/web/20230613201128/https://ponder.io/professional-pandas-indexing-with-pandas-loc/"&gt;View the archived original.&lt;/a&gt;
&lt;/div&gt;

&lt;figure class="article-figure article-figure--hero"&gt;
&lt;img src="/static/img/blog/pandas-loc/hero.png" width="1000" height="800" alt="Highlighted rows and columns illustrating dataframe selection" decoding="async"&gt;
&lt;figcaption&gt;Selecting dataframe rows and columns precisely with &lt;code&gt;.loc&lt;/code&gt;.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2&gt;Introduction to Pandas Loc&lt;/h2&gt;
&lt;p&gt;In this post, I describe how Pandas loc (.loc) can be used for advanced indexing. We start by reviewing basic indexing and slicing in Pandas. We then dive into .loc, and explore how this indexing attribute can be used to select and filter data in your DataFrames. Along the way, I provide simple and complex examples to help you understand how Pandas loc works, and discuss common gotchas to watch out for. By the end, you'll have a solid understanding of how to use Pandas loc to access data. I will cover Pandas iloc (.iloc) in a future article.&lt;/p&gt;
&lt;p&gt;This is the third piece in our Professional Pandas series on teaching best practices about writing professional-grade Pandas code. If you have questions or topics that you would like to dive into, please reach out on Twitter to &lt;a href="https://twitter.com/intent/follow?screen_name=ponderdata"&gt;@ponderdata&lt;/a&gt; or &lt;a href="https://twitter.com/__mharrison__"&gt;@__mharrison__&lt;/a&gt;, and if you’d like to see the notebook version of this blogpost, you can find it on Github &lt;a href="https://github.com/ponder-org/professional-pandas/blob/main/LocBlogPost.ipynb"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;The Data for Our Examples&lt;/h2&gt;
&lt;p&gt;For our examples, we will use &lt;a href="https://catalog.data.gov/dataset/crime-data-from-2020-to-present"&gt;Los Angeles crime data&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;See below for descriptions of the relevant columns, taken directly from the data producer’s &lt;a href="https://data.lacity.org/Public-Safety/Crime-Data-from-2020-to-Present/2nrs-mtv8"&gt;data dictionary&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;DR_NO (Plain Text) Division of Records Number: Official file number made up of a 2 digit year, area ID, and 5 digits&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Date Rptd (Date &amp;amp; Time) - MM/DD/YYYY&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DATE OCC (Date &amp;amp; Time) - MM/DD/YYYY&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;TIME OCC (Plain Text) - In 24 hour military time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;AREA NAME (Plain Text) - The 21 Geographic Areas or Patrol Divisions are also given a name designation that references a landmark or the surrounding community that it is responsible for. For example 77th Street Division is located at the intersection of South Broadway and 77th Street, serving neighborhoods in South Los Angeles.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Crm Cd (Plain Text) - Indicates the crime committed. (Same as Crime Code 1)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Crm Cd Desc (Plain Text) - Defines the Crime Code provided.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mocodes (Plain Text) - Modus Operandi: Activities associated with the suspect in commission of the crime. See attached PDF for the list of MO Codes in numerical order.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Vict Age (Plain Text) - Two character numeric&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Vict Sex (Plain Text) - F - Female M - Male X - Unknown&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Vict Descent (Plain Text) - Descent Code: A - Other Asian B - Black C - Chinese D - Cambodian F - Filipino G - Guamanian H - Hispanic/Latin/Mexican I - American Indian/Alaskan Native J - Japanese K - Korean L - Laotian O - Other P - Pacific Islander S - Samoan U - Hawaiian V - Vietnamese W - White X - Unknown Z - Asian Indian&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Premis Cd (Number) - The type of structure, vehicle, or location where the crime took place.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Premis Desc (Plain Text) - Defines the Premise Code provided.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Weapon Used Cd (Plain Text) - The type of weapon used in the crime.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Weapon Desc (Plain Text) - Defines the Weapon Used Code provided.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Status (Plain Text) - Status of the case. (IC is the default)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Status Desc (Plain Text) - Defines the Status Code provided.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Crm Cd 1 (Plain Text) - Indicates the crime committed. Crime Code 1 is the primary and most serious one. Crime Code 2, 3, and 4 are respectively less serious offenses. Lower crime class numbers are more serious.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;LOCATION (Plain Text) - Street address of crime incident rounded to the nearest hundred block to maintain anonymity.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Cross Street (Plain Text) - Cross Street of rounded Address&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;LAT (Number) - Latitude&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;LON (Number) - Longtitude&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s load the data.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pandas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pd&lt;/span&gt;
&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;https://data.lacity.org/api/views/2nrs-mtv8/rows.csv?accessType=DOWNLOAD&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;The Basics on Indexing and Slicing with Pandas&lt;/h2&gt;
&lt;p&gt;Before we dive into .loc, it's important to review some basic indexing and slicing in Pandas. In Pandas, a DataFrame is a two-dimensional size-mutable tabular data structure with rows and columns. You can think of it like a spreadsheet or an Excel sheet.&lt;/p&gt;
&lt;p&gt;To access a specific column in a DataFrame, you can use square brackets (e.g. df[col]). This is called index access and will return a series in Pandas. Let's get the Crime Description column.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Crm Cd Desc&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="go"&gt;0   BATTERY - SIMPLE ASSAULT&lt;/span&gt;
&lt;span class="go"&gt;1   BATTERY - SIMPLE ASSAULT&lt;/span&gt;
&lt;span class="go"&gt;2   SEX OFFENDER REGISTRANT OUT OF COMPLIANCE&lt;/span&gt;
&lt;span class="go"&gt;3   VANDALISM - MISDEAMEANOR ($399 OR UNDER)&lt;/span&gt;
&lt;span class="go"&gt;4   VANDALISM - FELONY ($400 &amp;amp; OVER, ALL CHURCH VA...&lt;/span&gt;
&lt;span class="go"&gt;    ...&lt;/span&gt;
&lt;span class="go"&gt;632385  THEFT OF IDENTITY&lt;/span&gt;
&lt;span class="go"&gt;632386  THEFT FROM MOTOR VEHICLE - GRAND ($950.01 AND ...&lt;/span&gt;
&lt;span class="go"&gt;632387  VEHICLE - STOLEN&lt;/span&gt;
&lt;span class="go"&gt;632388  VEHICLE - STOLEN&lt;/span&gt;
&lt;span class="go"&gt;632389  THEFT FROM MOTOR VEHICLE - GRAND ($950.01 AND ...&lt;/span&gt;
&lt;span class="go"&gt;Name: Crm Cd Desc, Length: 632390, dtype: object&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note that we can also access a single column by &lt;em&gt;attribute&lt;/em&gt; access IF the column has a valid Python attribute name. Meaning that the column must start with an alphabetic character or underscore and the rest of the name must be alphanumerics or underscores. Because &lt;em&gt;Crm Cd Desc&lt;/em&gt; has spaces, we will get an error when we try to access it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Crm&lt;/span&gt; &lt;span class="n"&gt;Cd&lt;/span&gt; &lt;span class="n"&gt;Desc&lt;/span&gt;
&lt;span class="go"&gt;  File &amp;quot;&amp;quot;, line 1&lt;/span&gt;
&lt;span class="go"&gt;    df.Crm Cd Desc&lt;/span&gt;
&lt;span class="go"&gt;           ^&lt;/span&gt;
&lt;span class="go"&gt;SyntaxError: invalid syntax&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;However, we can access the &lt;em&gt;AREA&lt;/em&gt; column this way:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AREA&lt;/span&gt;
&lt;span class="go"&gt;0          3&lt;/span&gt;
&lt;span class="go"&gt;1          1&lt;/span&gt;
&lt;span class="go"&gt;2          1&lt;/span&gt;
&lt;span class="go"&gt;3         15&lt;/span&gt;
&lt;span class="go"&gt;4         19&lt;/span&gt;
&lt;span class="go"&gt;          ..&lt;/span&gt;
&lt;span class="go"&gt;632385     3&lt;/span&gt;
&lt;span class="go"&gt;632386    10&lt;/span&gt;
&lt;span class="go"&gt;632387    10&lt;/span&gt;
&lt;span class="go"&gt;632388    11&lt;/span&gt;
&lt;span class="go"&gt;632389    16&lt;/span&gt;
&lt;span class="go"&gt;Name: AREA, Length: 632390, dtype: int64&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note that I generally try to have attribute-friendly column names or update them if they are not. Most code editing environments for Python have better completion on attribute access, and for that reason I tend to use it.&lt;/p&gt;
&lt;p&gt;We can also pull out multiple columns if we pass in a list of column names instead of a scalar. This returns a dataframe.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DATE OCC&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;AREA&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Vict Age&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="go"&gt;        DATE OCC                  AREA    Vict Age&lt;/span&gt;
&lt;span class="go"&gt;0       01/08/2020 12:00:00 AM    3       36&lt;/span&gt;
&lt;span class="go"&gt;1       01/01/2020 12:00:00 AM    1       25&lt;/span&gt;
&lt;span class="go"&gt;2       02/13/2020 12:00:00 AM    1       0&lt;/span&gt;
&lt;span class="go"&gt;3       01/01/2020 12:00:00 AM    15      76&lt;/span&gt;
&lt;span class="go"&gt;4       01/01/2020 12:00:00 AM    19      31&lt;/span&gt;
&lt;span class="go"&gt;...     ...                       ...     ...&lt;/span&gt;
&lt;span class="go"&gt;632385  08/02/2022 12:00:00 AM    3       34&lt;/span&gt;
&lt;span class="go"&gt;632386  12/01/2022 12:00:00 AM    10      68&lt;/span&gt;
&lt;span class="go"&gt;632387  02/09/2022 12:00:00 AM    10      0&lt;/span&gt;
&lt;span class="go"&gt;632388  02/08/2022 12:00:00 AM    11      0&lt;/span&gt;
&lt;span class="go"&gt;632389  02/14/2022 12:00:00 AM    16      61&lt;/span&gt;
&lt;span class="go"&gt;632390 rows × 3 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;What Is Pandas Loc, and What Inputs Does it Accept?&lt;/h2&gt;
&lt;p&gt;Pulling out a subset of columns is fine, but you might also want a subset of rows. Neither index access nor attribute access will give you that. However, the focus of this article, Pandas loc (and .iloc in future articles), allows you to pull out columns and rows.&lt;/p&gt;
&lt;p&gt;Here is the key thing to remember about Pandas loc, and if you remember anything from this article, remember this: .loc allows you to pull out rows and columns by label name.&lt;/p&gt;
&lt;p&gt;What even is .loc? It is a property. A property could be a post of its own, but in short, it allows you to call a method without parameters (or parentheses). When you say df.loc, pandas is actually running the .loc method and returning the result of it (which is a _LocIndexer).&lt;/p&gt;
&lt;p&gt;How do I know all of this? Well, I looked at the source code for Pandas. (This is really easy in Jupyter, just type &lt;code&gt;df.loc??&lt;/code&gt; and run the code. Jupyter will pull up the source code when you put &lt;code&gt;??&lt;/code&gt; after your code.)&lt;/p&gt;
&lt;p&gt;It being a property is not particularly interesting. Perhaps the more interesting part is the docstring which describes how you can index off of the property.&lt;/p&gt;
&lt;h3&gt;What the Loc Documentation Says About Allowed Inputs&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Allowed inputs are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A single label, e.g. 5 or 'a', (note that 5 is interpreted as a label of the index, and never as an integer position along the index).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A list or array of labels, e.g. ['a', 'b', 'c'].&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A slice object with labels, e.g. 'a':'f'.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;warning:: Note that contrary to usual python slices, &lt;/em&gt;&lt;em&gt;both&lt;/em&gt;&lt;em&gt; the start and the stop are included&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A boolean array of the same length as the axis being sliced, e.g. [True, False, True].&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;An alignable boolean Series. The index of the key will be aligned before masking.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;An alignable Index. The Index of the returned selection will be the input.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A callable function with one argument (the calling Series or DataFrame) and that returns valid output for indexing (one of the above)
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;One more thing to be aware of that the docs don’t make clear. (This is also confusing because this is completely different from how indexing normally occurs in Python.) The inputs to the index include both a &lt;em&gt;row indexer&lt;/em&gt; and an optional &lt;em&gt;column indexer&lt;/em&gt;. You separate these by a comma. Keep that in mind through the following examples.&lt;/p&gt;
&lt;h2&gt;How to Use Pandas Loc with Each Input Type&lt;/h2&gt;
&lt;p&gt;Now I will walk you through how to use Pandas loc with each of the above input types, and will turn to the crime data as real-world example data. Note that this data has the default index, the RangeIndex, which is a monotonic increasing integer value.&lt;/p&gt;
&lt;h3&gt;Part 1: Using Pandas Loc to Index with Scalars&lt;/h3&gt;
&lt;p&gt;In this case, we will select the row with label 5. (Note that I highlighted label, because remember Pandas loc indexes by label and not by index! Even though in this example the index labels also happen to be the same as the index position.) The integer 5 inside the square brackets is used to select the row with label 5 in the DataFrame.&lt;/p&gt;
&lt;p&gt;The syntax for indexing with .loc is df.loc[row_indexer, column_indexer]. In this case, row_indexer is the label 5, and column_indexer is not specified, so all columns are selected.&lt;/p&gt;
&lt;p&gt;Here is the code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="go"&gt;DR_NO       200100501&lt;/span&gt;
&lt;span class="go"&gt;Date Rptd   01/02/2020 12:00:00 AM&lt;/span&gt;
&lt;span class="go"&gt;DATE OCC    01/01/2020 12:00:00 AM&lt;/span&gt;
&lt;span class="go"&gt;TIME OCC    30&lt;/span&gt;
&lt;span class="go"&gt;AREA        1&lt;/span&gt;
&lt;span class="go"&gt;AREA NAME   Central&lt;/span&gt;
&lt;span class="go"&gt;Rpt Dist No 163&lt;/span&gt;
&lt;span class="go"&gt;Part 1-2    1&lt;/span&gt;
&lt;span class="go"&gt;Crm Cd      121&lt;/span&gt;
&lt;span class="go"&gt;Crm Cd Desc RAPE, FORCIBLE&lt;/span&gt;
&lt;span class="go"&gt;Mocodes     0413 1822 1262 1415&lt;/span&gt;
&lt;span class="go"&gt;Vict Age    25&lt;/span&gt;
&lt;span class="go"&gt;Vict Sex    F&lt;/span&gt;
&lt;span class="go"&gt;Vict Descent    H&lt;/span&gt;
&lt;span class="go"&gt;Premis Cd   735.0&lt;/span&gt;
&lt;span class="go"&gt;Premis Desc NIGHT CLUB (OPEN EVENINGS ONLY)&lt;/span&gt;
&lt;span class="go"&gt;Weapon Used Cd  500.0&lt;/span&gt;
&lt;span class="go"&gt;Weapon Desc UNKNOWN WEAPON/OTHER WEAPON&lt;/span&gt;
&lt;span class="go"&gt;Status      IC&lt;/span&gt;
&lt;span class="go"&gt;Status Desc Invest Cont&lt;/span&gt;
&lt;span class="go"&gt;Crm Cd 1    121.0&lt;/span&gt;
&lt;span class="go"&gt;Crm Cd 2    998.0&lt;/span&gt;
&lt;span class="go"&gt;Crm Cd 3    NaN&lt;/span&gt;
&lt;span class="go"&gt;Crm Cd 4    NaN&lt;/span&gt;
&lt;span class="go"&gt;LOCATION    700 S  BROADWAY&lt;/span&gt;
&lt;span class="go"&gt;Cross Street    NaN&lt;/span&gt;
&lt;span class="go"&gt;LAT     34.0452&lt;/span&gt;
&lt;span class="go"&gt;LON     -118.2534&lt;/span&gt;
&lt;span class="go"&gt;Name: 5, dtype: object&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This might not look like a row. However, because we asked for a single index value, it gave us a row and used a Series to represent it.&lt;/p&gt;
&lt;p&gt;One thing to be aware of is that if the row with label 5 does not exist in the DataFrame, this code will raise a KeyError. In this example, we try to pull out a row with the non-existent label of Crm Cd 1.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Crm Cd 1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="go"&gt;---------------------------------------------------------------------------&lt;/span&gt;
&lt;span class="go"&gt;KeyError                                  Traceback (most recent call last)&lt;/span&gt;
&lt;span class="go"&gt; in&lt;/span&gt;
&lt;span class="go"&gt;----&amp;gt; 1 df.loc[&amp;#39;Crm Cd 1&amp;#39;]&lt;/span&gt;
&lt;span class="go"&gt;/usr/local/lib/python3.8/dist-packages/pandas/core/indexing.py in __getitem__(self, key)&lt;/span&gt;
&lt;span class="go"&gt;    929&lt;/span&gt;
&lt;span class="go"&gt;    930             maybe_callable = com.apply_if_callable(key, self.obj)&lt;/span&gt;
&lt;span class="go"&gt;--&amp;gt; 931             return self._getitem_axis(maybe_callable, axis=axis)&lt;/span&gt;
&lt;span class="go"&gt;    932&lt;/span&gt;
&lt;span class="go"&gt;    933     def _is_scalar_access(self, key: tuple):&lt;/span&gt;
&lt;span class="go"&gt;/usr/local/lib/python3.8/dist-packages/pandas/core/indexing.py in _getitem_axis(self, key, axis)&lt;/span&gt;
&lt;span class="go"&gt;   1162         # fall thru to straight lookup&lt;/span&gt;
&lt;span class="go"&gt;   1163         self._validate_key(key, axis)&lt;/span&gt;
&lt;span class="go"&gt;-&amp;gt; 1164         return self._get_label(key, axis=axis)&lt;/span&gt;
&lt;span class="go"&gt;   1165&lt;/span&gt;
&lt;span class="go"&gt;   1166     def _get_slice_axis(self, slice_obj: slice, axis: int):&lt;/span&gt;
&lt;span class="go"&gt;/usr/local/lib/python3.8/dist-packages/pandas/core/indexing.py in _get_label(self, label, axis)&lt;/span&gt;
&lt;span class="go"&gt;   1111     def _get_label(self, label, axis: int):&lt;/span&gt;
&lt;span class="go"&gt;   1112         # GH#5667 this will fail if the label is not present in the axis.&lt;/span&gt;
&lt;span class="go"&gt;-&amp;gt; 1113         return self.obj.xs(label, axis=axis)&lt;/span&gt;
&lt;span class="go"&gt;   1114&lt;/span&gt;
&lt;span class="go"&gt;   1115     def _handle_lowerdim_multi_index_axis0(self, tup: tuple):&lt;/span&gt;
&lt;span class="go"&gt;/usr/local/lib/python3.8/dist-packages/pandas/core/generic.py in xs(self, key, axis, level, drop_level)&lt;/span&gt;
&lt;span class="go"&gt;   3774                 raise TypeError(f&amp;quot;Expected label or tuple of labels, got {key}&amp;quot;) from e&lt;/span&gt;
&lt;span class="go"&gt;   3775         else:&lt;/span&gt;
&lt;span class="go"&gt;-&amp;gt; 3776             loc = index.get_loc(key)&lt;/span&gt;
&lt;span class="go"&gt;   3777&lt;/span&gt;
&lt;span class="go"&gt;   3778             if isinstance(loc, np.ndarray):&lt;/span&gt;
&lt;span class="go"&gt;/usr/local/lib/python3.8/dist-packages/pandas/core/indexes/range.py in get_loc(self, key, method, tolerance)&lt;/span&gt;
&lt;span class="go"&gt;    386                 except ValueError as err:&lt;/span&gt;
&lt;span class="go"&gt;    387                     raise KeyError(key) from err&lt;/span&gt;
&lt;span class="go"&gt;--&amp;gt; 388             raise KeyError(key)&lt;/span&gt;
&lt;span class="go"&gt;    389         return super().get_loc(key, method=method, tolerance=tolerance)&lt;/span&gt;
&lt;span class="go"&gt;    390&lt;/span&gt;
&lt;span class="go"&gt;KeyError: &amp;#39;Crm Cd 1&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the next example we will select a single column. In this case, row_indexer is a slice with a start and end index of :, which selects all rows, and column_indexer is the label ‘Crm Cd 1’, which selects the column with that label.&lt;/p&gt;
&lt;p&gt;Here is the full code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Crm Cd 1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="go"&gt;0         624.0&lt;/span&gt;
&lt;span class="go"&gt;1         624.0&lt;/span&gt;
&lt;span class="go"&gt;2         845.0&lt;/span&gt;
&lt;span class="go"&gt;3         745.0&lt;/span&gt;
&lt;span class="go"&gt;4         740.0&lt;/span&gt;
&lt;span class="go"&gt;          ...&lt;/span&gt;
&lt;span class="go"&gt;632385    354.0&lt;/span&gt;
&lt;span class="go"&gt;632386    331.0&lt;/span&gt;
&lt;span class="go"&gt;632387    510.0&lt;/span&gt;
&lt;span class="go"&gt;632388    510.0&lt;/span&gt;
&lt;span class="go"&gt;632389    331.0&lt;/span&gt;
&lt;span class="go"&gt;Name: Crm Cd 1, Length: 632390, dtype: float64&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notice that the row selector for the example was a single colon, :. This syntax might seem weird, but it is actually a slice. You could rewrite this slice as 0:len(df), indicating to take all of rows.&lt;/p&gt;
&lt;h3&gt;Part 2: Using Pandas Loc to Index with Lists&lt;/h3&gt;
&lt;p&gt;In our next example, the row_indexer is a list of labels [0,1,2], which selects the rows with those labels, and column_indexer is not specified, so all columns are selected.&lt;/p&gt;
&lt;p&gt;Here is the full code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="go"&gt;    DR_NO       Date Rptd       DATE OCC        TIME OCC    AREA    AREA NAME   Rpt Dist No Part 1-2    Crm Cd  Crm Cd Desc                 ... Status  Status Desc Crm Cd 1    Crm Cd 2    Crm Cd 3    Crm Cd 4    LOCATION    Cross Street    LAT     LON&lt;/span&gt;
&lt;span class="go"&gt;0   10304468    01/08/2020 12:00:00 AM  01/08/2020 12:00:00 AM  2230        3   Southwest   377     2       624 BATTERY - SIMPLE ASSAULT            ... AO  Adult Other 624.0       NaN     NaN     NaN     1100 W 39TH PL  NaN     34.0141     -118.2978&lt;/span&gt;
&lt;span class="go"&gt;1   190101086   01/02/2020 12:00:00 AM  01/01/2020 12:00:00 AM  330     1   Central     163     2       624 BATTERY - SIMPLE ASSAULT            ... IC  Invest Cont 624.0       NaN     NaN     NaN     700 S HILL ST   NaN     34.0459     -118.2545&lt;/span&gt;
&lt;span class="go"&gt;2   200110444   04/14/2020 12:00:00 AM  02/13/2020 12:00:00 AM  1200        1   Central     155     2       845 SEX OFFENDER REGISTRANT OUT OF COMPLIANCE   ... AA  Adult Arrest    845.0       NaN     NaN     NaN     200 E 6TH ST    NaN     34.0448     -118.2474&lt;/span&gt;
&lt;span class="go"&gt;3 rows × 28 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this next example, we will return all of the rows and two columns, &lt;em&gt;AREA&lt;/em&gt; and &lt;em&gt;TIME OCC&lt;/em&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;AREA&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TIME OCC&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="go"&gt;    AREA    TIME OCC&lt;/span&gt;
&lt;span class="go"&gt;0   3   2230&lt;/span&gt;
&lt;span class="go"&gt;1   1   330&lt;/span&gt;
&lt;span class="go"&gt;2   1   1200&lt;/span&gt;
&lt;span class="go"&gt;3   15  1730&lt;/span&gt;
&lt;span class="go"&gt;4   19  415&lt;/span&gt;
&lt;span class="go"&gt;... ... ...&lt;/span&gt;
&lt;span class="go"&gt;632385  3   10&lt;/span&gt;
&lt;span class="go"&gt;632386  10  1800&lt;/span&gt;
&lt;span class="go"&gt;632387  10  1530&lt;/span&gt;
&lt;span class="go"&gt;632388  11  2000&lt;/span&gt;
&lt;span class="go"&gt;632389  16  1800&lt;/span&gt;
&lt;span class="go"&gt;632390 rows × 2 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now let’s combine using a list of row labels and column labels:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;AREA&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TIME OCC&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="go"&gt;        AREA    TIME OCC&lt;/span&gt;
&lt;span class="go"&gt;0   3   2230&lt;/span&gt;
&lt;span class="go"&gt;1   1   330&lt;/span&gt;
&lt;span class="go"&gt;2   1   1200&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Part 3: Using Pandas Loc to Index with Slices&lt;/h3&gt;
&lt;p&gt;Now we will dive more into passing slices into row and column selectors. Again, this example is passing in two slices separated by the comma.&lt;/p&gt;
&lt;p&gt;In this case, the syntax df.loc[0:2, 'TIME OCC':'Part 1-2'] is used to select the rows with labels 0, 1, and 2, and the columns with labels from 'TIME OCC' to 'Part 1-2', inclusive, in the DataFrame.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TIME OCC&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Part 1-2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="go"&gt;    TIME OCC    AREA    AREA NAME   Rpt Dist No Part 1-2&lt;/span&gt;
&lt;span class="go"&gt;0   2230        3   Southwest   377     2&lt;/span&gt;
&lt;span class="go"&gt;1   330     1   Central         163     2&lt;/span&gt;
&lt;span class="go"&gt;2   1200        1   Central         155     2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;One gotcha to be aware of is that slicing with Pandas loc is inclusive. It includes the stop value. Normal Python doesn't behave this way. If I slice a string with 0:2, it uses the half-open interval, returning values from index 0 up to but not including 2.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="go"&gt;&amp;#39;he&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can also pass in Python lists with boolean values for the index and column selectors. These lists need to be the same size as the index and columns respectively. In practice, I don’t find that I use this option too often, but for completeness I will show it here.&lt;/p&gt;
&lt;p&gt;One place where this is useful is if you have a bunch of columns that have the same prefix/suffix/substring. For example, this dataset has a bunch of columns with Crm in them. This example pulls out every third row and selects only the columns that have a 'Crm' in the them.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;))],&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;       &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Crm&amp;#39;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="go"&gt;    Crm Cd  Crm Cd Desc                     Crm Cd 1    Crm Cd 2    Crm Cd 3    Crm Cd 4&lt;/span&gt;
&lt;span class="go"&gt;2   845 SEX OFFENDER REGISTRANT OUT OF COMPLIANCE       845.0       NaN     NaN     NaN&lt;/span&gt;
&lt;span class="go"&gt;5   121 RAPE, FORCIBLE                      121.0       998.0       NaN     NaN&lt;/span&gt;
&lt;span class="go"&gt;8   341 THEFT-GRAND ($950.01 &amp;amp; OVER)EXCPT,GUNS,FOWL,LI...   341.0       998.0       NaN     NaN&lt;/span&gt;
&lt;span class="go"&gt;11  930 CRIMINAL THREATS - NO WEAPON DISPLAYED          930.0       NaN     NaN     NaN&lt;/span&gt;
&lt;span class="go"&gt;14  442 SHOPLIFTING - PETTY THEFT ($950 &amp;amp; UNDER)        442.0       NaN     NaN     NaN&lt;/span&gt;
&lt;span class="go"&gt;... ... ...                         ...     ...     ...     ...&lt;/span&gt;
&lt;span class="go"&gt;632375  510 VEHICLE - STOLEN                    510.0       NaN     NaN     NaN&lt;/span&gt;
&lt;span class="go"&gt;632378  341 THEFT-GRAND ($950.01 &amp;amp; OVER)EXCPT,GUNS,FOWL,LI...   341.0       NaN     NaN     NaN&lt;/span&gt;
&lt;span class="go"&gt;632381  310 BURGLARY                        310.0       998.0       NaN     NaN&lt;/span&gt;
&lt;span class="go"&gt;632384  626 INTIMATE PARTNER - SIMPLE ASSAULT           626.0       NaN     NaN     NaN&lt;/span&gt;
&lt;span class="go"&gt;632387  510 VEHICLE - STOLEN                    510.0       NaN     NaN     NaN&lt;/span&gt;
&lt;span class="go"&gt;210796 rows × 6 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I would probably just write the list comprehension for the column selector in the previous example as:&lt;/p&gt;
&lt;p&gt;[col for col in df.columns if 'Crm' in col]&lt;/p&gt;
&lt;h3&gt;Part 4: Using Pandas Loc to Index with Boolean Arrays&lt;/h3&gt;
&lt;p&gt;In this next example we pass in what the docs call &lt;em&gt;an alignable boolean Series&lt;/em&gt;. Often this is called a &lt;em&gt;boolean array&lt;/em&gt; in the real world (which comes from NumPy). In the Pandas context, a boolean array is a series with true/false values that has the same index as another dataframe or series.&lt;/p&gt;
&lt;p&gt;In this example, row_indexer is a boolean array created by comparing the values in the AREA NAME column to the string 'Central' using the == operator. Only the rows where the value is True are selected. The column_indexer is not specified, so all columns are selected.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;AREA NAME&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Central&amp;#39;&lt;/span&gt; &lt;span class="c1"&gt;# boolean array&lt;/span&gt;
&lt;span class="go"&gt;0         False&lt;/span&gt;
&lt;span class="go"&gt;1          True&lt;/span&gt;
&lt;span class="go"&gt;2          True&lt;/span&gt;
&lt;span class="go"&gt;3         False&lt;/span&gt;
&lt;span class="go"&gt;4         False&lt;/span&gt;
&lt;span class="go"&gt;          ...&lt;/span&gt;
&lt;span class="go"&gt;636127    False&lt;/span&gt;
&lt;span class="go"&gt;636128    False&lt;/span&gt;
&lt;span class="go"&gt;636129    False&lt;/span&gt;
&lt;span class="go"&gt;636130    False&lt;/span&gt;
&lt;span class="go"&gt;636131    False&lt;/span&gt;
&lt;span class="go"&gt;Name: AREA NAME, Length: 636132, dtype: bool&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can use a boolean array directly in .loc. This should return only the rows from the &lt;em&gt;Central&lt;/em&gt; area.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;AREA NAME&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Central&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="go"&gt;    DR_NO       Date Rptd       DATE OCC        TIME OCC    AREA    AREA NAME   Rpt Dist No Part 1-2    Crm Cd  Crm Cd Desc                 ... Status  Status Desc Crm Cd 1    Crm Cd 2    Crm Cd 3    Crm Cd 4    LOCATION        Cross Street    LAT LON&lt;/span&gt;
&lt;span class="go"&gt;1   190101086   01/02/2020 12:00:00 AM  01/01/2020 12:00:00 AM  330     1   Central     163     2       624 BATTERY - SIMPLE ASSAULT            ... IC  Invest Cont 624.0       NaN     NaN     NaN     700 S HILL ST       NaN 34.0459 -118.2545&lt;/span&gt;
&lt;span class="go"&gt;2   200110444   04/14/2020 12:00:00 AM  02/13/2020 12:00:00 AM  1200        1   Central     155     2       845 SEX OFFENDER REGISTRANT OUT OF COMPLIANCE   ... AA  Adult Arrest    845.0       NaN     NaN     NaN     200 E 6TH ST        NaN     34.0448 -118.2474&lt;/span&gt;
&lt;span class="go"&gt;5   200100501   01/02/2020 12:00:00 AM  01/01/2020 12:00:00 AM  30      1   Central     163     1       121 RAPE, FORCIBLE                  ... IC  Invest Cont 121.0       998.0       NaN     NaN     700 S BROADWAY      NaN     34.0452 -118.2534&lt;/span&gt;
&lt;span class="go"&gt;6   200100502   01/02/2020 12:00:00 AM  01/02/2020 12:00:00 AM  1315        1   Central     161     1       442 SHOPLIFTING - PETTY THEFT ($950 &amp;amp; UNDER)    ... IC  Invest Cont 442.0       998.0       NaN     NaN     700 S FIGUEROA ST   NaN     34.0483 -118.2631&lt;/span&gt;
&lt;span class="go"&gt;7   200100504   01/04/2020 12:00:00 AM  01/04/2020 12:00:00 AM  40      1   Central     155     2       946 OTHER MISCELLANEOUS CRIME           ... IC  Invest Cont 946.0       998.0       NaN     NaN     200 E 6TH ST        NaN     34.0448 -118.2474&lt;/span&gt;
&lt;span class="go"&gt;... ...     ...         ...         ...     ... ...     ...     ...     ... ...                     ... ... ...     ...     ...     ...     ...     ...         ...     ... ...&lt;/span&gt;
&lt;span class="go"&gt;632334  220123144   10/24/2022 12:00:00 AM  10/20/2022 12:00:00 AM  1930        1   Central     159     1       330 BURGLARY FROM VEHICLE               ... IC  Invest Cont 330.0       NaN     NaN     NaN     1500 JESSE ST       NaN     34.0362 -118.2325&lt;/span&gt;
&lt;span class="go"&gt;632336  220112110   05/10/2022 12:00:00 AM  01/10/2022 12:00:00 AM  1150        1   Central     195     2       354 THEFT OF IDENTITY               ... IC  Invest Cont 354.0       NaN     NaN     NaN     100 W 17TH ST       NaN     34.0329 -118.2631&lt;/span&gt;
&lt;span class="go"&gt;632340  220107479   03/01/2022 12:00:00 AM  02/28/2022 12:00:00 AM  1400        1   Central     129     1       330 BURGLARY FROM VEHICLE               ... IC  Invest Cont 330.0       NaN     NaN     NaN     400 N VIGNES ST     NaN     34.0511 -118.2334&lt;/span&gt;
&lt;span class="go"&gt;632360  220106541   02/13/2022 12:00:00 AM  02/13/2022 12:00:00 AM  1745        1   Central     145     2       624 BATTERY - SIMPLE ASSAULT            ... AO  Adult Other 624.0       NaN     NaN     NaN     100 E 5TH ST        NaN     34.0471 -118.2474&lt;/span&gt;
&lt;span class="go"&gt;632361  220118304   08/15/2022 12:00:00 AM  08/14/2022 12:00:00 AM  420     1   Central     195     1       310 BURGLARY                    ... IC  Invest Cont 310.0       NaN     NaN     NaN     1400 S MAIN ST      NaN     34.0351 -118.2614&lt;/span&gt;
&lt;span class="go"&gt;41748 rows × 28 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can see that rows with index label 3 and 4 are missing because those rows didn’t have crimes in the &lt;em&gt;Central&lt;/em&gt; area.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;AREA NAME&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="go"&gt;        AREA NAME&lt;/span&gt;
&lt;span class="go"&gt;3   N Hollywood&lt;/span&gt;
&lt;span class="go"&gt;4   Mission&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can also use a boolean array (or alignable boolean Series as the docs call it) for the column selector. It is normal to think of a boolean array for the index selector, a True or False value for each row with the same index. What is a boolean array for the column selector?&lt;/p&gt;
&lt;p&gt;To use a boolean array for a column selector you would have a Series that had the column names in the index and True or False values.&lt;/p&gt;
&lt;p&gt;In this example, we will select all the columns that have more than the median number of unique column entries.&lt;/p&gt;
&lt;p&gt;First, let’s calculate the number of unique entries for each column.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nunique&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="go"&gt;DR_NO       632390&lt;/span&gt;
&lt;span class="go"&gt;Date Rptd   1091&lt;/span&gt;
&lt;span class="go"&gt;DATE OCC    1091&lt;/span&gt;
&lt;span class="go"&gt;TIME OCC    1439&lt;/span&gt;
&lt;span class="go"&gt;AREA        21&lt;/span&gt;
&lt;span class="go"&gt;AREA NAME   21&lt;/span&gt;
&lt;span class="go"&gt;Rpt Dist No 1191&lt;/span&gt;
&lt;span class="go"&gt;Part 1-2    2&lt;/span&gt;
&lt;span class="go"&gt;Crm Cd      137&lt;/span&gt;
&lt;span class="go"&gt;Crm Cd Desc 137&lt;/span&gt;
&lt;span class="go"&gt;Mocodes     219372&lt;/span&gt;
&lt;span class="go"&gt;Vict Age    101&lt;/span&gt;
&lt;span class="go"&gt;Vict Sex    4&lt;/span&gt;
&lt;span class="go"&gt;Vict Descen 19&lt;/span&gt;
&lt;span class="go"&gt;Premis Cd   309&lt;/span&gt;
&lt;span class="go"&gt;Premis Desc 306&lt;/span&gt;
&lt;span class="go"&gt;Weapon Used Cd  79&lt;/span&gt;
&lt;span class="go"&gt;Weapon Desc 79&lt;/span&gt;
&lt;span class="go"&gt;Status      6&lt;/span&gt;
&lt;span class="go"&gt;Status Desc 6&lt;/span&gt;
&lt;span class="go"&gt;Crm Cd 1    139&lt;/span&gt;
&lt;span class="go"&gt;Crm Cd 2    120&lt;/span&gt;
&lt;span class="go"&gt;Crm Cd 3    35&lt;/span&gt;
&lt;span class="go"&gt;Crm Cd 4    6&lt;/span&gt;
&lt;span class="go"&gt;LOCATION    60076&lt;/span&gt;
&lt;span class="go"&gt;Cross Street    8884&lt;/span&gt;
&lt;span class="go"&gt;LAT     5363&lt;/span&gt;
&lt;span class="go"&gt;LON     4953&lt;/span&gt;
&lt;span class="go"&gt;dtype: int64&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then we will calculate the median of these values.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nunique&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;median&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="go"&gt;137.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The boolean array will be the columns where the number of unique values is greater than 137.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nunique&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;137&lt;/span&gt;
&lt;span class="go"&gt;DR_NO       True&lt;/span&gt;
&lt;span class="go"&gt;Date Rptd   True&lt;/span&gt;
&lt;span class="go"&gt;DATE OCC    True&lt;/span&gt;
&lt;span class="go"&gt;TIME OCC    True&lt;/span&gt;
&lt;span class="go"&gt;AREA        False&lt;/span&gt;
&lt;span class="go"&gt;AREA NAME   False&lt;/span&gt;
&lt;span class="go"&gt;Rpt Dist No True&lt;/span&gt;
&lt;span class="go"&gt;Part 1-2    False&lt;/span&gt;
&lt;span class="go"&gt;Crm Cd      False&lt;/span&gt;
&lt;span class="go"&gt;Crm Cd Desc False&lt;/span&gt;
&lt;span class="go"&gt;Mocodes     True&lt;/span&gt;
&lt;span class="go"&gt;Vict Age    False&lt;/span&gt;
&lt;span class="go"&gt;Vict Sex    False&lt;/span&gt;
&lt;span class="go"&gt;Vict Descent    False&lt;/span&gt;
&lt;span class="go"&gt;Premis Cd   True&lt;/span&gt;
&lt;span class="go"&gt;Premis Desc True&lt;/span&gt;
&lt;span class="go"&gt;Weapon Used Cd  False&lt;/span&gt;
&lt;span class="go"&gt;Weapon Desc False&lt;/span&gt;
&lt;span class="go"&gt;Status      False&lt;/span&gt;
&lt;span class="go"&gt;Status Desc False&lt;/span&gt;
&lt;span class="go"&gt;Crm Cd 1    True&lt;/span&gt;
&lt;span class="go"&gt;Crm Cd 2    False&lt;/span&gt;
&lt;span class="go"&gt;Crm Cd 3    False&lt;/span&gt;
&lt;span class="go"&gt;Crm Cd 4    False&lt;/span&gt;
&lt;span class="go"&gt;LOCATION    True&lt;/span&gt;
&lt;span class="go"&gt;Cross Street    True&lt;/span&gt;
&lt;span class="go"&gt;LAT     True&lt;/span&gt;
&lt;span class="go"&gt;LON     True&lt;/span&gt;
&lt;span class="go"&gt;dtype: bool&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let's use this boolean array as the column selector. We will use the slice, :, as the row selector to return all of the rows.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nunique&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;137&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="go"&gt;    DR_NO       Date Rptd       DATE OCC        TIME OCC    Rpt Dist No Mocodes     Premis Cd   Premis Desc                 Crm Cd 1    LOCATION        Cross Street    LAT LON&lt;/span&gt;
&lt;span class="go"&gt;0   10304468    01/08/2020 12:00:00 AM  01/08/2020 12:00:00 AM  2230        377     0444 0913   501.0       SINGLE FAMILY DWELLING              624.0       1100 W 39TH PL      NaN     34.0141 -118.2978&lt;/span&gt;
&lt;span class="go"&gt;1   190101086   01/02/2020 12:00:00 AM  01/01/2020 12:00:00 AM  330     163     0416 1822 1414  102.0       SIDEWALK                    624.0       700 S HILL ST       NaN     34.0459 -118.2545&lt;/span&gt;
&lt;span class="go"&gt;2   200110444   04/14/2020 12:00:00 AM  02/13/2020 12:00:00 AM  1200        155     1501        726.0       POLICE FACILITY                 845.0       200 E 6TH ST        NaN     34.0448 -118.2474&lt;/span&gt;
&lt;span class="go"&gt;3   191501505   01/01/2020 12:00:00 AM  01/01/2020 12:00:00 AM  1730        1543        0329 1402   502.0       MULTI-UNIT DWELLING (APARTMENT, DUPLEX, ETC)    745.0       5400 CORTEEN PL     NaN     34.1685 -118.4019&lt;/span&gt;
&lt;span class="go"&gt;4   191921269   01/01/2020 12:00:00 AM  01/01/2020 12:00:00 AM  415     1998        0329        409.0       BEAUTY SUPPLY STORE             740.0       14400 TITUS ST      NaN     34.2198 -118.4468&lt;/span&gt;
&lt;span class="go"&gt;... ...     ...         ...         ...     ...     ...     ...     ...                     ...     ...         ...     ... ...&lt;/span&gt;
&lt;span class="go"&gt;632385  220314584   08/02/2022 12:00:00 AM  08/02/2022 12:00:00 AM  10      334     0100 1822 0922  501.0       SINGLE FAMILY DWELLING              354.0       4300 W 28TH ST      NaN     34.0311 -118.3335&lt;/span&gt;
&lt;span class="go"&gt;632386  221017286   12/05/2022 12:00:00 AM  12/01/2022 12:00:00 AM  1800        1047        1822 0385   101.0       STREET                      331.0       17200 BURBANK BL    NaN     34.1722 -118.5077&lt;/span&gt;
&lt;span class="go"&gt;632387  221005507   02/10/2022 12:00:00 AM  02/09/2022 12:00:00 AM  1530        1024        NaN     108.0       PARKING LOT                 510.0       18800 SHERMAN WY    NaN     34.2011 -118.5426&lt;/span&gt;
&lt;span class="go"&gt;632388  221105477   02/10/2022 12:00:00 AM  02/08/2022 12:00:00 AM  2000        1171        NaN     101.0       STREET                      510.0       4000 FOUNTAIN AV    NaN     34.0958 -118.2787&lt;/span&gt;
&lt;span class="go"&gt;632389  221605448   02/15/2022 12:00:00 AM  02/14/2022 12:00:00 AM  1800        1613        0385 1300   101.0       STREET                      331.0       12700 VAN NUYS BL   NaN     34.2755 -118.4092&lt;/span&gt;
&lt;span class="go"&gt;632390 rows × 13 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Part 5: Using Pandas Loc to Index with Indexes&lt;/h3&gt;
&lt;p&gt;Let’s look at using an &lt;em&gt;alignable index&lt;/em&gt; for selection. This consists of passing in an Index that has entries that correspond to entries in the dataframe.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;       &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;AREA&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TIME OCC&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])]&lt;/span&gt;
&lt;span class="go"&gt;        AREA    TIME OCC&lt;/span&gt;
&lt;span class="go"&gt;0   3   2230&lt;/span&gt;
&lt;span class="go"&gt;5   1   30&lt;/span&gt;
&lt;span class="go"&gt;100 1   2210&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Why would you use this? In the example above it is just more typing that passing in a list to the row and column indexers.&lt;/p&gt;
&lt;p&gt;I grepped through a bunch of my Pandas code to look for examples of this. Let me show two.&lt;/p&gt;
&lt;p&gt;This first example comes from creating a dataset for machine learning. It creates the X dataset by dropping rows with missing values. To find the corresponding y labels we use the index from X. Note the line .loc[X.index].&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;https://raw.githubusercontent.com/vincentarelbundock/Rdatasets/master/csv/DAAG/possum.csv&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;possum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index_col&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;possum&lt;/span&gt;
     &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dropna&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
     &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[:,[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ones&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="s1"&gt;&amp;#39;hdlngth&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;skullw&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;totlngth&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;taill&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="s1"&gt;&amp;#39;footlgth&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;earconch&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;eye&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;chest&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;belly&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;possum&lt;/span&gt;
     &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
     &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here's one more example that combines the .intersection method of an Index to gather financial data where the we had the smallest openings and the largest gains.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pandas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pd&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;https://query1.finance.yahoo.com/v7/finance/download/TSLA?period1=1669852800&amp;amp;period2=1672444800&amp;amp;interval=1d&amp;amp;events=history&amp;amp;includeAdjustedClose=true&amp;#39;&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;tsla&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_smallest_open_largest_gain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="n"&gt;smallest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nsmallest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Open&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="n"&gt;largest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nlargest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Gain&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;smallest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intersection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;largest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tsla&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Date&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;datetime64[ns]&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;          &lt;span class="s2"&gt;&amp;quot;Open&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;float&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;          &lt;span class="s2"&gt;&amp;quot;High&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;float&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;          &lt;span class="s2"&gt;&amp;quot;Low&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;float&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;          &lt;span class="s2"&gt;&amp;quot;Close&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;float&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;          &lt;span class="s2"&gt;&amp;quot;Adj Close&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;float&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;          &lt;span class="s2"&gt;&amp;quot;Volume&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;float&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Gain&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_smallest_open_largest_gain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;    Date        Open        High        Low     Close       Adj Close   Volume      Gain&lt;/span&gt;
&lt;span class="go"&gt;18  2022-12-28  110.349998  116.269997  108.239998  112.709999  112.709999  221070500.0 2.360001&lt;/span&gt;
&lt;span class="go"&gt;20  2022-12-30  119.949997  124.480003  119.750000  123.180000  123.180000  157304500.0 3.230003&lt;/span&gt;
&lt;span class="go"&gt;19  2022-12-29  120.389999  123.570000  117.500000  121.820000  121.820000  221923300.0 1.430001&lt;/span&gt;
&lt;span class="go"&gt;14  2022-12-21  139.339996  141.259995  135.889999  137.570007  137.570007  145417400.0 -1.769989&lt;/span&gt;
&lt;span class="go"&gt;10  2022-12-15  153.440002  160.929993  153.279999  157.669998  157.669998  122334500.0 4.229996&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Part 6: Using Pandas Loc with Functions as Indexers&lt;/h3&gt;
&lt;p&gt;Now comes the fun part and the brain-bending part: Passing in a function for the selectors. These come in very hand when you are chaining operations and the index has different values (very common with grouping operations).&lt;/p&gt;
&lt;p&gt;Here is an example showing passing in a function that just returns a slice to get the labels from 0 through 10. Again, I don’t need to use a function here, but I’m showing it to introduce the concept before completely melting brains.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;first_ten&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;first_ten&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# same as df.loc[0:10]&lt;/span&gt;
&lt;span class="go"&gt;    DR_NO       Date Rptd       DATE OCC        TIME OCC    AREA    AREA NAME   Rpt Dist No Part 1-2    Crm Cd  Crm Cd Desc                     ... Status  Status Desc Crm Cd 1    Crm Cd 2    Crm Cd 3    Crm Cd 4    LOCATION        Cross Street    LAT LON&lt;/span&gt;
&lt;span class="go"&gt;0   10304468    01/08/2020 12:00:00 AM  01/08/2020 12:00:00 AM  2230        3   Southwest   377     2       624 BATTERY - SIMPLE ASSAULT                ... AO  Adult Other 624.0       NaN     NaN     NaN     1100 W 39TH PL      NaN     34.0141 -118.2978&lt;/span&gt;
&lt;span class="go"&gt;1   190101086   01/02/2020 12:00:00 AM  01/01/2020 12:00:00 AM  330     1   Central     163     2       624 BATTERY - SIMPLE ASSAULT                ... IC  Invest Cont 624.0       NaN     NaN     NaN     700 S HILL ST       NaN     34.0459 -118.2545&lt;/span&gt;
&lt;span class="go"&gt;2   200110444   04/14/2020 12:00:00 AM  02/13/2020 12:00:00 AM  1200        1   Central     155     2       845 SEX OFFENDER REGISTRANT OUT OF COMPLIANCE       ... AA  Adult Arrest    845.0       NaN     NaN     NaN     200 E 6TH ST        NaN     34.0448 -118.2474&lt;/span&gt;
&lt;span class="go"&gt;3   191501505   01/01/2020 12:00:00 AM  01/01/2020 12:00:00 AM  1730        15  N Hollywood 1543        2       745 VANDALISM - MISDEAMEANOR ($399 OR UNDER)        ... IC  Invest Cont 745.0       998.0       NaN     NaN     5400 CORTEEN PL     NaN     34.1685 -118.4019&lt;/span&gt;
&lt;span class="go"&gt;4   191921269   01/01/2020 12:00:00 AM  01/01/2020 12:00:00 AM  415     19  Mission     1998        2       740 VANDALISM - FELONY ($400 &amp;amp; OVER, ALL CHURCH VA...   ... IC  Invest Cont 740.0       NaN     NaN     NaN     14400 TITUS ST      NaN     34.2198 -118.4468&lt;/span&gt;
&lt;span class="go"&gt;5   200100501   01/02/2020 12:00:00 AM  01/01/2020 12:00:00 AM  30      1   Central     163     1       121 RAPE, FORCIBLE                      ... IC  Invest Cont 121.0       998.0       NaN     NaN     700 S BROADWAY      NaN     34.0452 -118.2534&lt;/span&gt;
&lt;span class="go"&gt;6   200100502   01/02/2020 12:00:00 AM  01/02/2020 12:00:00 AM  1315        1   Central     161     1       442 SHOPLIFTING - PETTY THEFT ($950 &amp;amp; UNDER)        ... IC  Invest Cont 442.0       998.0       NaN     NaN     700 S FIGUEROA ST   NaN     34.0483 -118.2631&lt;/span&gt;
&lt;span class="go"&gt;7   200100504   01/04/2020 12:00:00 AM  01/04/2020 12:00:00 AM  40      1   Central     155     2       946 OTHER MISCELLANEOUS CRIME               ... IC  Invest Cont 946.0       998.0       NaN     NaN     200 E 6TH ST        NaN     34.0448 -118.2474&lt;/span&gt;
&lt;span class="go"&gt;8   200100507   01/04/2020 12:00:00 AM  01/04/2020 12:00:00 AM  200     1   Central     101     1       341 THEFT-GRAND ($950.01 &amp;amp; OVER)EXCPT,GUNS,FOWL,LI...   ... IC  Invest Cont 341.0       998.0       NaN     NaN     700 BERNARD ST      NaN     34.0677 -118.2398&lt;/span&gt;
&lt;span class="go"&gt;9   201710201   06/19/2020 12:00:00 AM  05/26/2020 12:00:00 AM  1925        17  Devonshire  1708        1       341 THEFT-GRAND ($950.01 &amp;amp; OVER)EXCPT,GUNS,FOWL,LI...   ... AO  Adult Other 341.0       NaN     NaN     NaN     11900 BALBOA BL     NaN     34.2864 -118.5021&lt;/span&gt;
&lt;span class="go"&gt;10  200100509   01/04/2020 12:00:00 AM  01/04/2020 12:00:00 AM  2200        1   Central     192     1       330 BURGLARY FROM VEHICLE                   ... IC  Invest Cont 330.0       NaN     NaN     NaN     15TH            OLIVE       34.0359 -118.2648&lt;/span&gt;
&lt;span class="go"&gt;11 rows × 28 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Unless I'm reusing the function in multiple places in my code, I generally will inline it with an anonymous function, a lambda.&lt;/p&gt;
&lt;p&gt;This is the same code as above but it uses a lambda.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;ignore_df&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="go"&gt;    DR_NO       Date Rptd       DATE OCC        TIME OCC    AREA    AREA NAME   Rpt Dist No Part 1-2    Crm Cd  Crm Cd Desc                     ... Status  Status Desc Crm Cd 1    Crm Cd 2    Crm Cd 3    Crm Cd 4    LOCATION        Cross Street    LAT LON&lt;/span&gt;
&lt;span class="go"&gt;0   10304468    01/08/2020 12:00:00 AM  01/08/2020 12:00:00 AM  2230        3   Southwest   377     2       624 BATTERY - SIMPLE ASSAULT                ... AO  Adult Other 624.0       NaN     NaN     NaN     1100 W 39TH PL      NaN     34.0141 -118.2978&lt;/span&gt;
&lt;span class="go"&gt;1   190101086   01/02/2020 12:00:00 AM  01/01/2020 12:00:00 AM  330     1   Central     163     2       624 BATTERY - SIMPLE ASSAULT                ... IC  Invest Cont 624.0       NaN     NaN     NaN     700 S HILL ST       NaN     34.0459 -118.2545&lt;/span&gt;
&lt;span class="go"&gt;2   200110444   04/14/2020 12:00:00 AM  02/13/2020 12:00:00 AM  1200        1   Central     155     2       845 SEX OFFENDER REGISTRANT OUT OF COMPLIANCE       ... AA  Adult Arrest    845.0       NaN     NaN     NaN     200 E 6TH ST        NaN     34.0448 -118.2474&lt;/span&gt;
&lt;span class="go"&gt;3   191501505   01/01/2020 12:00:00 AM  01/01/2020 12:00:00 AM  1730        15  N Hollywood 1543        2       745 VANDALISM - MISDEAMEANOR ($399 OR UNDER)        ... IC  Invest Cont 745.0       998.0       NaN     NaN     5400 CORTEEN PL     NaN     34.1685 -118.4019&lt;/span&gt;
&lt;span class="go"&gt;4   191921269   01/01/2020 12:00:00 AM  01/01/2020 12:00:00 AM  415     19  Mission     1998        2       740 VANDALISM - FELONY ($400 &amp;amp; OVER, ALL CHURCH VA...   ... IC  Invest Cont 740.0       NaN     NaN     NaN     14400 TITUS ST      NaN     34.2198 -118.4468&lt;/span&gt;
&lt;span class="go"&gt;5   200100501   01/02/2020 12:00:00 AM  01/01/2020 12:00:00 AM  30      1   Central     163     1       121 RAPE, FORCIBLE                      ... IC  Invest Cont 121.0       998.0       NaN     NaN     700 S BROADWAY      NaN     34.0452 -118.2534&lt;/span&gt;
&lt;span class="go"&gt;6   200100502   01/02/2020 12:00:00 AM  01/02/2020 12:00:00 AM  1315        1   Central     161     1       442 SHOPLIFTING - PETTY THEFT ($950 &amp;amp; UNDER)        ... IC  Invest Cont 442.0       998.0       NaN     NaN     700 S FIGUEROA ST   NaN     34.0483 -118.2631&lt;/span&gt;
&lt;span class="go"&gt;7   200100504   01/04/2020 12:00:00 AM  01/04/2020 12:00:00 AM  40      1   Central     155     2       946 OTHER MISCELLANEOUS CRIME               ... IC  Invest Cont 946.0       998.0       NaN     NaN     200 E 6TH ST        NaN     34.0448 -118.2474&lt;/span&gt;
&lt;span class="go"&gt;8   200100507   01/04/2020 12:00:00 AM  01/04/2020 12:00:00 AM  200     1   Central     101     1       341 THEFT-GRAND ($950.01 &amp;amp; OVER)EXCPT,GUNS,FOWL,LI...   ... IC  Invest Cont 341.0       998.0       NaN     NaN     700 BERNARD ST      NaN     34.0677 -118.2398&lt;/span&gt;
&lt;span class="go"&gt;9   201710201   06/19/2020 12:00:00 AM  05/26/2020 12:00:00 AM  1925        17  Devonshire  1708        1       341 THEFT-GRAND ($950.01 &amp;amp; OVER)EXCPT,GUNS,FOWL,LI...   ... AO  Adult Other 341.0       NaN     NaN     NaN     11900 BALBOA BL     NaN     34.2864 -118.5021&lt;/span&gt;
&lt;span class="go"&gt;10  200100509   01/04/2020 12:00:00 AM  01/04/2020 12:00:00 AM  2200        1   Central     192     1       330 BURGLARY FROM VEHICLE                   ... IC  Invest Cont 330.0       NaN     NaN     NaN     15TH            OLIVE       34.0359 -118.2648&lt;/span&gt;
&lt;span class="go"&gt;11 rows × 28 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note that we can also pass in a function to the column selector, in this case we get an error because the columns are strings and the function trys to slice with numbers.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="n"&gt;first_ten&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="go"&gt;---------------------------------------------------------------------------&lt;/span&gt;
&lt;span class="go"&gt;TypeError                                 Traceback (most recent call last)&lt;/span&gt;
&lt;span class="go"&gt;&amp;lt;ipython-input-34-484bd8722f00&amp;gt; in &amp;lt;module&amp;gt;&lt;/span&gt;
&lt;span class="go"&gt;----&amp;gt; 1 df.loc[:, first_ten]&lt;/span&gt;
&lt;span class="go"&gt;/usr/local/lib/python3.8/dist-packages/pandas/core/indexing.py in __getitem__(self, key)&lt;/span&gt;
&lt;span class="go"&gt;    923                 with suppress(KeyError, IndexError):&lt;/span&gt;
&lt;span class="go"&gt;    924                     return self.obj._get_value(*key, takeable=self._takeable)&lt;/span&gt;
&lt;span class="go"&gt;--&amp;gt; 925             return self._getitem_tuple(key)&lt;/span&gt;
&lt;span class="go"&gt;    926         else:&lt;/span&gt;
&lt;span class="go"&gt;    927             # we by definition only have the 0th axis&lt;/span&gt;
&lt;span class="go"&gt;/usr/local/lib/python3.8/dist-packages/pandas/core/indexing.py in _getitem_tuple(self, tup)&lt;/span&gt;
&lt;span class="go"&gt;   1107             return self._multi_take(tup)&lt;/span&gt;
&lt;span class="go"&gt;   1108&lt;/span&gt;
&lt;span class="go"&gt;-&amp;gt; 1109         return self._getitem_tuple_same_dim(tup)&lt;/span&gt;
&lt;span class="go"&gt;   1110&lt;/span&gt;
&lt;span class="go"&gt;   1111     def _get_label(self, label, axis: int):&lt;/span&gt;
&lt;span class="go"&gt;/usr/local/lib/python3.8/dist-packages/pandas/core/indexing.py in _getitem_tuple_same_dim(self, tup)&lt;/span&gt;
&lt;span class="go"&gt;    804                 continue&lt;/span&gt;
&lt;span class="go"&gt;    805&lt;/span&gt;
&lt;span class="go"&gt;--&amp;gt; 806             retval = getattr(retval, self.name)._getitem_axis(key, axis=i)&lt;/span&gt;
&lt;span class="go"&gt;    807             # We should never have retval.ndim &amp;lt; self.ndim, as that should&lt;/span&gt;
&lt;span class="go"&gt;    808             #  be handled by the _getitem_lowerdim call above.&lt;/span&gt;
&lt;span class="go"&gt;/usr/local/lib/python3.8/dist-packages/pandas/core/indexing.py in _getitem_axis(self, key, axis)&lt;/span&gt;
&lt;span class="go"&gt;   1140         if isinstance(key, slice):&lt;/span&gt;
&lt;span class="go"&gt;   1141             self._validate_key(key, axis)&lt;/span&gt;
&lt;span class="go"&gt;-&amp;gt; 1142             return self._get_slice_axis(key, axis=axis)&lt;/span&gt;
&lt;span class="go"&gt;   1143         elif com.is_bool_indexer(key):&lt;/span&gt;
&lt;span class="go"&gt;   1144             return self._getbool_axis(key, axis=axis)&lt;/span&gt;
&lt;span class="go"&gt;/usr/local/lib/python3.8/dist-packages/pandas/core/indexing.py in _get_slice_axis(self, slice_obj, axis)&lt;/span&gt;
&lt;span class="go"&gt;   1174&lt;/span&gt;
&lt;span class="go"&gt;   1175         labels = obj._get_axis(axis)&lt;/span&gt;
&lt;span class="go"&gt;-&amp;gt; 1176         indexer = labels.slice_indexer(slice_obj.start, slice_obj.stop, slice_obj.step)&lt;/span&gt;
&lt;span class="go"&gt;   1177&lt;/span&gt;
&lt;span class="go"&gt;   1178         if isinstance(indexer, slice):&lt;/span&gt;
&lt;span class="go"&gt;/usr/local/lib/python3.8/dist-packages/pandas/core/indexes/base.py in slice_indexer(self, start, end, step, kind)&lt;/span&gt;
&lt;span class="go"&gt;   5683         slice(1, 3, None)&lt;/span&gt;
&lt;span class="go"&gt;   5684         &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="go"&gt;-&amp;gt; 5685         start_slice, end_slice = self.slice_locs(start, end, step=step)&lt;/span&gt;
&lt;span class="go"&gt;   5686&lt;/span&gt;
&lt;span class="go"&gt;   5687         # return a slice&lt;/span&gt;
&lt;span class="go"&gt;/usr/local/lib/python3.8/dist-packages/pandas/core/indexes/base.py in slice_locs(self, start, end, step, kind)&lt;/span&gt;
&lt;span class="go"&gt;   5885         start_slice = None&lt;/span&gt;
&lt;span class="go"&gt;   5886         if start is not None:&lt;/span&gt;
&lt;span class="go"&gt;-&amp;gt; 5887             start_slice = self.get_slice_bound(start, &amp;quot;left&amp;quot;)&lt;/span&gt;
&lt;span class="go"&gt;   5888         if start_slice is None:&lt;/span&gt;
&lt;span class="go"&gt;   5889             start_slice = 0&lt;/span&gt;
&lt;span class="go"&gt;/usr/local/lib/python3.8/dist-packages/pandas/core/indexes/base.py in get_slice_bound(self, label, side, kind)&lt;/span&gt;
&lt;span class="go"&gt;   5795         # For datetime indices label may be a string that has to be converted&lt;/span&gt;
&lt;span class="go"&gt;   5796         # to datetime boundary according to its resolution.&lt;/span&gt;
&lt;span class="go"&gt;-&amp;gt; 5797         label = self._maybe_cast_slice_bound(label, side)&lt;/span&gt;
&lt;span class="go"&gt;   5798&lt;/span&gt;
&lt;span class="go"&gt;   5799         # we need to look up the label&lt;/span&gt;
&lt;span class="go"&gt;/usr/local/lib/python3.8/dist-packages/pandas/core/indexes/base.py in _maybe_cast_slice_bound(self, label, side, kind)&lt;/span&gt;
&lt;span class="go"&gt;   5747         # reject them, if index does not contain label&lt;/span&gt;
&lt;span class="go"&gt;   5748         if (is_float(label) or is_integer(label)) and label not in self._values:&lt;/span&gt;
&lt;span class="go"&gt;-&amp;gt; 5749             raise self._invalid_indexer(&amp;quot;slice&amp;quot;, label)&lt;/span&gt;
&lt;span class="go"&gt;   5750&lt;/span&gt;
&lt;span class="go"&gt;   5751         return label&lt;/span&gt;
&lt;span class="go"&gt;TypeError: cannot do slice indexing on Index with these indexers [0] of type int&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here is the obligatory example with a function in the column selector.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;adf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;TIME OCC&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Part 1-2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="go"&gt;    TIME OCC    AREA    AREA NAME   Rpt Dist No Part 1-2&lt;/span&gt;
&lt;span class="go"&gt;0   2230        3   Southwest   377     2&lt;/span&gt;
&lt;span class="go"&gt;1   330     1   Central     163     2&lt;/span&gt;
&lt;span class="go"&gt;2   1200        1   Central     155     2&lt;/span&gt;
&lt;span class="go"&gt;3   1730        15  N Hollywood 1543        2&lt;/span&gt;
&lt;span class="go"&gt;4   415     19  Mission     1998        2&lt;/span&gt;
&lt;span class="go"&gt;... ...     ... ...     ...     ...&lt;/span&gt;
&lt;span class="go"&gt;632385  10      3   Southwest   334     2&lt;/span&gt;
&lt;span class="go"&gt;632386  1800        10  West Valley 1047        1&lt;/span&gt;
&lt;span class="go"&gt;632387  1530        10  West Valley 1024        1&lt;/span&gt;
&lt;span class="go"&gt;632388  2000        11  Northeast   1171        1&lt;/span&gt;
&lt;span class="go"&gt;632389  1800        16  Foothill    1613        1&lt;/span&gt;
&lt;span class="go"&gt;632390 rows × 5 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here is a more realistic example showing using a function in .loc in a chain of operations. Assume we want to understand how vehicle crimes occur over monthly periods. We could use some code like this.&lt;/p&gt;
&lt;p&gt;This code uses several functions and methods from the Pandas library to clean, organize, and summarize data in a DataFrame. First, the .astype method is used to convert the data types of the 'Date Rptd' and 'DATE OCC' columns to 'Datetime64'. Then, the .groupby method is used to group the data by the 'DATE OCC' column and the 'AREA NAME' and 'Crm Cd Desc' columns. The .size method is then used to count the number of rows in each group, and the .unstack method is used to pivot the data so that the 'Crm Cd Desc' values become column labels.&lt;/p&gt;
&lt;p&gt;Finally, the .loc indexer is used to select only the columns where the label contains the string 'VEHICLE'. We need to use a function to get the column labels because these columns come from the value of the Crm Cd Desc column. They were not columns in the original data frame.&lt;/p&gt;
&lt;p&gt;The a_df parameter for the lambda function is the intermediate state of the data in the chain. It is the result of the .unstack method on the line above it.&lt;/p&gt;
&lt;p&gt;I use functions all the time in .loc because I'm a big proponent of chaining your Pandas code to make it easier to understand. (See our article on chaining for more details on chaining.)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Date Rptd&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Datetime64&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;          &lt;span class="s1"&gt;&amp;#39;DATE OCC&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Datetime64&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;          &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grouper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DATE OCC&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;freq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;M&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;AREA NAME&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Crm Cd Desc&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unstack&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;      &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;a_df&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;a_df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;VEHICLE&amp;#39;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;        Crm Cd Desc BURGLARY FROM VEHICLE   BURGLARY FROM VEHICLE, ATTEMPTED    SHOTS FIRED AT MOVING VEHICLE, TRAIN OR AIRCRAFT    THEFT FROM MOTOR VEHICLE - ATTEMPT  THEFT FROM MOTOR VEHICLE - GRAND ($950.01 AND OVER) THEFT FROM MOTOR VEHICLE - PETTY ($950 &amp;amp; UNDER) THROWING OBJECT AT MOVING VEHICLE   VEHICLE - ATTEMPT STOLEN    VEHICLE - MOTORIZED SCOOTERS, BICYCLES, AND WHEELCHAIRS VEHICLE - STOLEN&lt;/span&gt;
&lt;span class="go"&gt;DATE OCC    AREA NAME&lt;/span&gt;
&lt;span class="go"&gt;2020-01-31  77th Street 75.0            NaN                 9.0                         3.0                 17.0                            49.0                        2.0                 4.0             NaN                         123.0&lt;/span&gt;
&lt;span class="go"&gt;        Central     144.0           NaN                 NaN                         1.0                 16.0                            31.0                        1.0                 NaN             1.0                         45.0&lt;/span&gt;
&lt;span class="go"&gt;        Devonshire  67.0            NaN                 NaN                         NaN                 20.0                            49.0                        1.0                 3.0             NaN                         40.0&lt;/span&gt;
&lt;span class="go"&gt;        Foothill    37.0            NaN                 NaN                         NaN                 13.0                            40.0                        NaN                 2.0             NaN                         69.0&lt;/span&gt;
&lt;span class="go"&gt;        Harbor      29.0            NaN                 NaN                         NaN                 19.0                            40.0                        1.0                 1.0             NaN                         77.0&lt;/span&gt;
&lt;span class="go"&gt;...     ...     ...         ...                 ...                         ...                 ...                         ...                     ...                 ...             ...                         ...&lt;/span&gt;
&lt;span class="go"&gt;2020-06-30  Topanga     55.0            2.0                 NaN                         1.0                 25.0                            39.0                        2.0                 NaN             NaN                         74.0&lt;/span&gt;
&lt;span class="go"&gt;        Van Nuys    81.0            2.0                 NaN                         NaN                 24.0                            45.0                        1.0                 3.0             NaN                         97.0&lt;/span&gt;
&lt;span class="go"&gt;        West LA     80.0            1.0                 NaN                         NaN                 32.0                            32.0                        NaN                 1.0             2.0                         62.0&lt;/span&gt;
&lt;span class="go"&gt;        West Valley 51.0            NaN                 NaN                         2.0                 23.0                            37.0                        NaN                 3.0             NaN                         79.0&lt;/span&gt;
&lt;span class="go"&gt;        Wilshire    50.0            1.0                 NaN                         1.0                 16.0                            37.0                        1.0                 1.0             NaN                         60.0&lt;/span&gt;
&lt;span class="go"&gt;126 rows × 10 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;A Practical Example of Pandas Loc&lt;/h2&gt;
&lt;p&gt;We will wrap up with a visualization of the previous analysis. I will dive into the Burglary from Vehicle column and plot that over time for the different Area Name values.&lt;/p&gt;
&lt;p&gt;In this example, in the latter .loc I use a lambda function to move the Hollywood column to the end so that it appears on top of the other columns.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;set_colors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;colors&lt;/span&gt;
  &lt;span class="n"&gt;colors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#991111&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Hollywood&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;#999999&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;

&lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Date Rptd&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Datetime64&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="s1"&gt;&amp;#39;DATE OCC&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Datetime64&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;})&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grouper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DATE OCC&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;freq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;M&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;AREA NAME&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Crm Cd Desc&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unstack&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;BURGLARY FROM VEHICLE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unstack&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;adf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;adf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Hollywood&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;set_colors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;BURGLARIES FROM VEHICLE in LA&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;legend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bbox_to_anchor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;ncol&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="Line plot of vehicle burglaries by Los Angeles area" src="/static/img/blog/pandas-loc/modin-output.png"&gt;&lt;/p&gt;
&lt;h2&gt;Using Loc with Modin&lt;/h2&gt;
&lt;p&gt;In Modin's pandas API, .loc works identically to the original Pandas. As you can imagine, this is tricky in a distributed dataframe system. There were a lot of new problems to solve:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What machine is a given row label on?&lt;/li&gt;
&lt;li&gt;How do we know if a row is not on any machine and throw an error for the user?&lt;/li&gt;
&lt;li&gt;How do we make this fast?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We solved all three of these by separating the dataframe's data from the Index and storing the Index close to the user for fast lookups with .loc. We maintain an internal mapping from the fast Index to the machine that the row is on. This way we can make the row lookups fast!&lt;/p&gt;
&lt;p&gt;Though .loc is fast in Modin, it is not as fast as Pandas because of the extra layer between the data and the Index. Still, the lookup should be within a few milliseconds of Pandas — and still well within the window of fast interactive performance.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Thanks for reading part one of our ultimate guide to indexing in Pandas (and the third article in our Professional Pandas series). In this article we introduced using Pandas loc to select rows and columns. You should have a good understanding of the different inputs that the .loc index accepts.&lt;/p&gt;
&lt;p&gt;To practice and further improve your skills, try using .loc on your own datasets and see how you can effectively index and slice your data. Don't forget to also review the common gotchas discussed in this tutorial to avoid any pitfalls when using these indexing attributes.&lt;/p&gt;
&lt;p&gt;For more in this series, read &lt;a href="/blog/professional-pandas-assign-method-chaining.html"&gt;the Pandas assign method and chaining&lt;/a&gt; and &lt;a href="/blog/professional-pandas-merge-method.html"&gt;the Pandas merge method&lt;/a&gt;.&lt;/p&gt;</content><category term="misc"/><category term="pandas"/><category term="indexing"/><category term="loc"/></entry><entry><title>Professional Pandas: The Pandas Merge Method</title><link href="https://www.metasnake.com/blog/professional-pandas-merge-method.html" rel="alternate"/><published>2022-11-03T00:00:00-06:00</published><updated>2026-08-12T00:00:00-06:00</updated><author><name>Matt Harrison</name></author><id>tag:www.metasnake.com,2022-11-03:/blog/professional-pandas-merge-method.html</id><summary type="html">&lt;p&gt;Understand pandas merge semantics, join types, validation, and a practical workflow combining river-flow and weather data.&lt;/p&gt;</summary><content type="html">&lt;div class="article-note"&gt;
&lt;strong&gt;Republication note:&lt;/strong&gt; I originally wrote this article for Ponder, where it was published on November 3, 2022. Ponder later removed the post following its acquisition, so I have preserved it here. The Ponder- and Modin-specific code reflects the environment available when the article was written; the pandas concepts remain broadly applicable. &lt;a href="https://web.archive.org/web/20230613201128/https://ponder.io/professional-pandas-the-pandas-merge-method/"&gt;View the archived original.&lt;/a&gt;
&lt;/div&gt;

&lt;figure class="article-figure article-figure--hero"&gt;
&lt;img src="/static/img/blog/pandas-merge/hero.png" width="1200" height="900" alt="Two pandas merging streams of tabular data" decoding="async"&gt;
&lt;figcaption&gt;Combining related datasets safely with the pandas &lt;code&gt;merge&lt;/code&gt; method.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2&gt;Intro&lt;/h2&gt;
&lt;p&gt;In this post, I discuss the relationship between the Pandas merge function (and Pandas merge method), and the Pandas join method, and then show examples of how to merge Pandas dataframes with the merge method. Along the way, I describe two useful merge method parameters: the validate parameter, and the indicator parameter.&lt;/p&gt;
&lt;p&gt;This article is the second in our Professional Pandas blog post series. The goal of this series is to teach best practices about writing professional-grade Pandas code. If you have questions or topics that you would like to dive into, please reach out on Twitter to &lt;a href="https://twitter.com/intent/follow?screen_name=ponderdata"&gt;@ponderdata&lt;/a&gt; or &lt;a href="https://twitter.com/__mharrison__"&gt;@__mharrison__&lt;/a&gt;, and if you’d like to see the notebook version of this blogpost, you can find it on Github &lt;a href="https://github.com/ponder-org/professional-pandas/blob/main/MergeBlogPost.ipynb"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;(Note: This content is modified from the author’s book, &lt;em&gt;Effective Pandas&lt;/em&gt;.)&lt;/p&gt;
&lt;h2&gt;Joining Data&lt;/h2&gt;
&lt;h3&gt;Terminology Refresher: Method vs. Function&lt;/h3&gt;
&lt;p&gt;Pandas often has one, two, three, or even more ways to do something. This paradox of choice can be overwhelming. (Indeed software engineering purists would say “&lt;a href="https://peps.python.org/pep-0020/#:~:text=There%20should%20be%20one%2D%2D,better%20than%20*right*%20now."&gt;There should be one– and preferably only one –obvious way to do it&lt;/a&gt;.”) However, here we are with Pandas joining.&lt;/p&gt;
&lt;p&gt;In short, there is :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;.join&lt;/code&gt; method found on a DataFrame&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;.merge&lt;/code&gt; method found on a DataFrame&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;pd.merge&lt;/code&gt; function found in the Pandas namespace (&lt;code&gt;pd&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;pd.concat&lt;/code&gt; function to horizontally or vertically stack data&lt;/li&gt;
&lt;li&gt;Various methods that align on the index and work similar to some joins (like using &lt;code&gt;df.assign(**other_df)&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4&gt;A Quick Aside on the Python Language&lt;/h4&gt;
&lt;p&gt;A Python class defines methods. Methods are called on an instance of a class. In the Pandas world, we often have a DataFrame (df) or Series (s) instance. We could call the merge method by saying:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;another_df&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;However, there is also a function, merge. Generally, when folks use Pandas they import the library like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pandas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Since pd is the module where the Pandas merge function is available, you can call the merge function like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;another_df&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Some think that in this last example that merge is a method on pd. That is not correct. If we change the import to load the function, we could run the code like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pandas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;merge&lt;/span&gt;

&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;another_df&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you aren’t familiar with the difference between methods and functions and would like to explore more, check out the &lt;a href="https://docs.python.org/3/tutorial/classes.html#:~:text=A%20method%20is%20a%20function,%2C%20sort%2C%20and%20so%20on" target="_blank" rel="noreferrer noopener"&gt;Python tutorial&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;End of the Aside&lt;/h4&gt;
&lt;hr&gt;
&lt;p&gt;From this author's point of view, forget that the Pandas merge function and the join method exist. You can get along just fine only using the merge method (which I will often refer to in this article as .merge with a period in front as a reminder that it needs to be called on the instance).&lt;/p&gt;
&lt;p&gt;In fact, if you dig into the implementation of .join, you will see that it calls the concat or merge functions. Don't waste your brain power trying to keep them straight. Just ignore the merge function and the join method.&lt;/p&gt;
&lt;p&gt;One final note, I wish that .merge was named .join because everyone coming from a database world knows what a join is, but .merge offers a little more functionality, hence my recommendation to favor it.&lt;/p&gt;
&lt;h2&gt;A Short Overview of Joining&lt;/h2&gt;
&lt;p&gt;Feel free to skip this if you are familiar with database joins. It shows the basic joins using some sales data. Our task might be to find products with no sales, sales that don’t have products, or only sales for products that we have information for.&lt;/p&gt;
&lt;p&gt;The supported join types for .merge (specified with the how parameter) are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;'left'&lt;/code&gt; – Keep all values from the merging column DataFrame the method was called on.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;'right'&lt;/code&gt; – Keep all values from the merging column of the &lt;code&gt;right&lt;/code&gt; DataFrame the method was called on.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;'inner'&lt;/code&gt; – Keep the intersection of all values from the merging columns.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;'outer'&lt;/code&gt; – Keep the union of all values from the merging columns.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;'cross'&lt;/code&gt; – For every row in the instance dataframe, combine with every row from the &lt;code&gt;right&lt;/code&gt; DataFrame.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pandas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pd&lt;/span&gt;
&lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;product&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                         &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Cat food&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Sparkling Water&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Apple Fritter&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]})&lt;/span&gt;
&lt;span class="n"&gt;sales&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;product_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                      &lt;span class="s1"&gt;&amp;#39;cost&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;4.99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;.99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;4.99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;4.99&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mf"&gt;.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;7.45&lt;/span&gt;&lt;span class="p"&gt;]})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Left Join&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="c1"&gt;# keep all *id* columns&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;left_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;product_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;how&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;left&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;    id  product     product_id  cost&lt;/span&gt;
&lt;span class="go"&gt;0   1   Cat food    1.0     4.990&lt;/span&gt;
&lt;span class="go"&gt;1   1   Cat food    1.0     4.990&lt;/span&gt;
&lt;span class="go"&gt;2   1   Cat food    1.0     3.992&lt;/span&gt;
&lt;span class="go"&gt;3   3   Sparkling Water 3.0     0.990&lt;/span&gt;
&lt;span class="go"&gt;4   10  Apple Fritter   NaN     NaN&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Right Join&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="c1"&gt;# keep all *product_id* columns&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;left_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;product_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;how&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;right&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;    id  product     product_id  cost&lt;/span&gt;
&lt;span class="go"&gt;0   1.0 Cat food    1       4.990&lt;/span&gt;
&lt;span class="go"&gt;1   3.0 Sparkling Water 3       0.990&lt;/span&gt;
&lt;span class="go"&gt;2   1.0 Cat food    1       4.990&lt;/span&gt;
&lt;span class="go"&gt;3   1.0 Cat food    1       3.992&lt;/span&gt;
&lt;span class="go"&gt;4   NaN NaN     15      7.450&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Inner Join&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;left_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;product_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;how&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;inner&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;    id  product     product_id  cost&lt;/span&gt;
&lt;span class="go"&gt;0   1   Cat food    1       4.990&lt;/span&gt;
&lt;span class="go"&gt;1   1   Cat food    1       4.990&lt;/span&gt;
&lt;span class="go"&gt;2   1   Cat food    1       3.992&lt;/span&gt;
&lt;span class="go"&gt;3   3   Sparkling Water 3       0.990&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Outer Join&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;left_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;product_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;how&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;outer&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;    id  product     product_id  cost&lt;/span&gt;
&lt;span class="go"&gt;0   1.0 Cat food    1.0     4.990&lt;/span&gt;
&lt;span class="go"&gt;1   1.0 Cat food    1.0     4.990&lt;/span&gt;
&lt;span class="go"&gt;2   1.0 Cat food    1.0     3.992&lt;/span&gt;
&lt;span class="go"&gt;3   3.0 Sparkling Water 3.0     0.990&lt;/span&gt;
&lt;span class="go"&gt;4   10.0    Apple Fritter   NaN     NaN&lt;/span&gt;
&lt;span class="go"&gt;5   NaN NaN     15.0        7.450&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Cross Join&lt;/h3&gt;
&lt;p&gt;A merge you might not be aware of is the &lt;em&gt;cross&lt;/em&gt; join. This repeats every row of the dataframe with every row that it is merged with. (So this gets big real fast).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="c1"&gt;# cross join&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;how&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;cross&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;    id  product     product_id  cost&lt;/span&gt;
&lt;span class="go"&gt;0   1   Cat food    1       4.990&lt;/span&gt;
&lt;span class="go"&gt;1   1   Cat food    3       0.990&lt;/span&gt;
&lt;span class="go"&gt;2   1   Cat food    1       4.990&lt;/span&gt;
&lt;span class="go"&gt;3   1   Cat food    1       3.992&lt;/span&gt;
&lt;span class="go"&gt;4   1   Cat food    15      7.450&lt;/span&gt;
&lt;span class="go"&gt;5   3   Sparkling Water 1       4.990&lt;/span&gt;
&lt;span class="go"&gt;6   3   Sparkling Water 3       0.990&lt;/span&gt;
&lt;span class="go"&gt;7   3   Sparkling Water 1       4.990&lt;/span&gt;
&lt;span class="go"&gt;8   3   Sparkling Water 1       3.992&lt;/span&gt;
&lt;span class="go"&gt;9   3   Sparkling Water 15      7.450&lt;/span&gt;
&lt;span class="go"&gt;10  10  Apple Fritter   1       4.990&lt;/span&gt;
&lt;span class="go"&gt;11  10  Apple Fritter   3       0.990&lt;/span&gt;
&lt;span class="go"&gt;12  10  Apple Fritter   1       4.990&lt;/span&gt;
&lt;span class="go"&gt;13  10  Apple Fritter   1       3.992&lt;/span&gt;
&lt;span class="go"&gt;14  10  Apple Fritter   15      7.450&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A cross join might come in hand if you need to create all the permutations of some values. In this example, all ways to select three different values from four or ten.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;values&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]})&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;how&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;cross&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;how&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;cross&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;    values_x    values_y    values&lt;/span&gt;
&lt;span class="go"&gt;0   4       4       4&lt;/span&gt;
&lt;span class="go"&gt;1   4       4       10&lt;/span&gt;
&lt;span class="go"&gt;2   4       10      4&lt;/span&gt;
&lt;span class="go"&gt;3   4       10      10&lt;/span&gt;
&lt;span class="go"&gt;4   10      4       4&lt;/span&gt;
&lt;span class="go"&gt;5   10      4       10&lt;/span&gt;
&lt;span class="go"&gt;6   10      10      4&lt;/span&gt;
&lt;span class="go"&gt;7   10      10      10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Validation Using the Pandas Merge Method&lt;/h2&gt;
&lt;p&gt;I will sometimes use a .pipe method to track the size of my data before and after the merge. If you are doing a lot of merges, this will be a snippet of code you will want to keep around.&lt;/p&gt;
&lt;p&gt;(Check out the article Professional Pandas: The Pandas Assign Method for more examples of the .pipe method.)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;debug_shape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a_df&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;a_df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a_df&lt;/span&gt;

&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;debug_shape&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;before merge&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;left_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;product_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;how&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;outer&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;debug_shape&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;after merge&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;(3, 2) before merge&lt;/span&gt;
&lt;span class="go"&gt;(6, 4) after merge&lt;/span&gt;
&lt;span class="go"&gt;    id  product     product_id  cost&lt;/span&gt;
&lt;span class="go"&gt;0   1.0 Cat food    1.0     4.990&lt;/span&gt;
&lt;span class="go"&gt;1   1.0 Cat food    1.0     4.990&lt;/span&gt;
&lt;span class="go"&gt;2   1.0 Cat food    1.0     3.992&lt;/span&gt;
&lt;span class="go"&gt;3   3.0 Sparkling Water 3.0     0.990&lt;/span&gt;
&lt;span class="go"&gt;4   10.0    Apple Fritter   NaN     NaN&lt;/span&gt;
&lt;span class="go"&gt;5   NaN NaN     15.0        7.450&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A very nice feature of the Pandas merge method is the validate parameter. It allows us to specify if our merge should be one to one ('1:1'), one to many ('1:m'), many to one ('m:1'), or many to many ('m:m').&lt;/p&gt;
&lt;p&gt;If your data grows much faster after a merge that might be because you are merging on duplicate values. In our example, the product_id repeats in the products DataFrame. If we were expecting only a single row for the Cat food product and one row from sales for each row from product, we could pass in validate='1:1' parameter.&lt;/p&gt;
&lt;p&gt;In this case, Pandas complains that the entries from sales are not unique. This is because there were multiple sales for the Cat food product:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;left_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;product_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;how&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;outer&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;        &lt;span class="n"&gt;validate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;1:1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;---------------------------------------------------------------------------&lt;/span&gt;
&lt;span class="go"&gt;MergeError                                Traceback (most recent call last)&lt;/span&gt;
&lt;span class="go"&gt; in&lt;/span&gt;
&lt;span class="go"&gt;      1 (products&lt;/span&gt;
&lt;span class="go"&gt;      2  .merge(sales, left_on=&amp;#39;id&amp;#39;, right_on=&amp;#39;product_id&amp;#39;, how=&amp;#39;outer&amp;#39;,&lt;/span&gt;
&lt;span class="go"&gt;----&amp;gt; 3         validate=&amp;#39;1:1&amp;#39;)&lt;/span&gt;
&lt;span class="go"&gt;      4 )&lt;/span&gt;

&lt;span class="go"&gt;3 frames&lt;/span&gt;
&lt;span class="go"&gt;/usr/local/lib/python3.7/dist-packages/pandas/core/reshape/merge.py in _validate(self, validate)&lt;/span&gt;
&lt;span class="go"&gt;   1428             elif not right_unique:&lt;/span&gt;
&lt;span class="go"&gt;   1429                 raise MergeError(&lt;/span&gt;
&lt;span class="go"&gt;-&amp;gt; 1430                     &amp;quot;Merge keys are not unique in right dataset; not a one-to-one merge&amp;quot;&lt;/span&gt;
&lt;span class="go"&gt;   1431                 )&lt;/span&gt;
&lt;span class="go"&gt;   1432&lt;/span&gt;

&lt;span class="go"&gt;MergeError: Merge keys are not unique in right dataset; not a one-to-one merge&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We would need to use validate='1:m' on this example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;left_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;product_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;how&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;outer&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;        &lt;span class="n"&gt;validate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;1:m&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;    id  product     product_id  cost&lt;/span&gt;
&lt;span class="go"&gt;0   1.0 Cat food    1.0     4.990&lt;/span&gt;
&lt;span class="go"&gt;1   1.0 Cat food    1.0     4.990&lt;/span&gt;
&lt;span class="go"&gt;2   1.0 Cat food    1.0     3.992&lt;/span&gt;
&lt;span class="go"&gt;3   3.0 Sparkling Water 3.0     0.990&lt;/span&gt;
&lt;span class="go"&gt;4   10.0    Apple Fritter   NaN     NaN&lt;/span&gt;
&lt;span class="go"&gt;5   NaN NaN     15.0        7.450&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(Note that specifying validate='m:m' can't ever fail, but it could be a nice indicator to whoever reads the code next.)&lt;/p&gt;
&lt;p&gt;One more parameter to be aware of is the indicator parameter. This allows us to create a new column indicating which DataFrame the resulting row came from. In this example we specify that the new column should be named side:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;left_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;product_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;how&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;outer&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;        &lt;span class="n"&gt;indicator&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;side&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;    id  product     product_id  cost    side&lt;/span&gt;
&lt;span class="go"&gt;0   1.0 Cat food    1.0     4.990   both&lt;/span&gt;
&lt;span class="go"&gt;1   1.0 Cat food    1.0     4.990   both&lt;/span&gt;
&lt;span class="go"&gt;2   1.0 Cat food    1.0     3.992   both&lt;/span&gt;
&lt;span class="go"&gt;3   3.0 Sparkling Water 3.0     0.990   both&lt;/span&gt;
&lt;span class="go"&gt;4   10.0    Apple Fritter   NaN     NaN left_only&lt;/span&gt;
&lt;span class="go"&gt;5   NaN NaN     15.0        7.450   right_only&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Example: Joining Dirty Devil Flow and Weather Data Using the Pandas Merge Method&lt;/h2&gt;
&lt;p&gt;Now let’s look at a real-world example.&lt;/p&gt;
&lt;p&gt;We are going to explore data from the Dirty Devil river. This is a river in Utah that the author had some interest in floating down. However, it is only floatable during a small period of time each year. This analysis was part of his attempt to determine when would be a good time to float down this river.&lt;/p&gt;
&lt;p&gt;I have some historic data about the flow of the Dirty Devil river on my Github. Let’s load the flow (cubic feet per second, or cfs) and gage height data. In this case we will leave the datetime column as a column and not use it for the index:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pandas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pd&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;https://github.com/mattharrison/datasets/raw/master&amp;#39;&lt;/span&gt;\
&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="s1"&gt;&amp;#39;/data/dirtydevil.txt&amp;#39;&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;skiprows&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;34&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                 &lt;span class="n"&gt;sep&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;to_denver_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time_col&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tz_col&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;     &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tz_col&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tz_col&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;MDT&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;MST7MDT&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;     &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tz_col&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;     &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;time_col&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;     &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_datetime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;         &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tz_localize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ambiguous&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;         &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tz_convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;America/Denver&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;tweak_river&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;     &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;to_denver_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;datetime&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;tz_cd&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;     &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;144166_00060&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;cfs&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                      &lt;span class="s1"&gt;&amp;#39;144167_00065&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;gage_height&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;dd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tweak_river&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;dd&lt;/span&gt;
&lt;span class="go"&gt;/usr/local/lib/python3.7/dist-packages/IPython/core/interactiveshell.py:3326: DtypeWarning: Columns (7) have mixed types.Specify dtype option on import or set low_memory=False.&lt;/span&gt;
&lt;span class="go"&gt;  exec(code_obj, self.user_global_ns, self.user_ns)&lt;/span&gt;
&lt;span class="go"&gt;    agency_cd   site_no     datetime            tz_cd   cfs 144166_00060_cd gage_height 144167_00065_cd&lt;/span&gt;
&lt;span class="go"&gt;0   USGS        9333500     2001-05-07 01:00:00-06:00   MDT 71.00   A:[91]      NaN     NaN&lt;/span&gt;
&lt;span class="go"&gt;1   USGS        9333500     2001-05-07 01:15:00-06:00   MDT 71.00   A:[91]      NaN     NaN&lt;/span&gt;
&lt;span class="go"&gt;2   USGS        9333500     2001-05-07 01:30:00-06:00   MDT 71.00   A:[91]      NaN     NaN&lt;/span&gt;
&lt;span class="go"&gt;3   USGS        9333500     2001-05-07 01:45:00-06:00   MDT 70.00   A:[91]      NaN     NaN&lt;/span&gt;
&lt;span class="go"&gt;4   USGS        9333500     2001-05-07 02:00:00-06:00   MDT 70.00   A:[91]      NaN     NaN&lt;/span&gt;
&lt;span class="go"&gt;... ...     ...     ...             ... ... ...     ...     ...&lt;/span&gt;
&lt;span class="go"&gt;539300  USGS        9333500     2020-09-28 08:30:00-06:00   MDT 9.53    P       6.16        P&lt;/span&gt;
&lt;span class="go"&gt;539301  USGS        9333500     2020-09-28 08:45:00-06:00   MDT 9.20    P       6.15        P&lt;/span&gt;
&lt;span class="go"&gt;539302  USGS        9333500     2020-09-28 09:00:00-06:00   MDT 9.20    P       6.15        P&lt;/span&gt;
&lt;span class="go"&gt;539303  USGS        9333500     2020-09-28 09:15:00-06:00   MDT 9.20    P       6.15        P&lt;/span&gt;
&lt;span class="go"&gt;539304  USGS        9333500     2020-09-28 09:30:00-06:00   MDT 9.20    P       6.15        P&lt;/span&gt;
&lt;span class="go"&gt;539305 rows × 8 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I’m also going to load some &lt;a href="https://www.ncdc.noaa.gov/cdo-web"&gt;meteorological data from Hanksville, Utah&lt;/a&gt;, a city nearby the river. We will then use the Pandas merge method to join both datasets together so we have flow data as well as temperature and precipitation information.&lt;/p&gt;
&lt;p&gt;Some of the columns that are interesting are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DATE – Date&lt;/li&gt;
&lt;li&gt;PRCP – Precipitation in inches&lt;/li&gt;
&lt;li&gt;TMIN – Minimum temperature (F) for day&lt;/li&gt;
&lt;li&gt;TMAX – Maximum temperature (F) for day&lt;/li&gt;
&lt;li&gt;TOBS – Observed temperature (F) when measurement made&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;https://github.com/mattharrison/datasets/raw/master/data/&amp;#39;&lt;/span&gt;\
&lt;span class="gp"&gt;... &lt;/span&gt;      &lt;span class="s1"&gt;&amp;#39;hanksville.csv&amp;#39;&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;temp_df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;tweak_temp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;           &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_datetime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tz_localize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;America/Denver&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ambiguous&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;           &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[:,[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DATE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;PRCP&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TMIN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TMAX&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TOBS&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;temp_df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tweak_temp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp_df&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;temp_df&lt;/span&gt;
&lt;span class="go"&gt;    DATE                PRCP    TMIN    TMAX    TOBS&lt;/span&gt;
&lt;span class="go"&gt;0   2000-01-01 00:00:00-07:00   0.02    21.0    43.0    28.0&lt;/span&gt;
&lt;span class="go"&gt;1   2000-01-02 00:00:00-07:00   0.03    24.0    39.0    24.0&lt;/span&gt;
&lt;span class="go"&gt;2   2000-01-03 00:00:00-07:00   0.00    7.0 39.0    18.0&lt;/span&gt;
&lt;span class="go"&gt;3   2000-01-04 00:00:00-07:00   0.00    5.0 39.0    25.0&lt;/span&gt;
&lt;span class="go"&gt;4   2000-01-05 00:00:00-07:00   0.00    10.0    44.0    22.0&lt;/span&gt;
&lt;span class="go"&gt;... ...             ... ... ... ...&lt;/span&gt;
&lt;span class="go"&gt;6843    2020-09-20 00:00:00-06:00   0.00    46.0    92.0    83.0&lt;/span&gt;
&lt;span class="go"&gt;6844    2020-09-21 00:00:00-06:00   0.00    47.0    92.0    84.0&lt;/span&gt;
&lt;span class="go"&gt;6845    2020-09-22 00:00:00-06:00   0.00    54.0    84.0    77.0&lt;/span&gt;
&lt;span class="go"&gt;6846    2020-09-23 00:00:00-06:00   0.00    47.0    91.0    87.0&lt;/span&gt;
&lt;span class="go"&gt;6847    2020-09-24 00:00:00-06:00   0.00    43.0    94.0    88.0&lt;/span&gt;
&lt;span class="go"&gt;6848 rows × 5 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Joining Data&lt;/h3&gt;
&lt;p&gt;Let's use the Pandas merge method to merge by date. This method will try to merge by columns that have the same name, but our dataframes don't have overlapping column names. The dd dataframe has a datetime column and temp_df has a DATE column. We can use the left_on and right_on parameters to help it know how to align the data. The merge method tries to do an inner join by default. That means that rows with values that are the same in the merge columns will be joined together:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dd&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp_df&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;left_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;datetime&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DATE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;    agency_cd   site_no     datetime            tz_cd   cfs 144166_00060_cd gage_height 144167_00065_cd DATE                PRCP    TMIN    TMAX    TOBS&lt;/span&gt;
&lt;span class="go"&gt;0   USGS        9333500     2001-05-08 00:00:00-06:00   MDT 75.00   A:[91]      NaN     NaN     2001-05-08 00:00:00-06:00   0.0 43.0    85.0    58.0&lt;/span&gt;
&lt;span class="go"&gt;1   USGS        9333500     2001-05-09 00:00:00-06:00   MDT 64.00   A:[91]      NaN     NaN     2001-05-09 00:00:00-06:00   0.0 36.0    92.0    64.0&lt;/span&gt;
&lt;span class="go"&gt;2   USGS        9333500     2001-05-10 00:00:00-06:00   MDT 54.00   A:[91]      NaN     NaN     2001-05-10 00:00:00-06:00   0.0 50.0    92.0    67.0&lt;/span&gt;
&lt;span class="go"&gt;3   USGS        9333500     2001-05-11 00:00:00-06:00   MDT 56.00   A:[91]      NaN     NaN     2001-05-11 00:00:00-06:00   0.0 46.0    87.0    60.0&lt;/span&gt;
&lt;span class="go"&gt;4   USGS        9333500     2001-05-12 00:00:00-06:00   MDT 49.00   A:[91]      NaN     NaN     2001-05-12 00:00:00-06:00   0.0 45.0    93.0    72.0&lt;/span&gt;
&lt;span class="go"&gt;... ...     ...     ...             ... ... ...     ...     ...     ...             ... ... ... ...&lt;/span&gt;
&lt;span class="go"&gt;4968    USGS        9333500     2020-09-20 00:00:00-06:00   MDT 6.04    P       6.04        P       2020-09-20 00:00:00-06:00   0.0 46.0    92.0    83.0&lt;/span&gt;
&lt;span class="go"&gt;4969    USGS        9333500     2020-09-21 00:00:00-06:00   MDT 6.83    P       6.07        P       2020-09-21 00:00:00-06:00   0.0 47.0    92.0    84.0&lt;/span&gt;
&lt;span class="go"&gt;4970    USGS        9333500     2020-09-22 00:00:00-06:00   MDT 6.83    P       6.07        P       2020-09-22 00:00:00-06:00   0.0 54.0    84.0    77.0&lt;/span&gt;
&lt;span class="go"&gt;4971    USGS        9333500     2020-09-23 00:00:00-06:00   MDT 7.68    P       6.10        P       2020-09-23 00:00:00-06:00   0.0 47.0    91.0    87.0&lt;/span&gt;
&lt;span class="go"&gt;4972    USGS        9333500     2020-09-24 00:00:00-06:00   MDT 9.86    P       6.17        P       2020-09-24 00:00:00-06:00   0.0 43.0    94.0    88.0&lt;/span&gt;
&lt;span class="go"&gt;4973 rows × 13 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This appears to have worked, but is somewhat problematic. Remember that the dd dataset has a 15-minute frequency, but temp_df only has daily data, so we are only using the value from midnight. We should probably use our resampling skills to calculate the median flow value for each date and then merge. In that case we will want to use the index of the grouped data to merge, so we specify left_index=True:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dd&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grouper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;datetime&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;freq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;D&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;median&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp_df&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;left_index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DATE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;    site_no     cfs     gage_height DATE                PRCP    TMIN    TMAX    TOBS&lt;/span&gt;
&lt;span class="go"&gt;492 9333500.0   71.50       NaN     2001-05-07 00:00:00-06:00   0.0 41.0    82.0    55.0&lt;/span&gt;
&lt;span class="go"&gt;493 9333500.0   69.00       NaN     2001-05-08 00:00:00-06:00   0.0 43.0    85.0    58.0&lt;/span&gt;
&lt;span class="go"&gt;494 9333500.0   63.50       NaN     2001-05-09 00:00:00-06:00   0.0 36.0    92.0    64.0&lt;/span&gt;
&lt;span class="go"&gt;495 9333500.0   55.00       NaN     2001-05-10 00:00:00-06:00   0.0 50.0    92.0    67.0&lt;/span&gt;
&lt;span class="go"&gt;496 9333500.0   55.00       NaN     2001-05-11 00:00:00-06:00   0.0 46.0    87.0    60.0&lt;/span&gt;
&lt;span class="go"&gt;... ...     ...     ...     ...             ... ... ... ...&lt;/span&gt;
&lt;span class="go"&gt;6843    9333500.0   6.83        6.07        2020-09-20 00:00:00-06:00   0.0 46.0    92.0    83.0&lt;/span&gt;
&lt;span class="go"&gt;6844    9333500.0   6.83        6.07        2020-09-21 00:00:00-06:00   0.0 47.0    92.0    84.0&lt;/span&gt;
&lt;span class="go"&gt;6845    9333500.0   7.39        6.09        2020-09-22 00:00:00-06:00   0.0 54.0    84.0    77.0&lt;/span&gt;
&lt;span class="go"&gt;6846    9333500.0   7.97        6.11        2020-09-23 00:00:00-06:00   0.0 47.0    91.0    87.0&lt;/span&gt;
&lt;span class="go"&gt;6847    9333500.0   9.53        6.16        2020-09-24 00:00:00-06:00   0.0 43.0    94.0    88.0&lt;/span&gt;
&lt;span class="go"&gt;6356 rows × 8 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That looks better (and gives us a few more rows of data).&lt;/p&gt;
&lt;h3&gt;Validating Joined Data&lt;/h3&gt;
&lt;p&gt;Let's validate that we had a one-to-one join, i.e. each date from the flow data matched up with a single date from the temperature data. We can use the validate parameter to do this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dd&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grouper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;datetime&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;freq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;D&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;median&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp_df&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;left_index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DATE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;how&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;inner&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;        &lt;span class="n"&gt;validate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;1:1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;    site_no     cfs gage_height DATE                PRCP    TMIN    TMAX    TOBS&lt;/span&gt;
&lt;span class="go"&gt;492 9333500.0   71.50   NaN     2001-05-07 00:00:00-06:00   0.0 41.0    82.0    55.0&lt;/span&gt;
&lt;span class="go"&gt;493 9333500.0   69.00   NaN     2001-05-08 00:00:00-06:00   0.0 43.0    85.0    58.0&lt;/span&gt;
&lt;span class="go"&gt;494 9333500.0   63.50   NaN     2001-05-09 00:00:00-06:00   0.0 36.0    92.0    64.0&lt;/span&gt;
&lt;span class="go"&gt;495 9333500.0   55.00   NaN     2001-05-10 00:00:00-06:00   0.0 50.0    92.0    67.0&lt;/span&gt;
&lt;span class="go"&gt;496 9333500.0   55.00   NaN     2001-05-11 00:00:00-06:00   0.0 46.0    87.0    60.0&lt;/span&gt;
&lt;span class="go"&gt;... ...     ... ...     ...             ... ... ... ...&lt;/span&gt;
&lt;span class="go"&gt;6843    9333500.0   6.83    6.07        2020-09-20 00:00:00-06:00   0.0 46.0    92.0    83.0&lt;/span&gt;
&lt;span class="go"&gt;6844    9333500.0   6.83    6.07        2020-09-21 00:00:00-06:00   0.0 47.0    92.0    84.0&lt;/span&gt;
&lt;span class="go"&gt;6845    9333500.0   7.39    6.09        2020-09-22 00:00:00-06:00   0.0 54.0    84.0    77.0&lt;/span&gt;
&lt;span class="go"&gt;6846    9333500.0   7.97    6.11        2020-09-23 00:00:00-06:00   0.0 47.0    91.0    87.0&lt;/span&gt;
&lt;span class="go"&gt;6847    9333500.0   9.53    6.16        2020-09-24 00:00:00-06:00   0.0 43.0    94.0    88.0&lt;/span&gt;
&lt;span class="go"&gt;6356 rows × 8 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Because this did not raise a MergeError, we know that our data had non-repeating date fields.&lt;/p&gt;
&lt;h3&gt;Visualization of Data Joined with the Pandas Merge Method&lt;/h3&gt;
&lt;p&gt;I'm a big fan of visualization. Let's visualize the merged time series. We will add on to our merge chain, stick the date in the index (so that we can plot it on the x-axis), pull out the years from 2014 forward, use the cfs (cubic feet per second), gage_height, PRCP, and TOBS columns, interpolate the missing values, do a rolling 15-day average, and plot the result in their own subplot:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;matplotlib.pyplot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;plt&lt;/span&gt;
&lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subplots&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dpi&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dd&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grouper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;datetime&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;freq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;D&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;median&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp_df&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;left_index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DATE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;how&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;inner&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;validate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;1:1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DATE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2014&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:,[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;cfs&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;gage_height&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;PRCP&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TOBS&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;interpolate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rolling&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subplots&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;suptitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Dirty Devil Metrics (15-day average)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tight_layout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="Dirty Devil River metrics with a 15-day rolling average" src="/static/img/blog/pandas-merge/river-flow-average.png"&gt;&lt;/p&gt;
&lt;p&gt;Here’s another plot that is kind of cool once you piece together what is happening. It is a scatterplot of temperature against river flow. I’m coloring this by month of the year. You can see the start of the year at the bottom of the plot. As the year progresses and the temperature warms up, the &lt;em&gt;cfs&lt;/em&gt; goes up a little, and then as summer hits, the river almost dries up. During the fall, it starts to cool off and the river starts running higher:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subplots&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dpi&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;dd2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dd&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grouper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;datetime&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;freq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;D&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;median&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp_df&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;left_index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right_on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DATE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;how&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;inner&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;validate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;1:1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;cfs &amp;lt; 400&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dd2&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scatter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;cfs&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;TOBS&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dd2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;hsv&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alpha&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Observation Temperature (TOBS) &amp;#39;&lt;/span&gt;
   &lt;span class="s1"&gt;&amp;#39;vs River Flow (cubic feet per sec)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;Colored by Month&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="Observed temperature compared with Dirty Devil River flow by month" src="/static/img/blog/pandas-merge/temperature-vs-river-flow.png"&gt;&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;Data can often have more utility if we combine it with other data. In the '70s, relational algebra was invented to describe various joins among tabular data. The Pandas merge method of the DataFrame lets us apply these operations to tabular data in the Pandas world. This post explored using the Pandas merge method and the parameters you can use to validate your joining logic.&lt;/p&gt;
&lt;p&gt;We would love to hear your feedback. Was this helpful? Did you learn anything new? Tag &lt;a href="https://twitter.com/intent/follow?screen_name=ponderdata"&gt;@ponderdata&lt;/a&gt; and &lt;a href="https://twitter.com/__mharrison__"&gt;@__mharrison__&lt;/a&gt; on Twitter with your insights, and follow both for more content like this. And feel free to suggest new topics you’d like us to dive into for our next Professional Pandas blog post!&lt;/p&gt;</content><category term="misc"/><category term="pandas"/><category term="merge"/><category term="joins"/></entry><entry><title>Professional Pandas: The Pandas Assign Method and Chaining</title><link href="https://www.metasnake.com/blog/professional-pandas-assign-method-chaining.html" rel="alternate"/><published>2022-08-24T00:00:00-06:00</published><updated>2026-08-12T00:00:00-06:00</updated><author><name>Matt Harrison</name></author><id>tag:www.metasnake.com,2022-08-24:/blog/professional-pandas-assign-method-chaining.html</id><summary type="html">&lt;p&gt;Learn why the pandas assign method enables readable method chains, avoids SettingWithCopyWarning, and simplifies creating dependent columns.&lt;/p&gt;</summary><content type="html">&lt;div class="article-note"&gt;
&lt;strong&gt;Republication note:&lt;/strong&gt; I originally wrote this article for Ponder, where it was published on August 24, 2022. Ponder later removed the post following its acquisition, so I have preserved it here. The Ponder- and Modin-specific code reflects the environment available when the article was written; the pandas concepts remain broadly applicable. &lt;a href="https://web.archive.org/web/20230613201128/https://ponder.io/professional-pandas-the-pandas-assign-method-and-chaining/"&gt;View the archived original.&lt;/a&gt;
&lt;/div&gt;

&lt;figure class="article-figure article-figure--hero"&gt;
&lt;img src="/static/img/blog/pandas-assign/hero.jpg" width="1024" height="768" alt="Golden chain links shaped like pandas" decoding="async"&gt;
&lt;figcaption&gt;Using &lt;code&gt;.assign&lt;/code&gt; to build readable pandas method chains.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2&gt;Intro&lt;/h2&gt;
&lt;p&gt;This article on the Pandas assign method is the first in a series of Professional Pandas blog posts that we will put out over the coming months. The goal of this series is to teach best practices about writing professional-grade pandas code. If you have questions or topics that you would like to dive into, please reach out on Twitter to &lt;a href="https://twitter.com/ponderdata"&gt;@ponderdata&lt;/a&gt; or &lt;a href="https://twitter.com/__mharrison__"&gt;@__mharrison__&lt;/a&gt;, and if you’d like to see the notebook version of this blogpost, you can find it on Github &lt;a href="https://github.com/ponder-org/professional-pandas/blob/main/AssignBlogPost.ipynb"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In my opinion, one of the most underutilized methods in Pandas is the .assign method. My take (which may be extreme) is that .assign is the one true way to create a new column or update an existing column.&lt;/p&gt;
&lt;p&gt;For those who don't want to read the whole article, here are my reasons for preferring .assign:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You get around the dreaded &lt;code&gt;SettingWithCopyWarning&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;It enables chaining&lt;/li&gt;
&lt;li&gt;It forces you to write readable code that you, your future self, and your colleagues will appreciate&lt;/li&gt;
&lt;li&gt;It eases otherwise difficult operations&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I get that this "only use .assign" may be extreme, but I encourage you to try it out first before you knock it. If you still hate it after trying it out, please send me your before and after code, because I am curious what happened.&lt;/p&gt;
&lt;p&gt;For those still reading, let’s jump in!&lt;/p&gt;
&lt;h2&gt;Load data&lt;/h2&gt;
&lt;p&gt;To explore uses of the Pandas assign method, I'm going to use a dataset of meteorological data from a ski resort called Alta.&lt;/p&gt;
&lt;p&gt;This data set has some descriptive columns and some daily facts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;PRCP&lt;/em&gt; – liquid precipitation (inches)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;SNOW&lt;/em&gt; – snowfall (inches)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;SNWD&lt;/em&gt; – snow on the ground (inches)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;TMAX&lt;/em&gt; – maximum temperature (F)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;TMIN&lt;/em&gt; – minimum temperature (F)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;TOBS&lt;/em&gt; – temperature (F) at observation time&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let's load the data and create a tweak_alta function to pull out the columns we want.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;modin.pandas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pd&lt;/span&gt;

&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;https://github.com/mattharrison/datasets/raw/master&amp;#39;&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                 &lt;span class="s1"&gt;&amp;#39;/data/alta-noaa-1980-2019.csv&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parse_dates&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DATE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;tweak_alta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STATION&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;NAME&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;LATITUDE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;LONGITUDE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;ELEVATION&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;DATE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                     &lt;span class="s1"&gt;&amp;#39;PRCP&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;SNOW&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;SNWD&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TMAX&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TMIN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TOBS&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;           &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;alta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tweak_alta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;alta&lt;/span&gt;
&lt;span class="go"&gt;STATION NAME    LATITUDE    LONGITUDE   ELEVATION   DATE    PRCP    SNOW    SNWD    TMAX    TMIN    TOBS&lt;/span&gt;
&lt;span class="go"&gt;0   USC00420072 ALTA, UT US 40.5905 -111.6369   2660.9  1980-01-01  0.10    2.0 29.0    38.0    25.0    25.0&lt;/span&gt;
&lt;span class="go"&gt;1   USC00420072 ALTA, UT US 40.5905 -111.6369   2660.9  1980-01-02  0.43    3.0 34.0    27.0    18.0    18.0&lt;/span&gt;
&lt;span class="go"&gt;2   USC00420072 ALTA, UT US 40.5905 -111.6369   2660.9  1980-01-03  0.09    1.0 30.0    27.0    12.0    18.0&lt;/span&gt;
&lt;span class="go"&gt;3   USC00420072 ALTA, UT US 40.5905 -111.6369   2660.9  1980-01-04  0.00    0.0 30.0    31.0    18.0    27.0&lt;/span&gt;
&lt;span class="go"&gt;4   USC00420072 ALTA, UT US 40.5905 -111.6369   2660.9  1980-01-05  0.00    0.0 30.0    34.0    26.0    34.0&lt;/span&gt;
&lt;span class="go"&gt;... ... ... ... ... ... ... ... ... ... ... ... ...&lt;/span&gt;
&lt;span class="go"&gt;14155   USC00420072 ALTA, UT US 40.5905 -111.6369   2660.9  2019-09-03  0.01    0.0 0.0 74.0    57.0    73.0&lt;/span&gt;
&lt;span class="go"&gt;14156   USC00420072 ALTA, UT US 40.5905 -111.6369   2660.9  2019-09-04  0.00    0.0 0.0 77.0    52.0    74.0&lt;/span&gt;
&lt;span class="go"&gt;14157   USC00420072 ALTA, UT US 40.5905 -111.6369   2660.9  2019-09-05  0.00    0.0 0.0 76.0    54.0    65.0&lt;/span&gt;
&lt;span class="go"&gt;14158   USC00420072 ALTA, UT US 40.5905 -111.6369   2660.9  2019-09-06  0.07    0.0 0.0 66.0    52.0    60.0&lt;/span&gt;
&lt;span class="go"&gt;14159   USC00420072 ALTA, UT US 40.5905 -111.6369   2660.9  2019-09-07  0.00    0.0 0.0 68.0    45.0    64.0&lt;/span&gt;
&lt;span class="go"&gt;14160 rows x 12 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(Notice that we are using the Modin library above, import modin.pandas as pd. However, this same code will run with the Pandas library by only changing that line to import pandas as pd.)&lt;/p&gt;
&lt;h2&gt;Create a new column&lt;/h2&gt;
&lt;p&gt;A common operation is adding a column to a dataframe.&lt;/p&gt;
&lt;p&gt;Most create a column by using index assignment. This is convenient because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It looks like a dictionary operation that Python users are used to&lt;/li&gt;
&lt;li&gt;It (usually) overwrites the data making it a low overhead operation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are also some disadvantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It might cause a &lt;code&gt;SettingWithCopyWarning&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;It does not return a dataframe. Hence it cannot be used in a chain of operations&lt;/li&gt;
&lt;li&gt;Many users create intermediate variables (and call &lt;code&gt;.copy&lt;/code&gt;on the dataframe), thus removing the low overhead benefit&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Below I will create a copy of the dataframe, alta_bad, and add a new column, PRCP_CM, that stores daily precipitation measured in centimeters. This is how many folks add columns to dataframes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;alta_bad&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;alta_bad&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;PRCP_CM&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alta_bad&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PRCP&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;2.54&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Using Pandas assign instead&lt;/h2&gt;
&lt;p&gt;I prefer using the .assign method to create new columns. It also has some advantages and disadvantages. The advantages are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It returns a new dataframe so you can chain operations&lt;/li&gt;
&lt;li&gt;It sidesteps the &lt;code&gt;SettingWithCopyWarning&lt;/code&gt; completely. (As in, you will NEVER see it or deal with it).&lt;/li&gt;
&lt;li&gt;It makes your code read like a recipe&lt;/li&gt;
&lt;li&gt;It forces you to think about the order of column creation for dependent columns&lt;/li&gt;
&lt;li&gt;It allows you to create multiple columns&lt;/li&gt;
&lt;li&gt;It lets you merge in a dataframe&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The disadvantages of using the .assign method in Pandas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It copies the dataframe (in the Pandas implementation)&lt;/li&gt;
&lt;li&gt;Because it uses keyword parameters, you are limited to column names that are valid Python parameter names (unless you do &lt;code&gt;**&lt;/code&gt; unpacking with a dictionary that has the column stored as a key)&lt;/li&gt;
&lt;li&gt;It requires knowledge of &lt;code&gt;lambda functions if you want to work on intermediate dataframes&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here is how I would add the PRCP_CM column using .assign:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alta&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PRCP_CM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;alta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PRCP&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;2.54&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;    STATION NAME    LATITUDE    LONGITUDE   ELEVATION   DATE    PRCP    SNOW    SNWD    TMAX    TMIN    TOBS    PRCP_CM&lt;/span&gt;
&lt;span class="go"&gt;0   USC00420072 ALTA, UT US 40.5905 -111.6369   2660.9  1980-01-01  0.10    2.0 29.0    38.0    25.0    25.0    0.2540&lt;/span&gt;
&lt;span class="go"&gt;1   USC00420072 ALTA, UT US 40.5905 -111.6369   2660.9  1980-01-02  0.43    3.0 34.0    27.0    18.0    18.0    1.0922&lt;/span&gt;
&lt;span class="go"&gt;2   USC00420072 ALTA, UT US 40.5905 -111.6369   2660.9  1980-01-03  0.09    1.0 30.0    27.0    12.0    18.0    0.2286&lt;/span&gt;
&lt;span class="go"&gt;3   USC00420072 ALTA, UT US 40.5905 -111.6369   2660.9  1980-01-04  0.00    0.0 30.0    31.0    18.0    27.0    0.0000&lt;/span&gt;
&lt;span class="go"&gt;4   USC00420072 ALTA, UT US 40.5905 -111.6369   2660.9  1980-01-05  0.00    0.0 30.0    34.0    26.0    34.0    0.0000&lt;/span&gt;
&lt;span class="go"&gt;... ... ... ... ... ... ... ... ... ... ... ... ... ...&lt;/span&gt;
&lt;span class="go"&gt;14155   USC00420072 ALTA, UT US 40.5905 -111.6369   2660.9  2019-09-03  0.01    0.0 0.0 74.0    57.0    73.0    0.0254&lt;/span&gt;
&lt;span class="go"&gt;14156   USC00420072 ALTA, UT US 40.5905 -111.6369   2660.9  2019-09-04  0.00    0.0 0.0 77.0    52.0    74.0    0.0000&lt;/span&gt;
&lt;span class="go"&gt;14157   USC00420072 ALTA, UT US 40.5905 -111.6369   2660.9  2019-09-05  0.00    0.0 0.0 76.0    54.0    65.0    0.0000&lt;/span&gt;
&lt;span class="go"&gt;14158   USC00420072 ALTA, UT US 40.5905 -111.6369   2660.9  2019-09-06  0.07    0.0 0.0 66.0    52.0    60.0    0.1778&lt;/span&gt;
&lt;span class="go"&gt;14159   USC00420072 ALTA, UT US 40.5905 -111.6369   2660.9  2019-09-07  0.00    0.0 0.0 68.0    45.0    64.0    0.0000&lt;/span&gt;
&lt;span class="go"&gt;14160 rows x 13 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Chaining interlude&lt;/h2&gt;
&lt;p&gt;Let's take a break from discussing the .assign method for a moment.&lt;/p&gt;
&lt;p&gt;This section might be controversial. My advice is to hold back your cringe reflex and hear me out. (Also, I would advise you to try out this style on your own code. My experience is that many who initially are repulsed by this have a wonderful epiphany when they try it, and it completely changes the way they write Pandas code.)&lt;/p&gt;
&lt;p&gt;Folks who read my book, &lt;em&gt;Effective Pandas&lt;/em&gt;, or follow my Pandas content know that I’m a big proponent of &lt;em&gt;chaining&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;What is chaining?&lt;/p&gt;
&lt;p&gt;Chaining is writing a series of operations to a dataframe to manipulate it. Each operation works on the result of the previous operation.&lt;/p&gt;
&lt;p&gt;One complaint I have against the many “learn to use Pandas” blog posts scattered about the internet is that they teach a method in isolation. In practice, you almost never perform an operation to data in isolation. There are multiple operations that are required to change column types, update values, deal with missing data, aggregate, plot, etc. But generally, you only care about the end result. The intermediate data along the way is not important.&lt;/p&gt;
&lt;p&gt;Let’s assume that you wanted to summarize the Alta data by week. You might:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Filter out columns&lt;/li&gt;
&lt;li&gt;Group by the date&lt;/li&gt;
&lt;li&gt;Aggregate different columns (by different functions)&lt;/li&gt;
&lt;li&gt;Create a new column with the &lt;em&gt;NAME&lt;/em&gt; of the ski resort&lt;/li&gt;
&lt;li&gt;Create a new column with the weekly range&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s also assume that the resort was named “Alta Ski Resort” before year 2000 and just “Alta” after.&lt;/p&gt;
&lt;p&gt;Most folks would write code like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;my_cols&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STATION&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;NAME&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;LATITUDE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;LONGITUDE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;ELEVATION&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;DATE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;           &lt;span class="s1"&gt;&amp;#39;PRCP&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;SNOW&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;SNWD&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TMAX&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TMIN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TOBS&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alta&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;my_cols&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;grouped_df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grouper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DATE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;freq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;W&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;grouped_df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;agg&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;PRCP&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;sum&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TMAX&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;max&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TMIN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;min&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                     &lt;span class="s1"&gt;&amp;#39;SNOW&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;sum&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;SNWD&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;mean&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reset_index&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;2000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;LOCATION&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Alta Ski Resort&amp;#39;&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;2000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;LOCATION&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Alta&amp;#39;&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;T_RANGE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TMAX&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TMIN&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df3&lt;/span&gt;
&lt;span class="go"&gt;DATE    PRCP    TMAX    TMIN    SNOW    SNWD    T_RANGE&lt;/span&gt;
&lt;span class="go"&gt;0   1980-01-06  0.68    42.0    12.0    7.0 30.500000   30.0&lt;/span&gt;
&lt;span class="go"&gt;1   1980-01-13  8.76    33.0    -5.0    63.0    48.142857   38.0&lt;/span&gt;
&lt;span class="go"&gt;2   1980-01-20  4.68    40.0    15.0    34.0    63.285714   25.0&lt;/span&gt;
&lt;span class="go"&gt;3   1980-01-27  0.00    43.0    10.0    0.0 57.000000   33.0&lt;/span&gt;
&lt;span class="go"&gt;4   1980-02-03  2.58    38.0    -6.0    40.0    70.571429   44.0&lt;/span&gt;
&lt;span class="go"&gt;... ... ... ... ... ... ... ...&lt;/span&gt;
&lt;span class="go"&gt;2066    2019-08-11  1.09    78.0    42.0    0.0 0.000000    36.0&lt;/span&gt;
&lt;span class="go"&gt;2067    2019-08-18  0.00    75.0    42.0    0.0 0.000000    33.0&lt;/span&gt;
&lt;span class="go"&gt;2068    2019-08-25  0.00    76.0    45.0    0.0 0.000000    31.0&lt;/span&gt;
&lt;span class="go"&gt;2069    2019-09-01  0.02    78.0    41.0    0.0 0.000000    37.0&lt;/span&gt;
&lt;span class="go"&gt;2070    2019-09-08  0.08    78.0    45.0    0.0 0.000000    33.0&lt;/span&gt;
&lt;span class="go"&gt;2071 rows × 7 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;They would find that the lines:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;2000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;LOCATION&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Alta Ski Resort&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;2000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;LOCATION&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Alta&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;don’t really work and would probably change them to this (after searching around on the internet):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;2000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;LOCATION&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Alta Ski Resort&amp;#39;&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;2000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;LOCATION&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Alta&amp;#39;&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df3&lt;/span&gt;
&lt;span class="go"&gt;DATE    PRCP    TMAX    TMIN    SNOW    SNWD    LOCATION    T_RANGE SEASON&lt;/span&gt;
&lt;span class="go"&gt;0   1980-01-06  0.68    42.0    12.0    7.0 30.500000   Alta Ski Resort 30.0    Ski 1979&lt;/span&gt;
&lt;span class="go"&gt;1   1980-01-13  8.76    33.0    -5.0    63.0    48.142857   Alta Ski Resort 38.0    Ski 1979&lt;/span&gt;
&lt;span class="go"&gt;2   1980-01-20  4.68    40.0    15.0    34.0    63.285714   Alta Ski Resort 25.0    Ski 1979&lt;/span&gt;
&lt;span class="go"&gt;3   1980-01-27  0.00    43.0    10.0    0.0 57.000000   Alta Ski Resort 33.0    Ski 1979&lt;/span&gt;
&lt;span class="go"&gt;4   1980-02-03  2.58    38.0    -6.0    40.0    70.571429   Alta Ski Resort 44.0    Ski 1979&lt;/span&gt;
&lt;span class="go"&gt;... ... ... ... ... ... ... ... ... ...&lt;/span&gt;
&lt;span class="go"&gt;2066    2019-08-11  1.09    78.0    42.0    0.0 0.000000    Alta    36.0    Summer 2019&lt;/span&gt;
&lt;span class="go"&gt;2067    2019-08-18  0.00    75.0    42.0    0.0 0.000000    Alta    33.0    Summer 2019&lt;/span&gt;
&lt;span class="go"&gt;2068    2019-08-25  0.00    76.0    45.0    0.0 0.000000    Alta    31.0    Summer 2019&lt;/span&gt;
&lt;span class="go"&gt;2069    2019-09-01  0.02    78.0    41.0    0.0 0.000000    Alta    37.0    Summer 2019&lt;/span&gt;
&lt;span class="go"&gt;2070    2019-09-08  0.08    78.0    45.0    0.0 0.000000    Alta    33.0    Summer 2019&lt;/span&gt;
&lt;span class="go"&gt;2071 rows × 9 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now let’s add a ski season to the rows. Generally a ski season starts in November and ends in April.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SEASON&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Summer&amp;#39;&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;       &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="s1"&gt;&amp;#39;SEASON&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Ski&amp;#39;&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df3&lt;/span&gt;
&lt;span class="go"&gt;DATE    PRCP    TMAX    TMIN    SNOW    SNWD    LOCATION    T_RANGE SEASON&lt;/span&gt;
&lt;span class="go"&gt;0   1980-01-06  0.68    42.0    12.0    7.0 30.500000   Alta Ski Resort 30.0    Ski&lt;/span&gt;
&lt;span class="go"&gt;1   1980-01-13  8.76    33.0    -5.0    63.0    48.142857   Alta Ski Resort 38.0    Ski&lt;/span&gt;
&lt;span class="go"&gt;2   1980-01-20  4.68    40.0    15.0    34.0    63.285714   Alta Ski Resort 25.0    Ski&lt;/span&gt;
&lt;span class="go"&gt;3   1980-01-27  0.00    43.0    10.0    0.0 57.000000   Alta Ski Resort 33.0    Ski&lt;/span&gt;
&lt;span class="go"&gt;4   1980-02-03  2.58    38.0    -6.0    40.0    70.571429   Alta Ski Resort 44.0    Ski&lt;/span&gt;
&lt;span class="go"&gt;... ... ... ... ... ... ... ... ... ...&lt;/span&gt;
&lt;span class="go"&gt;2066    2019-08-11  1.09    78.0    42.0    0.0 0.000000    Alta    36.0    Summer&lt;/span&gt;
&lt;span class="go"&gt;2067    2019-08-18  0.00    75.0    42.0    0.0 0.000000    Alta    33.0    Summer&lt;/span&gt;
&lt;span class="go"&gt;2068    2019-08-25  0.00    76.0    45.0    0.0 0.000000    Alta    31.0    Summer&lt;/span&gt;
&lt;span class="go"&gt;2069    2019-09-01  0.02    78.0    41.0    0.0 0.000000    Alta    37.0    Summer&lt;/span&gt;
&lt;span class="go"&gt;2070    2019-09-08  0.08    78.0    45.0    0.0 0.000000    Alta    33.0    Summer&lt;/span&gt;
&lt;span class="go"&gt;2071 rows × 9 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Finally, let’s add a year to the &lt;em&gt;SEASON&lt;/em&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SEASON&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SEASON&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt; \
&lt;span class="gp"&gt;... &lt;/span&gt;                &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                                                    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;df3&lt;/span&gt;
&lt;span class="go"&gt;DATE    PRCP    TMAX    TMIN    SNOW    SNWD    LOCATION    T_RANGE SEASON&lt;/span&gt;
&lt;span class="go"&gt;0   1980-01-06  0.68    42.0    12.0    7.0 30.500000   Alta Ski Resort 30.0    Ski 1979&lt;/span&gt;
&lt;span class="go"&gt;1   1980-01-13  8.76    33.0    -5.0    63.0    48.142857   Alta Ski Resort 38.0    Ski 1979&lt;/span&gt;
&lt;span class="go"&gt;2   1980-01-20  4.68    40.0    15.0    34.0    63.285714   Alta Ski Resort 25.0    Ski 1979&lt;/span&gt;
&lt;span class="go"&gt;3   1980-01-27  0.00    43.0    10.0    0.0 57.000000   Alta Ski Resort 33.0    Ski 1979&lt;/span&gt;
&lt;span class="go"&gt;4   1980-02-03  2.58    38.0    -6.0    40.0    70.571429   Alta Ski Resort 44.0    Ski 1979&lt;/span&gt;
&lt;span class="go"&gt;... ... ... ... ... ... ... ... ... ...&lt;/span&gt;
&lt;span class="go"&gt;2066    2019-08-11  1.09    78.0    42.0    0.0 0.000000    Alta    36.0    Summer 2019&lt;/span&gt;
&lt;span class="go"&gt;2067    2019-08-18  0.00    75.0    42.0    0.0 0.000000    Alta    33.0    Summer 2019&lt;/span&gt;
&lt;span class="go"&gt;2068    2019-08-25  0.00    76.0    45.0    0.0 0.000000    Alta    31.0    Summer 2019&lt;/span&gt;
&lt;span class="go"&gt;2069    2019-09-01  0.02    78.0    41.0    0.0 0.000000    Alta    37.0    Summer 2019&lt;/span&gt;
&lt;span class="go"&gt;2070    2019-09-08  0.08    78.0    45.0    0.0 0.000000    Alta    33.0    Summer 2019&lt;/span&gt;
&lt;span class="go"&gt;2071 rows × 9 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This looks ok, and you have probably seen code like this. You’ve probably written code like this if you are reading this post.&lt;/p&gt;
&lt;p&gt;It does have some issues. It spans multiple cells, creates unneeded intermediate variables, and might be buggy (note that the &lt;em&gt;LOCATION&lt;/em&gt; column initially failed silently).&lt;/p&gt;
&lt;p&gt;Let's use the Pandas .assign method and chaining to write it a little differently.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;monthly_summary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="n"&gt;my_cols&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STATION&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;NAME&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;LATITUDE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;LONGITUDE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;ELEVATION&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;DATE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;               &lt;span class="s1"&gt;&amp;#39;PRCP&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;SNOW&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;SNWD&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TMAX&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TMIN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TOBS&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;my_cols&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grouper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DATE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;freq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;W&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;agg&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;PRCP&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;sum&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TMAX&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;max&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TMIN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;min&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;SNOW&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;sum&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;SNWD&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;mean&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reset_index&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LOCATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Alta&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                    &lt;span class="n"&gt;SEASON&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Ski&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LOCATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LOCATION&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                                                            &lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                                                            &lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Alta Ski Resort&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                    &lt;span class="n"&gt;T_RANGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TMAX&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TMIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                    &lt;span class="n"&gt;SEASON&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="p"&gt;:(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                                       &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SEASON&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                                       &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Summer&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                                       &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                                       &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                                            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                                            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                                                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                   &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;           &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;monthly_summary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;DATE    PRCP    TMAX    TMIN    SNOW    SNWD    LOCATION    SEASON  T_RANGE&lt;/span&gt;
&lt;span class="go"&gt;0   1980-01-06  0.68    42.0    12.0    7.0 30.500000   Alta Ski Resort Ski 1979    30.0&lt;/span&gt;
&lt;span class="go"&gt;1   1980-01-13  8.76    33.0    -5.0    63.0    48.142857   Alta Ski Resort Ski 1979    38.0&lt;/span&gt;
&lt;span class="go"&gt;2   1980-01-20  4.68    40.0    15.0    34.0    63.285714   Alta Ski Resort Ski 1979    25.0&lt;/span&gt;
&lt;span class="go"&gt;3   1980-01-27  0.00    43.0    10.0    0.0 57.000000   Alta Ski Resort Ski 1979    33.0&lt;/span&gt;
&lt;span class="go"&gt;4   1980-02-03  2.58    38.0    -6.0    40.0    70.571429   Alta Ski Resort Ski 1979    44.0&lt;/span&gt;
&lt;span class="go"&gt;... ... ... ... ... ... ... ... ... ...&lt;/span&gt;
&lt;span class="go"&gt;2066    2019-08-11  1.09    78.0    42.0    0.0 0.000000    Alta    Summer 2019 36.0&lt;/span&gt;
&lt;span class="go"&gt;2067    2019-08-18  0.00    75.0    42.0    0.0 0.000000    Alta    Summer 2019 33.0&lt;/span&gt;
&lt;span class="go"&gt;2068    2019-08-25  0.00    76.0    45.0    0.0 0.000000    Alta    Summer 2019 31.0&lt;/span&gt;
&lt;span class="go"&gt;2069    2019-09-01  0.02    78.0    41.0    0.0 0.000000    Alta    Summer 2019 37.0&lt;/span&gt;
&lt;span class="go"&gt;2070    2019-09-08  0.08    78.0    45.0    0.0 0.000000    Alta    Summer 2019 33.0&lt;/span&gt;
&lt;span class="go"&gt;2071 rows × 9 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;A false positive issue&lt;/h2&gt;
&lt;p&gt;One common comment that I hear when folks see code that looks like monthly_summary is: "This code must be hard to debug."&lt;/p&gt;
&lt;p&gt;I beg to differ. It is written as a chain. But I didn’t write out all the code at once. I wrote one operation at a time. Then I ran the code and validated (debugged) that it was doing what I wanted.&lt;/p&gt;
&lt;p&gt;There are a few pleasant aspects of code written this way. First, it is encapsulated in a function. This makes it easy to pull out into a script and use elsewhere. Also, because it is a function, there aren't any intermediate variables hanging around messing up the global namespace. For example, the my_cols variable is garbage collected when the function has finished executing.&lt;/p&gt;
&lt;p&gt;Also, this chain reads like a recipe of steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pull out the columns&lt;/li&gt;
&lt;li&gt;Groupby by the date with a weekly (&lt;code&gt;'W'&lt;/code&gt;) frequency&lt;/li&gt;
&lt;li&gt;Aggregate the columns as indicated&lt;/li&gt;
&lt;li&gt;Push the index (the week date) into a column&lt;/li&gt;
&lt;li&gt;Add a temperature range (&lt;em&gt;T_RANGE&lt;/em&gt;) column&lt;/li&gt;
&lt;li&gt;Add columns for &lt;em&gt;LOCATION&lt;/em&gt; and &lt;em&gt;SEASON&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Update the &lt;em&gt;LOCATION&lt;/em&gt; and &lt;em&gt;SEASON&lt;/em&gt; columns with logic&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In fact, writing chains forces you to think about each step that you will perform on the data. It is a constraint that I find allows me to write better code. (Again, you might think I’m spewing crazy talk. Try it out and see how it helps with your code.)&lt;/p&gt;
&lt;p&gt;This code is also easy to execute. It is all in one place. Another struggle with notebooks is cells strewn with data manipulation logic (that can be executed in arbitrary order). With the chained code, you can come back to this notebook in the future and run this cell with confidence, knowing that you weren’t missing running other random cells from the notebook.&lt;/p&gt;
&lt;p&gt;Debugging this code is easy as well. I'm not going to dive into that here as I have devoted a whole chapter to that in my book, Effective Pandas (maybe I will do a future blog post on debugging if there is interest). In short, you can comment out the operations to see previous intermediate results or combine a .pipe call with a breakpoint() to jump into the debugger if you really want to.&lt;/p&gt;
&lt;h2&gt;Real issues with Pandas assign&lt;/h2&gt;
&lt;p&gt;Everything is not peaches and cream with the .assign method. There are some real issues with this code. One is that it requires understanding lambda expressions.&lt;/p&gt;
&lt;p&gt;However, I think if you want to be a serious user of Pandas, it pays off to take a few minutes to understand lambda functions.&lt;/p&gt;
&lt;p&gt;We use lambda expressions to create anonymous functions. These are just functions that we can inline in a call. In fact, we don’t really need to use them. We can define a normal function instead. I could write the line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T_RANGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TMAX&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TMIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T_RANGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;calc_range&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If I had a calc_range function defined as:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;calc_range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TMAX&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TMIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(Note I use the variable df_ in my lambda to distinguish it from df that was passed into the monthly_summary function.)&lt;/p&gt;
&lt;p&gt;Using a lambda function (or a normal function) with .assign passes in the current state of the dataframe into the function. Because we have aggregated the daily data to a weekly level, we can only calculate the weekly range from the current data and not the original daily data, df.&lt;/p&gt;
&lt;p&gt;The lambda accepts the current state of the dataframe and should return a scalar value or a series to use for the new or updated column values.&lt;/p&gt;
&lt;p&gt;The lines:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;
                    &lt;span class="n"&gt;LOCATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Alta&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;SEASON&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Ski&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Create columns for LOCATION and SEASON with a single value. You can also set them to a series as well. They don't need lambdas because we are not dependent on the current state of the dataframe.&lt;/p&gt;
&lt;p&gt;Another "issue" with Pandas assign is that we need a new call to it if we want to update a column again (like we do with LOCATION and SEASON). (Because .assign is leveraging named parameters in Python, we can't have two parameters with the same name).&lt;/p&gt;
&lt;p&gt;Complaints that this code is “complicated” are valid, in my opinion. But the complication comes from Pandas’ lack of providing a clean interface for &lt;em&gt;if else&lt;/em&gt; logic, not from the chain.&lt;/p&gt;
&lt;p&gt;(I personally find the .where method lacking and wish that Pandas had something similar to NumPy's select function for implementing conditional logic.)&lt;/p&gt;
&lt;h2&gt;Further refactoring&lt;/h2&gt;
&lt;p&gt;To address the “complicated” nature of creating the &lt;em&gt;LOCATION&lt;/em&gt; and &lt;em&gt;SEASON&lt;/em&gt; columns, you might consider refactoring the logic to create these columns into a function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;monthly_summary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_location&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LOCATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Alta&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LOCATION&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Alta Ski Resort&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="gp"&gt;... &lt;/span&gt;               &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="go"&gt;...     def get_season(df_):&lt;/span&gt;
&lt;span class="go"&gt;...         return (df_&lt;/span&gt;
&lt;span class="go"&gt;...                 .assign(SEASON=&amp;#39;Ski&amp;#39;)&lt;/span&gt;
&lt;span class="go"&gt;...                 .SEASON&lt;/span&gt;
&lt;span class="go"&gt;...                 .where((df_.DATE.dt.month &amp;lt;= 4) | (df_.DATE.dt.month &amp;gt;= 11), &amp;#39;Summer&amp;#39;)&lt;/span&gt;
&lt;span class="go"&gt;...                 .add(&amp;#39; &amp;#39;)&lt;/span&gt;
&lt;span class="go"&gt;...                 .add(df_&lt;/span&gt;
&lt;span class="go"&gt;...                    .DATE.dt.year.astype(str)&lt;/span&gt;
&lt;span class="go"&gt;...                    .where(df_.DATE.dt.month &amp;gt; 4, (df_.DATE.dt.year - 1).astype(str)))&lt;/span&gt;
&lt;span class="go"&gt;...                )&lt;/span&gt;

&lt;span class="go"&gt;...     my_cols =  [&amp;#39;STATION&amp;#39;, &amp;#39;NAME&amp;#39;, &amp;#39;LATITUDE&amp;#39;, &amp;#39;LONGITUDE&amp;#39;, &amp;#39;ELEVATION&amp;#39;, &amp;#39;DATE&amp;#39;,&lt;/span&gt;
&lt;span class="go"&gt;...                 &amp;#39;PRCP&amp;#39;, &amp;#39;SNOW&amp;#39;, &amp;#39;SNWD&amp;#39;, &amp;#39;TMAX&amp;#39;, &amp;#39;TMIN&amp;#39;, &amp;#39;TOBS&amp;#39;]&lt;/span&gt;
&lt;span class="go"&gt;...     return (df&lt;/span&gt;
&lt;span class="go"&gt;...             [my_cols]&lt;/span&gt;
&lt;span class="go"&gt;...             .groupby(pd.Grouper(key=&amp;#39;DATE&amp;#39;, freq=&amp;#39;W&amp;#39;))&lt;/span&gt;
&lt;span class="go"&gt;...             .agg({&amp;#39;PRCP&amp;#39;: &amp;#39;sum&amp;#39;, &amp;#39;TMAX&amp;#39;: &amp;#39;max&amp;#39;, &amp;#39;TMIN&amp;#39;: &amp;#39;min&amp;#39;, &amp;#39;SNOW&amp;#39;: &amp;#39;sum&amp;#39;, &amp;#39;SNWD&amp;#39;: &amp;#39;mean&amp;#39;})&lt;/span&gt;
&lt;span class="go"&gt;...             .reset_index()&lt;/span&gt;
&lt;span class="go"&gt;...             .assign(T_RANGE=lambda df_: df_.TMAX - df_.TMIN,&lt;/span&gt;
&lt;span class="go"&gt;...                     LOCATION=get_location,&lt;/span&gt;
&lt;span class="go"&gt;...                     SEASON=get_season&lt;/span&gt;
&lt;span class="go"&gt;...                    )&lt;/span&gt;
&lt;span class="go"&gt;...            )&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;monthly_summary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;DATE    PRCP    TMAX    TMIN    SNOW    SNWD    T_RANGE LOCATION    SEASON&lt;/span&gt;
&lt;span class="go"&gt;0   1980-01-06  0.68    42.0    12.0    7.0 30.500000   30.0    Alta Ski Resort Ski 1979&lt;/span&gt;
&lt;span class="go"&gt;1   1980-01-13  8.76    33.0    -5.0    63.0    48.142857   38.0    Alta Ski Resort Ski 1979&lt;/span&gt;
&lt;span class="go"&gt;2   1980-01-20  4.68    40.0    15.0    34.0    63.285714   25.0    Alta Ski Resort Ski 1979&lt;/span&gt;
&lt;span class="go"&gt;3   1980-01-27  0.00    43.0    10.0    0.0 57.000000   33.0    Alta Ski Resort Ski 1979&lt;/span&gt;
&lt;span class="go"&gt;4   1980-02-03  2.58    38.0    -6.0    40.0    70.571429   44.0    Alta Ski Resort Ski 1979&lt;/span&gt;
&lt;span class="go"&gt;... ... ... ... ... ... ... ... ... ...&lt;/span&gt;
&lt;span class="go"&gt;2066    2019-08-11  1.09    78.0    42.0    0.0 0.000000    36.0    Alta    Summer 2019&lt;/span&gt;
&lt;span class="go"&gt;2067    2019-08-18  0.00    75.0    42.0    0.0 0.000000    33.0    Alta    Summer 2019&lt;/span&gt;
&lt;span class="go"&gt;2068    2019-08-25  0.00    76.0    45.0    0.0 0.000000    31.0    Alta    Summer 2019&lt;/span&gt;
&lt;span class="go"&gt;2069    2019-09-01  0.02    78.0    41.0    0.0 0.000000    37.0    Alta    Summer 2019&lt;/span&gt;
&lt;span class="go"&gt;2070    2019-09-08  0.08    78.0    45.0    0.0 0.000000    33.0    Alta    Summer 2019&lt;/span&gt;
&lt;span class="go"&gt;2071 rows × 9 columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Create a plot&lt;/h2&gt;
&lt;p&gt;Ok, a weekly summary is nice. But the goal of most manipulating data is not the individual step but creating a result that we can use to inspire, inform, or take action. Let’s use Matplotlib to create a plot of snow on the ground during a season.&lt;/p&gt;
&lt;p&gt;This is similar to what is found in my book, Pandas Cookbook 1.x, and was inspired by a plot created by Trud Antzee (@Antzee_).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;matplotlib.pyplot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;plt&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;plot_season&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;blue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;#99ddee&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;white&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;#fff&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;
     &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SEASON==&amp;quot;Ski &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;&amp;quot;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;side&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;top,right,bottom,left&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;side&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_visible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tick_params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;both&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;colors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;white&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tick_params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;both&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;colors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;white&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tick_params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;x&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;which&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;minor&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;colors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;white&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fill_between&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SNWD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;white&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_facecolor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_ylim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt; Season Snowfall&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fontsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;white&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;facet_plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;years&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;blue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;#99ddee&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;white&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;#fff&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subplots&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ncols&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nrows&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;years&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                          &lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;facecolor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;axs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;axs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;years&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;plot_season&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;suptitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Alta Snowfall (@__mharrison__)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fontsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;white&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tight_layout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fig&lt;/span&gt;

&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;monthly_summary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;facet_plot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;years&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;2005&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2010&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;2015&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="Monthly snowfall totals at Alta" src="/static/img/blog/pandas-assign/monthly-snowfall.png"&gt;&lt;/p&gt;
&lt;h2&gt;Final code&lt;/h2&gt;
&lt;p&gt;Thanks for getting this far. I hope you have a better understanding of using the .assign method. Also I hope you appreciate that operations do not occur in isolation.&lt;/p&gt;
&lt;p&gt;We showed how to take "traditional" Pandas code, refactor it into chains and functions. I would love to hear your feedback. How are you going to use the Pandas assign method? Please share examples of applying chains like this to your code on Twitter, and tag @ponderdata and @&lt;strong&gt;mharrison&lt;/strong&gt; (and follow us on Twitter for more content like this). What insights did you have as you were doing it?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;matplotlib.pyplot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;plt&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;modin.pandas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pd&lt;/span&gt;

&lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;https://github.com/mattharrison/datasets/raw/master/data/alta-noaa-1980-2019.csv&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="n"&gt;parse_dates&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DATE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;tweak_alta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STATION&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;NAME&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;LATITUDE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;LONGITUDE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;ELEVATION&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;DATE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                     &lt;span class="s1"&gt;&amp;#39;PRCP&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;SNOW&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;SNWD&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TMAX&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TMIN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TOBS&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
           &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;monthly_summary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_location&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LOCATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Alta&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LOCATION&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Alta Ski Resort&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_season&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SEASON&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Ski&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SEASON&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Summer&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;
                   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
               &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;my_cols&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STATION&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;NAME&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;LATITUDE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;LONGITUDE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;ELEVATION&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;DATE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s1"&gt;&amp;#39;PRCP&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;SNOW&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;SNWD&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TMAX&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TMIN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TOBS&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;my_cols&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grouper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DATE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;freq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;W&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;agg&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;PRCP&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;sum&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TMAX&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;max&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TMIN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;min&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;SNOW&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;sum&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;SNWD&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;mean&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reset_index&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T_RANGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TMAX&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TMIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;LOCATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;get_location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;SEASON&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;get_season&lt;/span&gt;
                   &lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;plot_season&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;blue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;#99ddee&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;white&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;#fff&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;
     &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SEASON==&amp;quot;Ski &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;&amp;quot;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;side&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;top,right,bottom,left&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;side&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_visible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tick_params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;both&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;colors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;white&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tick_params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;both&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;colors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;white&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tick_params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;x&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;which&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;minor&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;colors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;white&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fill_between&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SNWD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;white&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_facecolor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_ylim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt; Season Snowfall&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fontsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;white&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;facet_plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;years&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;blue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;#99ddee&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;white&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;#fff&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subplots&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ncols&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nrows&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;years&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                          &lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;facecolor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;axs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;axs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;years&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;plot_season&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;suptitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Alta Snowfall (@__mharrison__)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fontsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;white&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tight_layout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fig&lt;/span&gt;


&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;
     &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tweak_alta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;monthly_summary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;facet_plot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;years&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;2005&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2010&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;2015&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="Monthly snowfall totals at Alta" src="/static/img/blog/pandas-assign/monthly-snowfall.png"&gt;&lt;/p&gt;</content><category term="misc"/><category term="pandas"/><category term="assign"/><category term="method-chaining"/></entry><entry><title>Pandas Series Introduction</title><link href="https://www.metasnake.com/blog/pandas-series-intro.html" rel="alternate"/><published>2021-06-03T00:00:00-06:00</published><updated>2021-06-03T00:00:00-06:00</updated><author><name>Matt Harrison</name></author><id>tag:www.metasnake.com,2021-06-03:/blog/pandas-series-intro.html</id><summary type="html">&lt;p class="first last"&gt;Pandas Series Introduction&lt;/p&gt;
</summary><content type="html">&lt;p&gt;A &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt; is used to model one-dimensional data, similar to a list
in Python. The &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt; object also has a few more bits of data,
including an index and a name. A common idea through pandas is the
notion of an axis. Because a series is one dimensiona-, it has a single
&lt;em&gt;axis&lt;/em&gt;—the index.&lt;/p&gt;
&lt;p&gt;Below is a table of counts of songs artists composed. We will use this to
explore how the series type functions:&lt;/p&gt;
&lt;table border="1" class="docutils"&gt;
&lt;colgroup&gt;
&lt;col width="55%" /&gt;
&lt;col width="45%" /&gt;
&lt;/colgroup&gt;
&lt;thead valign="bottom"&gt;
&lt;tr&gt;&lt;th class="head"&gt;Artist&lt;/th&gt;
&lt;th class="head"&gt;Data&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;145&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;142&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;38&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;If you wanted to represent this data in pure Python, you could use a data structure
similar to the one that follows. It is a dictionary that has a list of
the data points stored under the &lt;tt class="docutils literal"&gt;'data'&lt;/tt&gt; key. In addition to an
entry in the dictionary for the actual data, there is an explicit
entry for the corresponding index values for the data (in the
&lt;tt class="docutils literal"&gt;'index'&lt;/tt&gt; key), as well as an entry for the name of the data (in the
&lt;tt class="docutils literal"&gt;'name'&lt;/tt&gt; key):&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; ser = {
...   'index':[0, 1, 2, 3],
...   'data':[145, 142, 38, 13],
...   'name':'songs'
...   }
&lt;/pre&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;get&lt;/tt&gt; function defined below can pull items out of this data
structure based on the index:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; def get(ser, idx):
...     value_idx = ser['index'].index(idx)
...     return ser['data'][value_idx]

&amp;gt;&amp;gt;&amp;gt; get(ser, 1)
142
&lt;/pre&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p&gt;The code samples in this book are shown as if they were
typed directly into an interpreter. Lines starting with &lt;tt class="docutils literal"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/tt&gt; and
&lt;tt class="docutils literal"&gt;...&lt;/tt&gt; are interpreter markers for the &lt;em&gt;input prompt&lt;/em&gt; and
&lt;em&gt;continuation prompt&lt;/em&gt; respectively. Lines that are not prefixed by one
of those sequences are the output from the interpreter after running
the code.&lt;/p&gt;
&lt;p class="last"&gt;The Python interpreter will print the return value of the last
invocation (even if the &lt;tt class="docutils literal"&gt;print&lt;/tt&gt; statement is missing)
automatically. If you desire to use the code samples found in this book, leave the
interpreter prompts out.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-index-abstraction"&gt;
&lt;h2&gt;The index abstraction&lt;/h2&gt;
&lt;p&gt;This double abstraction of the index seems unnecessary at first
glance—a list already has integer indexes. But there is a trick up pandas'
sleeves. By allowing non-integer values, the data structure
supports other index types such as strings, dates, as well as
arbitrarily ordered indices or even duplicate index values.&lt;/p&gt;
&lt;p&gt;Below is an example that has string values for the index:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; songs = {
...   'index':['Paul', 'John', 'George', 'Ringo'],
...   'data':[145, 142, 38, 13],
...   'name':'counts'
...   }

&amp;gt;&amp;gt;&amp;gt; get(songs, 'John')
142
&lt;/pre&gt;
&lt;p&gt;The index is a core feature of pandas’ data structures given the
library’s past in analysis of financial data or &lt;em&gt;time series
data&lt;/em&gt;. Many of the operations performed on a &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt; operate directly on the index
or by index lookup.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-pandas-series"&gt;
&lt;h2&gt;The pandas &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt;&lt;/h2&gt;
&lt;p&gt;With that background in mind, let’s look at how to create a &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt;
in pandas.  It is easy to create a &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt; object from a list:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; import pandas as pd
&amp;gt;&amp;gt;&amp;gt; songs2 = pd.Series([145, 142, 38, 13],
...      name='counts')

&amp;gt;&amp;gt;&amp;gt; songs2
0    145
1    142
2     38
3     13
Name: counts, dtype: int64
&lt;/pre&gt;
&lt;p&gt;When the interpreter prints our series, pandas makes a best effort to
format it for the current terminal size. The leftmost column is the
&lt;em&gt;index&lt;/em&gt; column which contains entries for the index. The generic name
for an index is an &lt;em&gt;axis&lt;/em&gt;, and the values of the index—0, 1, 2, 3—are called
&lt;em&gt;axis labels&lt;/em&gt;. The two-dimensional structure in
pandas—a &lt;tt class="docutils literal"&gt;DataFrame&lt;/tt&gt;—has two axes, one for the rows and another for
the columns.&lt;/p&gt;
&lt;img alt="foo" class="img-fluid" src="/static/img/pandas2/04-series.png" /&gt;
&lt;p class="figcaption"&gt;The parts of a Series.&lt;/p&gt;
&lt;p&gt;The rightmost column in the output contains the &lt;em&gt;values&lt;/em&gt; of the series—145, 142, 38, and 13. In this
case, they are integers (the console representation says &lt;tt class="docutils literal"&gt;dtype: int64&lt;/tt&gt;,
&lt;tt class="docutils literal"&gt;dtype&lt;/tt&gt; meaning data type, and &lt;tt class="docutils literal"&gt;int64&lt;/tt&gt; meaning 64-bit integer),
but in general values of a &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt; can hold strings, floats, booleans, or
arbitrary Python objects. To get the best speed (and to leverage vectorized operations), the
values should be of the same type, though this is not required.&lt;/p&gt;
&lt;p&gt;It is easy to inspect the index of a series (or data frame), as it
is an attribute of the object:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; songs2.index
RangeIndex(start=0, stop=4, step=1)
&lt;/pre&gt;
&lt;p&gt;The default values for an index are monotonically increasing integers. &lt;tt class="docutils literal"&gt;songs2&lt;/tt&gt;
has an integer-based index.&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p&gt;The index can be string based as well, in which case pandas
indicates that the datatype for the index is &lt;tt class="docutils literal"&gt;object&lt;/tt&gt; (not
string):&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; songs3 = pd.Series([145, 142, 38, 13],
...      name='counts',
...      index=['Paul', 'John', 'George', 'Ringo'])
&lt;/pre&gt;
&lt;p&gt;Note that the &lt;tt class="docutils literal"&gt;dtype&lt;/tt&gt; that we see when we print a &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt; is the type of the values,
not of the index:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; songs3
Paul      145
John      142
George     38
Ringo      13
Name: counts, dtype: int64
&lt;/pre&gt;
&lt;p&gt;When we inspect the index attribute, we see that the &lt;tt class="docutils literal"&gt;dtype&lt;/tt&gt; is &lt;tt class="docutils literal"&gt;object&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class="last literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; songs3.index   # doctest: +NORMALIZE_WHITESPACE
Index(['Paul', 'John', 'George', 'Ringo'],
dtype='object')
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The actual data for a series does not have to be numeric or
homogeneous. We can insert Python objects into a series:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; class Foo:
...     pass

&amp;gt;&amp;gt;&amp;gt; ringo = pd.Series(
...      ['Richard', 'Starkey', 13, Foo()],
...      name='ringo')

&amp;gt;&amp;gt;&amp;gt; ringo  # doctest: +SKIP +NORMALIZE_WHITESPACE
0                             Richard
1                             Starkey
2                                  13
3    &amp;lt;__main__.Foo instance at 0x...&amp;gt;
Name: ringo, dtype: object
&lt;/pre&gt;
&lt;p&gt;In the above case, the &lt;tt class="docutils literal"&gt;dtype&lt;/tt&gt;-&lt;em&gt;datatype&lt;/em&gt;-of the &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt; is
&lt;tt class="docutils literal"&gt;object&lt;/tt&gt; (meaning a Python object). This can be good or bad.&lt;/p&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;object&lt;/tt&gt; data type is used for strings. But, it is also used for
values that have heterogeneous types. If you have just numeric data in a series, you
wouldn't want it stored as a Python object, but rather as an &lt;tt class="docutils literal"&gt;int64&lt;/tt&gt; or &lt;tt class="docutils literal"&gt;float64&lt;/tt&gt;,
which allow you to do vectorized numeric operations.&lt;/p&gt;
&lt;p&gt;If you have time data and it says it has the &lt;tt class="docutils literal"&gt;object&lt;/tt&gt; type, you probably have
strings for the dates. Using strings instead of date types is bad as you don't get the date operations that you
would get if the type were &lt;tt class="docutils literal"&gt;datetime64[ns]&lt;/tt&gt;. Strings, on the other hand, are
stored in pandas as &lt;tt class="docutils literal"&gt;object&lt;/tt&gt;. Don't worry; we will see how to convert types
later in the book.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-nan-value"&gt;
&lt;h2&gt;The &lt;tt class="docutils literal"&gt;NaN&lt;/tt&gt; value&lt;/h2&gt;
&lt;p&gt;A value that may be familiar to NumPy users, but not Python users in
general, is &lt;tt class="docutils literal"&gt;NaN&lt;/tt&gt;. When pandas determines that a series holds
numeric values, but it cannot find a number to represent an entry, it
will use &lt;tt class="docutils literal"&gt;NaN&lt;/tt&gt;. This value stands for &lt;em&gt;Not A Number&lt;/em&gt; and is usually
ignored in arithmetic operations. (Similar to NULL in SQL).&lt;/p&gt;
&lt;p&gt;Here is a series that has &lt;tt class="docutils literal"&gt;NaN&lt;/tt&gt; in it:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; import numpy as np
&amp;gt;&amp;gt;&amp;gt; nan_ser = pd.Series([2, np.nan],
...    index=['Ono', 'Clapton'])
&amp;gt;&amp;gt;&amp;gt; nan_ser
Ono        2.0
Clapton    NaN
dtype: float64
&lt;/pre&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;One thing to note is that the type of this series is &lt;tt class="docutils literal"&gt;float64&lt;/tt&gt;, not &lt;tt class="docutils literal"&gt;int64&lt;/tt&gt;!
The type is a float because &lt;tt class="docutils literal"&gt;float64&lt;/tt&gt; supports &lt;tt class="docutils literal"&gt;NaN&lt;/tt&gt;, which &lt;tt class="docutils literal"&gt;int64&lt;/tt&gt; does not. When pandas sees numeric
data (&lt;tt class="docutils literal"&gt;2&lt;/tt&gt;) as well as the &lt;tt class="docutils literal"&gt;None&lt;/tt&gt;, it coerced the &lt;tt class="docutils literal"&gt;2&lt;/tt&gt; to a float value.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Below is an example of how pandas ignores &lt;tt class="docutils literal"&gt;NaN&lt;/tt&gt;. The &lt;tt class="docutils literal"&gt;.count&lt;/tt&gt; method,
which counts the number of values in a series, disregards &lt;tt class="docutils literal"&gt;NaN&lt;/tt&gt;. In
this case, it indicates that the count of items in the &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt; is one,
one for the value of &lt;tt class="docutils literal"&gt;2&lt;/tt&gt; at index location
&lt;tt class="docutils literal"&gt;Ono&lt;/tt&gt;, ignoring the &lt;tt class="docutils literal"&gt;NaN&lt;/tt&gt; value at index location &lt;tt class="docutils literal"&gt;Clapton&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; nan_ser.count()
1
&lt;/pre&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;If you load data from a CSV file, an empty value for an otherwise
numeric column will become &lt;tt class="docutils literal"&gt;NaN&lt;/tt&gt;. Later, methods such as
&lt;tt class="docutils literal"&gt;.fillna&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;.dropna&lt;/tt&gt; will explain how to deal with &lt;tt class="docutils literal"&gt;NaN&lt;/tt&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;None&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;NaN&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;nan&lt;/tt&gt;, and null are synonyms in this book when
referring to empty or missing data found in a pandas series or
data frame.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="optional-integer-support-for-nan"&gt;
&lt;h2&gt;Optional Integer Support for &lt;tt class="docutils literal"&gt;NaN&lt;/tt&gt;&lt;/h2&gt;
&lt;p&gt;As of pandas 0.24, there is optional support for the integer type to hold &lt;tt class="docutils literal"&gt;NaN&lt;/tt&gt; values.
The documentation calls this type the &lt;em&gt;nullable integer type&lt;/em&gt;.
When you create a series, you can pass in &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;dtype='Int64'&lt;/span&gt;&lt;/tt&gt; (note the capitalization):&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; nan_ser2 = pd.Series([2, None],
...    index=['Ono', 'Clapton'],
...    dtype='Int64')
&amp;gt;&amp;gt;&amp;gt; nan_ser2
Ono           2
Clapton    &amp;lt;NA&amp;gt;
dtype: Int64
&lt;/pre&gt;
&lt;p&gt;Operations on these series still ignore &lt;tt class="docutils literal"&gt;NaN&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; nan_ser2.count()
1
&lt;/pre&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p&gt;You can use the &lt;tt class="docutils literal"&gt;.astype&lt;/tt&gt; method to convert columns to the nullable integer type. Just use
the string &lt;tt class="docutils literal"&gt;'Int64'&lt;/tt&gt; as the type:&lt;/p&gt;
&lt;pre class="last literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; nan_ser.astype('Int64')
Ono           2
Clapton    &amp;lt;NA&amp;gt;
dtype: Int64
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="similar-to-numpy"&gt;
&lt;h2&gt;Similar to NumPy&lt;/h2&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt; object behaves similarly to a NumPy
array. As shown below, both types respond to index operations:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; import numpy as np
&amp;gt;&amp;gt;&amp;gt; numpy_ser = np.array([145, 142, 38, 13])
&amp;gt;&amp;gt;&amp;gt; songs3[1]
142
&amp;gt;&amp;gt;&amp;gt; numpy_ser[1]
142
&lt;/pre&gt;
&lt;p&gt;They both have methods in common:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; songs3.mean()
84.5
&amp;gt;&amp;gt;&amp;gt; numpy_ser.mean()
84.5
&lt;/pre&gt;
&lt;p&gt;They also both have a notion of a &lt;em&gt;boolean array&lt;/em&gt;. A boolean array is a series with the same index as the series you are working with that has boolean values. It can be used
as a mask to filter out items. Normal Python lists do not support such fancy
index operations:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; mask = songs3 &amp;gt; songs3.median()  # boolean array

&amp;gt;&amp;gt;&amp;gt; mask
Paul       True
John       True
George    False
Ringo     False
Name: counts, dtype: bool
&lt;/pre&gt;
&lt;p&gt;Once we have a mask, we can use that as a filter. We just need to pass the mask into
an index operation. If the mask has a &lt;tt class="docutils literal"&gt;True&lt;/tt&gt; value for a given index, the value is
kept. Otherwise, the value is dropped. The mask above represents the locations
that have a value higher than the median value of the series.&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; songs3[mask]
Paul    145
John    142
Name: counts, dtype: int64
&lt;/pre&gt;
&lt;img alt="foo" class="img-fluid" src="/static/img/pandas2/04-booleanarray.png" /&gt;
&lt;p class="figcaption"&gt;Filtering a series with a boolean array.&lt;/p&gt;
&lt;p&gt;NumPy also has filtering by boolean arrays, but lacks the &lt;tt class="docutils literal"&gt;.median&lt;/tt&gt;
method on an array. Instead, NumPy provides a &lt;tt class="docutils literal"&gt;median&lt;/tt&gt; function in
the NumPy namespace:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; numpy_ser[numpy_ser &amp;gt; np.median(numpy_ser)]
array([145, 142])
&lt;/pre&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p&gt;Both NumPy and pandas have adopted the convention of using import
statements in combination with an &lt;tt class="docutils literal"&gt;as&lt;/tt&gt; statement to rename their imports to two
letter acronyms:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; import pandas as pd
&amp;gt;&amp;gt;&amp;gt; import numpy as np
&lt;/pre&gt;
&lt;p&gt;Renaming imports provides a slight typing benefit (four fewer characters) while still allowing the user to be
explicit with their namespaces.&lt;/p&gt;
&lt;p&gt;Be careful, as you may see the following cast about in code samples, blogs, or documentation:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; from pandas import *
&lt;/pre&gt;
&lt;p class="last"&gt;Though you see &lt;em&gt;star imports&lt;/em&gt; frequently used in examples online, I would advise not
to use star imports. I never use them in examples or my work. They have the potential to clobber items in your
namespace and make tracing the source of a definition more difficult
(especially if you have multiple star imports). As the Zen of Python states,
“Explicit is better than implicit” &lt;a class="footnote-reference" href="#footnote-1" id="footnote-reference-1"&gt;[1]&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Type &lt;tt class="docutils literal"&gt;import this&lt;/tt&gt; into an interpreter to see the Zen of Python. Or search for &amp;quot;PEP 20&amp;quot;.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="section" id="categorical-data"&gt;
&lt;h2&gt;Categorical Data&lt;/h2&gt;
&lt;p&gt;When you load data, you can indicate that the data is categorical. If we know that
our data is limited to a few values; we might want to use categorical data. Categorical values
have a few benefits:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Use less memory than strings&lt;/li&gt;
&lt;li&gt;Can have an ordering&lt;/li&gt;
&lt;li&gt;Can perform operations on categories&lt;/li&gt;
&lt;li&gt;Enforce membership on values&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Categories are not limited to strings; we can also use numbers or datetime values.&lt;/p&gt;
&lt;p&gt;To create a category, we pass &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;dtype=&amp;quot;category&amp;quot;&lt;/span&gt;&lt;/tt&gt; into the &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt;
constructor. Alternatively, we can call the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;.as_type(&amp;quot;category&amp;quot;)&lt;/span&gt;&lt;/tt&gt; method on a series:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; s = pd.Series(['m', 'l', 'xs', 's', 'xl'], dtype='category')
&amp;gt;&amp;gt;&amp;gt; s
0     m
1     l
2    xs
3     s
4    xl
dtype: category
Categories (5, object): ['l', 'm', 's', 'xl', 'xs']
&lt;/pre&gt;
&lt;p&gt;If this series represents size, there is a natural ordering as a small is less
than a medium. By default, categories don't have an ordering. We can verify this by inspecting the &lt;tt class="docutils literal"&gt;.cat&lt;/tt&gt; attribute
that has various properties:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; s.cat.ordered
False
&lt;/pre&gt;
&lt;p&gt;To convert a non-categorical series to an ordered category, we can create a type with the &lt;tt class="docutils literal"&gt;CategoricalDtype&lt;/tt&gt;
constructor and the appropriate parameters. Then we pass this type into the &lt;tt class="docutils literal"&gt;.astype&lt;/tt&gt; method:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; s2 = pd.Series(['m', 'l', 'xs', 's', 'xl'])
&amp;gt;&amp;gt;&amp;gt; size_type = pd.api.types.CategoricalDtype(
...     categories=['s','m','l'], ordered=True)
&amp;gt;&amp;gt;&amp;gt; s3 = s2.astype(size_type)
...
&amp;gt;&amp;gt;&amp;gt; s3
0      m
1      l
2    NaN
3      s
4    NaN
dtype: category
Categories (3, object): ['s' &amp;lt; 'm' &amp;lt; 'l']
&lt;/pre&gt;
&lt;p&gt;In this case, we limited the categories to just &lt;tt class="docutils literal"&gt;'s'&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;'m'&lt;/tt&gt;, and &lt;tt class="docutils literal"&gt;'l'&lt;/tt&gt;,
but the data had values that were not in those categories. These extra values were
replaced with &lt;tt class="docutils literal"&gt;NaN&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;If we have ordered categories, we can do comparisons on them:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; s3 &amp;gt; 's'
0     True
1     True
2    False
3    False
4    False
dtype: bool
&lt;/pre&gt;
&lt;p&gt;The prior example created a new &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt; from existing data that was not categorical. We can also add
ordering information to categorical data. We just need to make sure that we
specify all of the members of the category or pandas will throw a
&lt;tt class="docutils literal"&gt;ValueError&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; s.cat.reorder_categories(['xs','s','m','l', 'xl'],
...                          ordered=True)
0     m
1     l
2    xs
3     s
4    xl
dtype: category
Categories (5, object): ['xs' &amp;lt; 's' &amp;lt; 'm' &amp;lt; 'l' &amp;lt; 'xl']
&lt;/pre&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p&gt;String and datetime series have a &lt;tt class="docutils literal"&gt;str&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;dt&lt;/tt&gt; attribute that allow us to perform common
operations specific to that type. If we convert these types to categorical types, we can still
use the &lt;tt class="docutils literal"&gt;str&lt;/tt&gt; or &lt;tt class="docutils literal"&gt;dt&lt;/tt&gt; attributes on them:&lt;/p&gt;
&lt;pre class="last literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; s3.str.upper()
0      M
1      L
2    NaN
3      S
4    NaN
dtype: object
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="summary"&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt; object is a one-dimensional data structure. It can hold numerical data,
time data, strings, or arbitrary Python objects. If you are dealing with numeric
data, using pandas rather than a Python list will give you additional benefits. Pandas is
faster, consumes less memory, and comes with built-in methods that are very useful to manipulate the data.
Also, the index abstraction allows for accessing values by position or label.
A &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt; can also have empty values and has some similarities to NumPy arrays.
It is the basic workhorse of pandas; mastering it will pay dividends.&lt;/p&gt;
&lt;/div&gt;
</content><category term="misc"/><category term="pandas"/></entry><entry><title>Pandas Data Structures</title><link href="https://www.metasnake.com/blog/pandas-data-structures.html" rel="alternate"/><published>2021-06-02T00:00:00-06:00</published><updated>2021-06-02T00:00:00-06:00</updated><author><name>Matt Harrison</name></author><id>tag:www.metasnake.com,2021-06-02:/blog/pandas-data-structures.html</id><summary type="html">&lt;p class="first last"&gt;Pandas Data Structures&lt;/p&gt;
</summary><content type="html">&lt;p&gt;One of the keys to understanding pandas is to understand the data
model. At the core of pandas are two data structures:&lt;/p&gt;
&lt;table border="1" class="docutils"&gt;
&lt;caption&gt;Different dimensions of pandas data structures&lt;/caption&gt;
&lt;colgroup&gt;
&lt;col width="25%" /&gt;
&lt;col width="32%" /&gt;
&lt;col width="42%" /&gt;
&lt;/colgroup&gt;
&lt;thead valign="bottom"&gt;
&lt;tr&gt;&lt;th class="head"&gt;Data Structure&lt;/th&gt;
&lt;th class="head"&gt;Dimensionality&lt;/th&gt;
&lt;th class="head"&gt;Spreadsheet Analog&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td&gt;&lt;tt class="docutils literal"&gt;Series&lt;/tt&gt;&lt;/td&gt;
&lt;td&gt;1D&lt;/td&gt;
&lt;td&gt;Column&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;tt class="docutils literal"&gt;DataFrame&lt;/tt&gt;&lt;/td&gt;
&lt;td&gt;2D&lt;/td&gt;
&lt;td&gt;Single Sheet&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The most widely used data structures are the &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt; and the
&lt;tt class="docutils literal"&gt;DataFrame&lt;/tt&gt; that deal with array data and tabular data,
respectively. An analogy with the spreadsheet world illustrates the
basic differences between these types. A &lt;tt class="docutils literal"&gt;DataFrame&lt;/tt&gt; is similar to a
sheet with rows and columns, while a &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt; is similar to a single
column of data.&lt;/p&gt;
&lt;img alt="foo" class="img-fluid" src="/static/img/pandas2/03-datastructures.png" /&gt;
&lt;p class="figcaption"&gt;Figure showing the relation between the main data structures in pandas. Namely,
that a data frame can have multiple series.&lt;/p&gt;
&lt;p&gt;Diving into these core data structures a little more is useful because a bit of
understanding goes a long way towards better use of the library. We will spend a
good portion of time discussing the &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;DataFrame&lt;/tt&gt;. Both the
&lt;tt class="docutils literal"&gt;Series&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;DataFrame&lt;/tt&gt; share features. For example, they both have an
index, which we will need to examine to understand how pandas works.&lt;/p&gt;
&lt;p&gt;Also, because the &lt;tt class="docutils literal"&gt;DataFrame&lt;/tt&gt; can be thought of as a collection of columns
that are really &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt; objects, it is imperative that we have a comprehensive
study of the &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt; first. Additionally (and perhaps odd to some), we will see this when we iterate over rows, and the rows are
represented as &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt;.&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;Some have compared the data structures to Python lists or dictionaries,
and I think this is a stretch that doesn't provide much benefit.
Mapping the list and dictionary methods on top of pandas' data structures
just leads to confusion.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="summary"&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;The pandas library includes three main data structures and associated functions for manipulating them.
This book will focus on the &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;DataFrame&lt;/tt&gt;. First, we will look at the &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt; as
the &lt;tt class="docutils literal"&gt;DataFrame&lt;/tt&gt; can be thought of as a collection of &lt;tt class="docutils literal"&gt;Series&lt;/tt&gt;.&lt;/p&gt;
&lt;/div&gt;
</content><category term="misc"/><category term="pandas"/></entry><entry><title>The Future of Corporate Training</title><link href="https://www.metasnake.com/blog/postcovidetraining.html" rel="alternate"/><published>2021-04-15T00:00:00-06:00</published><updated>2021-04-15T00:00:00-06:00</updated><author><name>Matt Harrison</name></author><id>tag:www.metasnake.com,2021-04-15:/blog/postcovidetraining.html</id><summary type="html"/><content type="html">&lt;p&gt;&lt;strong&gt;TLDR&lt;/strong&gt; - I think in a post-Covid19 society, virtual training will be the default, but live training will return to office campuses and quarterly onsites.&lt;/p&gt;
&lt;h2&gt;Training Flipped&lt;/h2&gt;
&lt;p&gt;The last year threw corporate training for a loop. One week I was wrapping up a wonderful Machine Learning course for my biggest client and the next week they had dropped the dozen classes they had planned for the year.&lt;/p&gt;
&lt;p&gt;It is never fun to lose your biggest client, but rather than look back, I doubled down and invested in upping my virtual training skills. I read a lot of material, bought equipment, and the feedback has been wonderful:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I have had many programming teachers who were super knowledgeable but didn't
know much about pedagogy or vice versa and it was refreshing to be taught by
someone who had both sets of skills.&lt;/p&gt;
&lt;p&gt;Over all I think this was an excellent course and worthwhile. I like your
teaching style and appreciate your willingness to answer questions, even when
you had already explained it once before.&lt;/p&gt;
&lt;p&gt;I really enjoyed it and learned a lot, thanks!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Default to Work from Home?&lt;/h2&gt;
&lt;p&gt;The jury is mixed on what the future of work will look like. Tech titans like Netflix and Google are insisted on a return to the office, while Twitter is leading the way pushing for permanent work from home. Between these extremes are the many companies that can operate remotely, but may do so only part time.&lt;/p&gt;
&lt;p&gt;I asked my network on Twitter and LinkedIn and got very mixed results. The only take away is that a small percentage of my contacts will be going to the Netflix/Google model. The question is the degree from which they will work from home.&lt;/p&gt;
&lt;h2&gt;Where does Training Go?&lt;/h2&gt;
&lt;p&gt;My feeling is that much of training will remain virtual. However, I'm getting feeders from my network that in-person training is also desired. I suspect much of this may migrate to onsites. &lt;/p&gt;
&lt;p&gt;I feel that even with my investment into virtual training, in-person is just a bit better. You get to see people (many are Zoom-shy or just Zoom-exhausted), you can help them easier, and they can help each other easier. &lt;/p&gt;
&lt;p&gt;If you are looking for virtual or in-person (I'm vaccinated) training for Python or Data Science, reach out. Happy to help!&lt;/p&gt;</content><category term="misc"/><category term="training"/></entry><entry><title>Best Way to Learn Python in 2021</title><link href="https://www.metasnake.com/blog/learn-python-2021.html" rel="alternate"/><published>2021-01-12T00:00:00-07:00</published><updated>2021-01-12T00:00:00-07:00</updated><author><name>Matt Harrison</name></author><id>tag:www.metasnake.com,2021-01-12:/blog/learn-python-2021.html</id><summary type="html">&lt;p&gt;Lot's of Options&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;strong&gt;TLDR:&lt;/strong&gt; There is a great demand for Python skills. There are also lots of ways to learn.&lt;/p&gt;
&lt;p&gt;How does the saying go? The best time to learn Python was 20 years ago. The second best time is now. &lt;/p&gt;
&lt;p&gt;That's not quite true, Python was a niche language 20 years ago. Today Python is ubiquitous and one of the top languages used to develop applications, analyze data, create predictive models, manage servers, and more.&lt;/p&gt;
&lt;p&gt;When I learned Python in 2000, it was frowned upon as a less expressive Perl. It fit my brain, and I never looked back even though I have used Java, C#, Clojure, JavaScript, and other tools since.&lt;/p&gt;
&lt;p&gt;A common question I get these days is: what is the best way to learn Python? I'm going to answer that with a staple of data science, a decision tree. The answer really depends, but after teaching Python to thousands over many years, I have a few opinions on the topic.&lt;/p&gt;
&lt;figure&gt;
&lt;img src='/static/img/pythonflow.png' class='img-fluid' alt='Learning Python'/&gt;
&lt;figcaption&gt;&lt;strong&gt;TLDR:&lt;/strong&gt; Follow this for Python mastery&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;(&lt;em&gt;Full disclosure: I  make my living selling snake oil. I literally tell and enable people to do amazing things with Python that cure most ails.&lt;/em&gt;)&lt;/p&gt;
&lt;h2&gt;Are You a Corporation?&lt;/h2&gt;
&lt;p&gt;First things first. If you are a corporation, treat your employees well, and consider 
corporate training. There is something to be said about getting a team together and having
them work through training together. (I said work because training can be intense).
Your team will be on the same page at the end of the day. Training will fill in 
their knowledge gaps. They can address any issues or questions they have immediately with
a knowledgeable instructor. Good trainers can facilitate discussions that 
bring out customers issues and solutions to those quickly.&lt;/p&gt;
&lt;figure&gt;
&lt;img src='/static/img/custom-training.png' class='img-fluid' alt='Learning Python'/&gt;
&lt;figcaption&gt;Corporate Training is the quickest way to get your team on the same page.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Here is a quote from a manager at a large video company:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Nice breadth, very practical, easy to follow along. Everybody loved it. We already used some of the skills to debug two different production issues. Awesome!”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Seriously, invest in your employees. Here is a common complaint. I talk to many
companies that spend money on on-demand courses (full-disclosure: I have created
content for many of these courseware providers), and while the content may be
good, most employees are not motivated nor incentivized to go through it. The
employers are not getting the value out of these courses. This is a typical
criticism (in fact, most if not all of my clients have on-demand courses in
addition to live training because they want their employees to have certain skills and most
employees do not do on-demand.)&lt;/p&gt;
&lt;p&gt;One more thing to consider with live corporate training. Not all corporate
training is the same. Who would you rather have training you? Someone who
is a professional slide reader? Or someone who has worked with the technology
for 20+ years and also has had extensive experience tutoring, teaching, and 
writing?&lt;/p&gt;
&lt;p&gt;Going with a quality trainer who has in-the-trenches experience and teaching
skills can make a big difference. I generally only train on material that
I have used as a consultant or as an employee. &lt;/p&gt;
&lt;p&gt;If you are not interested in MetaSnake's offerings, reach out, I know a bunch
of other quality trainers that also have more experience than just reciting
Powerpoint presentations.&lt;/p&gt;
&lt;h2&gt;The Best for Individuals&lt;/h2&gt;
&lt;p&gt;How bad do you want to learn Python? I've come across countless people who
claim they want to learn Python, but are not willing to invest anything to get results.
The best results come from having a coach to identify weak spots and 
provide advice and practice to improve those faults.&lt;/p&gt;
&lt;figure&gt;
&lt;img src='/static/img/Brandon-Payne-profile.jpeg' class='img-fluid' alt='Brandon Payne'/&gt;
&lt;figcaption&gt;Coach you probably don't recognize.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;You have probably never heard of the coach above. His name is Brandon
Payne. Still at a loss? His client is 
likely the best shooter in basketball history. Steph Curry
has won NBA championships, MVPs, and made an amazing 100 three pointers in 
a row. Why would he need a coach? In Steph's own words:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I appreciate [Brandon's] perspective on things — everything from watching game film and cutting it up to advice and direction on &lt;strong&gt;reaching my full potential&lt;/strong&gt;... And we created a vision for where I wanted to be in terms of ballhandling, footwork, balance and, of course, &lt;strong&gt;accountability&lt;/strong&gt;.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A coach is a partner who can help with reaching full potential and perhaps more
importantly accountability.&lt;/p&gt;
&lt;p&gt;Those who are at the top of their game use coaches: CEOs, athletes,
entrepreneurs, and programmers. Why? Because they invest in their future. A
coach can help identify and cure weaknesses and further strengthen existing
skills. I could go on, but the point is that people who are serious about
something invest in it, and coaching is probably the best way to improve.&lt;/p&gt;
&lt;p&gt;A "free" option for coaching might be a more senior colleague who is willing
to let you tag along and pair program. If this includes mentoring along the
way, this can be invaluable. Some companies encourage this sort of behavior
while others view it as "off task" and a waste of precious developer time.&lt;/p&gt;
&lt;h2&gt;Workshops &amp;amp; Live Courses&lt;/h2&gt;
&lt;p&gt;Similar to corporate training, workshops and live courses are the equivalents
for an individual. Sometimes smaller companies or startups invest in one-off
trainings for individuals when they don't have a whole team to train.&lt;/p&gt;
&lt;p&gt;These courses lack many of the bonding and insight moments that come with team
training, but if you want to grok something quickly, these are the way to go.
Again, an experienced trainer can pinpoint weaknesses or gaps and develop them
much quicker than going solo.&lt;/p&gt;
&lt;p&gt;These may appear to cost more, but consider they can be like drinking from a firehose. You get comments like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;I felt like I learned 3 months worth of material in 3 days!&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After three days, most students are off and running with their new skills.
Thrilled to be using thier new knowledge.&lt;/p&gt;
&lt;p&gt;I was once in a training, and after demoing some code, a participant did a face
palm. I asked what was the matter and they replied that the one line of code I
had just showed them had taken them almost a month to implement. 🤦‍&lt;/p&gt;
&lt;h2&gt;Projects&lt;/h2&gt;
&lt;p&gt;Invariably, some are not sold on learning fast and thoroughly. (They have not 
allocated budget to invest in the future.)&lt;/p&gt;
&lt;p&gt;At this point, there is a new requirement for learning Python (or 
any new skill), &lt;strong&gt;sustained motivation&lt;/strong&gt;. Sitting through a couple of days of training
is really easy compared to this, but I digress.&lt;/p&gt;
&lt;p&gt;A great way to pick up Python is to choose a project and implement it in Python.
In fact, this is how I learned Python. Was my code idiomatic Python when I was done?
Nope, I was pretty clueless, but I enjoyed the language features that I did use.
Did I have an expert helping me? No, it was the blind leading the blind. Was
it quick? Somewhat, but again I wasn't using the tools how I should be. However,
it did give me a good chance to play around with the language and compare it
to other tools that I was used to.&lt;/p&gt;
&lt;p&gt;If you have a hobby project that you are itching to do, or your boss is 
breathing down your neck about your next task, consider using this
as a forcing function to get familiar with Python. There can be some inherent 
motivation here to learn.&lt;/p&gt;
&lt;h2&gt;Videos and On-demand Training&lt;/h2&gt;
&lt;p&gt;For those with sufficient self-motivation, on-demand video courses can
be excellent. Again, the quality of the material can vary. You might 
want to consider if you are acquiring the courses from sources that
focus on the topics at hand or if they are trying to be everything to
everyone. &lt;/p&gt;
&lt;p&gt;Over the years, many have asked me for training and I ask them how big their
team is. When the response was "just me", I felt bad, but in the past year I
have been developing a library of training for such individuals in addition to
my corporate training. (Indeed, this can be complementary to corporate training
as review material.)&lt;/p&gt;
&lt;p&gt;I think my material is wonderful (but also realize that I'm heavily biased),
and am willing to share my thoughts about other platforms and their pros and cons.&lt;/p&gt;
&lt;p&gt;Again, the lack of budget might be a concern for some. I offer discounts to
individuals not from the world's 30 wealthiest countries (or those laid off due
to Covid19 and students). Still, for some, their willingness to invest in
learning consists of spending no money but lots of time. (I hope you can
see that I think this is the wrong tradeoff, especially for professionals).&lt;/p&gt;
&lt;p&gt;In that case, most courses are paid courses. However, there are thousands if 
not millions of hours of free content on Youtube. These vary in quality of 
content, audio, and video. However, you can strike gold with these. &lt;/p&gt;
&lt;p&gt;Unless you come across some University course (which might lean more theoretical
and lacking application or at least experience in the battlefield), you will
be picking up nuggets here and there without a coherent learning path. Again,
not an effective use of time, in my opinion, but if the only currency you are
willing to spend is time, this is an option.&lt;/p&gt;
&lt;h2&gt;Books&lt;/h2&gt;
&lt;p&gt;The final category of my learning options is the written word. You should
ask yourself (or your company) "what are you willing to invest?". Many companies
are willing to reimburse book purchases.&lt;/p&gt;
&lt;figure&gt;
&lt;img src='/static/img/books.jpg' class='img-fluid' alt='Lots of books'/&gt;
&lt;figcaption&gt;Some of the books that I have written&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Why are books a good investment? Because the author was forced to fill out a
proposal form that required that they think about taking the end-user, aka
the reader, aka you, down a learning path. During the writing process, there
are editors and reviewers whose purpose is to ensure that the learning 
happens.&lt;/p&gt;
&lt;p&gt;Having written a few books (and seeing the reader feedback) as well as reading
and reviewing many technical books, I'm a huge proponent of books. However, if
you just read books, science tells us that you will not retain most of what
you read. To retain information, you will need to apply it (or work on getting
it into long term storage). This is probably my biggest beef with many books,
they do not include exercises, or they are hard to apply (before they leave
short-term memory).&lt;/p&gt;
&lt;p&gt;Again, there are books of differing quality. I tend to read a lot of Python 
books, and am more than willing to proffer my opinion.&lt;/p&gt;
&lt;p&gt;We are now back at the "lack of budget" folks. One option is the library. However most
libraries do not have up-to-date material. Offering to be a technical reviewer might
be a way to get your hands on newer material, but generally these are 
jobs that are requested from you rather than the other way around.&lt;/p&gt;
&lt;p&gt;The cheap option, that sadly has suffered in the past few years with the rise
of Twitter and blogging platforms like Medium, is the blog. This is the Youtube of
written content. There is a lot out there. Some is gold, some is outdated. But,
these posts generally lack a learning path and are not great for taking you
along on a learning journey.&lt;/p&gt;
&lt;h2&gt;Get Started Learning&lt;/h2&gt;
&lt;p&gt;There you have it. My (obviously biased) thoughts around the most effective ways
to learn Python after having been involved in almost every aspect of this for 
the past twenty years. Feel free to reach out on Twitter or LinkedIn to discuss.&lt;/p&gt;</content><category term="misc"/><category term="python"/></entry><entry><title>Why Write a Book?</title><link href="https://www.metasnake.com/blog/authoring.html" rel="alternate"/><published>2020-11-13T00:00:00-07:00</published><updated>2020-11-13T00:00:00-07:00</updated><author><name>Matt Harrison</name></author><id>tag:www.metasnake.com,2020-11-13:/blog/authoring.html</id><summary type="html">&lt;p&gt;Why Write?&lt;/p&gt;</summary><content type="html">&lt;h2&gt;The New Business Card&lt;/h2&gt;
&lt;p&gt;I never considered myself an &lt;em&gt;author&lt;/em&gt;. But after answering many one-off calls asking for advice on book writing and realizing that I have published over a dozen books on Amazon, I guess I should admit it. I am an author!&lt;/p&gt;
&lt;figure class='border'&gt;
&lt;img src='/static/img/books.jpg' class='img-fluid' alt='bunch of books'/&gt;
&lt;figcaption&gt;Many of the books that I have written over the years.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Authoring has never been easier. Let's chat about some of the reasons for writing a book and see if they might resonate with you. &lt;/p&gt;
&lt;p&gt;Note: I'm specifically talking about writing a non-fiction technical book. I've yet to tackle fiction (other than publishing a book of short stories from a book writing class I taught at the local elementary school.)&lt;/p&gt;
&lt;h2&gt;Lend me your ears and I'll sing you a song&lt;/h2&gt;
&lt;p&gt;Is there a story inside of you? I just said that I was not referring to fiction, so what does this even mean?&lt;/p&gt;
&lt;p&gt;I started my writing journey after preparing and delivering a half-day Python tutorial. I was very excited about the tutorial's content and felt that it was "the tutorial that I wanted when I was learning Python." The tutorial feedback was extremely positive, and the tutorial had been accepted to be offered at another conference. &lt;/p&gt;
&lt;p&gt;Rather than just rewriting my slides in preparation for the upcoming conference, I figured why not take this awesome content and turn it into a book? It should not be too hard, plus I had three months before the conference, so this would allow me to double-down and learn the material inside out. &lt;/p&gt;
&lt;p&gt;Long story short, it took a bit more than three months to write the book, but this effort became the first version of what is now &lt;a href="https://www.amazon.com/Illustrated-Guide-Python-Walkthrough-Illustrations/dp/1977921752/ref=sxts_sxwds-bia-wc-p13n1_0?crid=BP7UUYGQWD9C&amp;amp;cv_ct_cx=illustrated+guide+to+python+3&amp;amp;dchild=1&amp;amp;keywords=illustrated+guide+to+python+3&amp;amp;pd_rd_i=1977921752&amp;amp;pd_rd_r=a4fbe37f-a03e-42ea-8e0d-1a67b3db4573&amp;amp;pd_rd_w=ctKMv&amp;amp;pd_rd_wg=eLACG&amp;amp;pf_rd_p=1835a2a9-7ed8-48dc-ad07-fcd7527bd2bc&amp;amp;pf_rd_r=H81VRR49YZ8SAYXMA9WD&amp;amp;psc=1&amp;amp;qid=1605381873&amp;amp;sprefix=illustrated+guide+to+p%2Caps%2C198&amp;amp;sr=1-1-80ba0e26-a1cd-4e7b-87a0-a2ffae3a273c"&gt;&lt;em&gt;Illustrated Guide to Python 3&lt;/em&gt;&lt;/a&gt;. And this kickstarted my path as an author.&lt;/p&gt;
&lt;p&gt;This seems to be a common occurrence. A (lead) engineer gets asked what resources they would recommend for ... and they come up empty. There are no good resources (or bikesheds that are their favorite color). So they set out to create their own. I have interviewed many authors who had this experience. They set out to create the resource they desired.&lt;/p&gt;
&lt;h2&gt;Recognition&lt;/h2&gt;
&lt;p&gt;After I published my book, I didn't want to make too much noise about it; because technical people realize that the value is in the product not the marketing or sales (how wrong I was). &lt;/p&gt;
&lt;p&gt;Then I had the coolest experience, I was walking down the hallway at work, and a colleague approached me and said, "Hey, aren't you the author of &lt;em&gt;Treading On Python&lt;/em&gt;?". I was dumbfounded. Without any mention on my part, the Amazon sales engine sold a book to someone who worked a few cubicles away from me. That felt awesome. But even better was that they had high praise for the book. Recognition is something that everyone craves.&lt;/p&gt;
&lt;p&gt;Many potential authors want this recognition. Perhaps it can be better described as the author wants a "book with an animal on the cover" (along with their name).&lt;/p&gt;
&lt;figure class='border'&gt;
&lt;img src='/static/img/animalcover.jpg' class='img-fluid' alt='framed OReilly book'/&gt;
&lt;figcaption&gt;The coveted animal cover.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I'm guilty of that. I have a framed copy of my book with a northern crested newt on the cover. (I wish it were a short-horned lizard, but I digress). This work has since been translated into seven languages and distributed around the world.&lt;/p&gt;
&lt;p&gt;That experience of serendipitous recognition has been repeated over the years. I don't have a paparazzi following me, but...&lt;/p&gt;
&lt;h2&gt;Hustle&lt;/h2&gt;
&lt;p&gt;Recognition opens doors.&lt;/p&gt;
&lt;p&gt;Many authors (or would-be authors) are interested in "the hustle." This could be looking for side gigs, augmenting income, looking for a better job, or starting consulting.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Book writing is an excellent business card&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;One of my author friends, Mark Beckner, put it this way in his book &lt;a href="https://www.amazon.com/Coders-Path-Wealth-Independence/dp/1484204220/ref=sr_1_1?dchild=1&amp;amp;keywords=the+coders+path+to+wealth+and+independence&amp;amp;qid=1605382078&amp;amp;s=books&amp;amp;sr=1-1"&gt;&lt;em&gt;The Coder's Path to Wealth and Independence&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you publish intelligently, your business will be transformed. 
If you write with the intention that &lt;em&gt;your publication will create unexpected opportunities&lt;/em&gt;, it will enable you to move to a new level in your business.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I have found this to be true. And I know and have spoken with many other authors who had this experience.&lt;/p&gt;
&lt;p&gt;It is well known that the process of writing helps you to understand a subject better. You have literally &lt;em&gt;written the book on the subject&lt;/em&gt;. With self-publishing (or even purchasing bulk copies from your publisher), you can use your book as a cost-effective business card booster. (In the current Covid-19 climate, this is a little harder. I have a bookshelf of books I meant to deliver to (potential) clients this year at conferences.)&lt;/p&gt;
&lt;p&gt;This opens the doors to opportunities that would not come your way even if you were an expert in said technology.&lt;/p&gt;
&lt;p&gt;Part of the hustle is money. While I know many authors who have sold six figures worth of books, these tend to be outliers. However, many authors I know have indicated that though they earned minimum wage from the writing, they have indirectly profited much more after the book from side gigs, job opportunities, and more.&lt;/p&gt;
&lt;h2&gt;Taking the Plunge&lt;/h2&gt;
&lt;p&gt;Having said this, writing a book is a marathon. Many have sprinted out of the gate only to fail. (I've been approached by a few publishers to "become a second author" on an in-progress book, which is code for "the author burned out").&lt;/p&gt;
&lt;p&gt;Have you considered writing a book? I've created a course that walks from ideation to holding a book in your hand. It discusses the tradeoffs of self-publishing and going with a publisher, how to outline, what tools to use, how to get distribution, ebook and physical book tips, audiobook creation, and more. I've come full-circle. This is the course I wanted 10 years ago when I set out to write my first book.&lt;/p&gt;</content><category term="misc"/><category term="authoring"/></entry><entry><title>Learn to use the assign method in Pandas (or how to deal with SettingWithCopyWarning issues)</title><link href="https://www.metasnake.com/blog/pydata-assign.html" rel="alternate"/><published>2020-04-03T00:00:00-06:00</published><updated>2020-04-03T00:00:00-06:00</updated><author><name>Matt Harrison</name></author><id>tag:www.metasnake.com,2020-04-03:/blog/pydata-assign.html</id><summary type="html">&lt;p&gt;Do not use index assignment&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;strong&gt;TLDR:&lt;/strong&gt; Favor the &lt;code&gt;.assign&lt;/code&gt; method, and you will not deal with &lt;code&gt;SettingWithCopyWarning&lt;/code&gt; issues.&lt;/p&gt;
&lt;figure class='border'&gt;
&lt;img src='/static/img/pandas-err2.png' class='img-fluid' alt=Python TLDR'/&gt;
&lt;figcaption&gt;Master the &lt;tt&gt;.assign&lt;/tt&gt; method and not index assignment!&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;!--
## Pandas King

I will proclaim myself the Pandas King. I have used pandas since it came out. I
have taught thousands pandas. I created one of the first video courses on
Pandas. I have written three books on Pandas and am working on another. Listen
to the Pandas King.
--&gt;

&lt;h2&gt;Bad Code&lt;/h2&gt;
&lt;p&gt;Today I'm going to show you the solution to the dreaded
&lt;code&gt;SettingWithCopyWarning&lt;/code&gt; error that you eventually run into, but no
one seems to explain it or give you a solution that you can understand.&lt;/p&gt;
&lt;p&gt;I just saw &lt;a href="https://www.kdnuggets.com/2020/04/stop-hurting-pandas.html"&gt;another article discussing&lt;/a&gt; it today and thought I would share
the best solution (that no one else talks about).&lt;/p&gt;
&lt;p&gt;Here's the data referred to in the above article:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;df = pd.DataFrame({
  &amp;#39;x&amp;#39;:[1,5,4,3,4,5],
  &amp;#39;y&amp;#39;:[.1,.5,.4,.3,.4,.5],
  &amp;#39;w&amp;#39;:[11,15,14,13,14,15]})
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The quest with this toy data is to change all values in the &lt;em&gt;y&lt;/em&gt; column to 50 when
the &lt;em&gt;x&lt;/em&gt; column is greater than 3. Most try to do this by using indexing operations
to filter out the appropriate rows and then doing an index assignment.&lt;/p&gt;
&lt;p&gt;If you do an index operation directly on &lt;code&gt;df&lt;/code&gt;, the update does not work. And you see
the dreaded &lt;code&gt;SettingWithCopyWarning&lt;/code&gt; warning:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;df[df[&amp;#39;x&amp;#39;]&amp;gt;3][&amp;#39;y&amp;#39;] = 50
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;figure class='border'&gt;
&lt;img src='/static/img/pandas-err1.png' class='img-fluid' alt=Python TLDR'/&gt;
&lt;figcaption&gt;The dreaded warning!&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The issue with this code is that &lt;code&gt;df[df['x']&amp;gt;3]&lt;/code&gt; does not return the original dataframe. So the subsequent index assignment, &lt;code&gt;['y'] = 50&lt;/code&gt;, updates the new dataframe and not &lt;code&gt;df&lt;/code&gt;. In effect, you create a new dataframe, assign to it, and do not capture it to a variable, so it is immediately available to be garbage collected.&lt;/p&gt;
&lt;p&gt;The warning includes a tip to use &lt;code&gt;.loc&lt;/code&gt; for indexing instead. Here is an example that works:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;df.loc[df[&amp;#39;x&amp;#39;]&amp;gt;3,&amp;#39;y&amp;#39;] = 50
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I recommend that you do &lt;em&gt;not&lt;/em&gt; use this solution. I have a better solution below.&lt;/p&gt;
&lt;h2&gt;Three Rules for Better Pandas&lt;/h2&gt;
&lt;p&gt;However, I'll add three more rules of thumb that I have found to make pandas
code easier to understand and less prone to errors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Do not mutate objects&lt;/li&gt;
&lt;li&gt;Favor chaining operations&lt;/li&gt;
&lt;li&gt;Do not use assignment (the &lt;code&gt;=&lt;/code&gt; operator) in pandas&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The above code mutates &lt;code&gt;df&lt;/code&gt;. However, most pandas operations do not mutate. For feeble-minded people like me, mixing mutation and immutability leads to confusing code and errors. My preferred solution to the above is this code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;50&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In fact, whenever I create a new column (or update one) in pandas, I try to do it with the &lt;code&gt;.assign&lt;/code&gt; method. This code also requires understanding the &lt;code&gt;.where&lt;/code&gt;, method which takes some getting used to but obeys my three rules above.&lt;/p&gt;
&lt;h2&gt;A Chained Example&lt;/h2&gt;
&lt;p&gt;Here is an example from Chapter 5 of the &lt;em&gt;The Pandas 1.x Cookbook&lt;/em&gt;. This code loads vehicle data from the fueleconomy.gov website. It applies a chain of operations to the dataframe when creating the &lt;code&gt;data&lt;/code&gt; variable. &lt;/p&gt;
&lt;p&gt;First, it filters out the makes that are Ford, Tesla, BMW, or Toyota with this line &lt;code&gt;[fueleco.make.isin(makes)]&lt;/code&gt;. (It could
have used &lt;code&gt;.loc&lt;/code&gt; here as well). Next, it assigns a column, &lt;em&gt;SClass&lt;/em&gt;, that is
created from an inlined function (a &lt;code&gt;lambda&lt;/code&gt; function) with this line &lt;code&gt;.assign(SClass=...&lt;/code&gt;. If you use a function
with the &lt;code&gt;.assign&lt;/code&gt; method, you have access to the intermediate dataframe, referred to as &lt;code&gt;df_&lt;/code&gt; in the code. The lambda function dispatches to the &lt;code&gt;generalize&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;generalize&lt;/code&gt; function is a function I use all over the place when refining data. It takes a column and a list of tuples with match names and new values in it. It also accepts a default value. It loop over the list returns a new series where the match names are replaced with the new names. If there is no match, the default value is used. This function can be useful if you have a bunch of 
categorical data and want to limit it to a smaller subset:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;#39;&lt;/span&gt;&lt;span class="nl"&gt;https:&lt;/span&gt;&lt;span class="c1"&gt;//github.com/mattharrison/datasets/raw/master/data/vehicles.csv.zip&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;fueleco&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;generalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;match_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;match_name:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;mask&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;None:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mask&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mask&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;mask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;

&lt;span class="n"&gt;makes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Ford&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Tesla&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;BMW&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Toyota&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;]&lt;/span&gt;
&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fueleco&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fueleco&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;makes&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SClass&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;lambda&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;df_:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;generalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VClass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[(&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Seaters&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Car&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Car&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Car&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Utility&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;SUV&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;),&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;(&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Truck&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Truck&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Van&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Van&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;van&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Van&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;),&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;(&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Wagon&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Wagon&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;)],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;))&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[[&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;SClass&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;VClass&lt;/span&gt;&lt;span class="p"&gt;&amp;#39;]]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;figure class='border'&gt;
&lt;img src='/static/img/pandas-err3.png' class='img-fluid' alt=Python TLDR'/&gt;
&lt;figcaption&gt;Master the &lt;tt&gt;.assign&lt;/tt&gt; method and gain superpowers!&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Try not to mutate data when using pandas. Even the pandas core developers say that you should not use mutation. If you use method chaining (note that index assignment does not work with chaining!), you will not mutate data. You will not have to deal with the &lt;code&gt;SettingWithCopyWarning&lt;/code&gt;. Your code will be easier to read because it will read like processing steps. &lt;/p&gt;
&lt;p&gt;If you want to see examples of pandas code that obey these rules see my latest book, &lt;a href="https://store.metasnake.com/effective-pandas-book"&gt;Effective Pandas&lt;/a&gt; or &lt;a href="https://twitter.com/__mharrison__"&gt;follow me on twitter where I rant on such topics&lt;/a&gt;.&lt;/p&gt;</content><category term="misc"/><category term="python"/><category term="anaconda"/></entry><entry><title>Setting up a Python Data Science Environment</title><link href="https://www.metasnake.com/blog/pydata-dev.html" rel="alternate"/><published>2020-03-06T00:00:00-07:00</published><updated>2020-03-06T00:00:00-07:00</updated><author><name>Matt Harrison</name></author><id>tag:www.metasnake.com,2020-03-06:/blog/pydata-dev.html</id><summary type="html">&lt;p&gt;Anaconda or pip&lt;/p&gt;</summary><content type="html">&lt;figure&gt;
&lt;img src='/static/img/pipvsconda.png' class='img-fluid' alt=Python TLDR'/&gt;
&lt;figcaption&gt;You can set up your environment using either method with three commands&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Here are instructions for getting a Python stack installed on Windows, Mac, and Linux. These examples will use Python 3 (which I recommend as Python 2 is no longer being developed). &lt;/p&gt;
&lt;p&gt;You have two main options for installing a Python environment. You can use the Python executable that you can get from &lt;a href="https://www.python.org"&gt;the Python website&lt;/a&gt;, or you can use the Anaconda distribution. I will show you both. If you are new to Python, only doing "data science" work, or using Windows, I recommend using Anaconda.&lt;/p&gt;
&lt;h2&gt;Using Anaconda&lt;/h2&gt;
&lt;figure&gt;
&lt;img src='/static/img/conda-tldr.png' class='img-fluid' alt='Conda TLDR'/&gt;
&lt;figcaption&gt;&lt;strong&gt;TLDR:&lt;/strong&gt; Use these to create an environment using Anaconda&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Anaconda is both a product and a company. The company supports Python data tooling and makes the distribution available as a free product, but also as a supported enterprise paid for product. This page will demo the free option, but I'm assuming that the paid product is similar after install. There are versions for both Python 3.x and Python 2.7. Make sure you use the Python 3.x version.&lt;/p&gt;
&lt;p&gt;The Anaconda distribution includes "Python" it just has some extras. It uses its own package system to make it simple to create working Python environments on most platforms. The steps you need to take if you want to use it are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Install Anaconda (or Miniconda)&lt;/li&gt;
&lt;li&gt;Create an environment&lt;/li&gt;
&lt;li&gt;Install packages into the environment&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Install Anaconda&lt;/h3&gt;
&lt;p&gt;You have two options for installing Anaconda (the product). The first is to install the whole kitchen sink, which is referred to as the "Anaconda Distribution" a 600MB+ download that includes many common libraries for machine learning, data analysis, and visualization. You can &lt;a href="https://www.anaconda.com/distribution/"&gt;download it here&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;The other option is to use Miniconda. This is a smaller download that does not include various libraries but rather lets you download and install them on demand. You can &lt;a href="https://docs.conda.io/en/latest/miniconda.html"&gt;download it here&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;(Many of my clients work inside a firewall and should use the Anaconda distribution that is available locally inside of their firewall.)&lt;/p&gt;
&lt;p&gt;After you have installed Anaconda or Miniconda, you should have an executable called &lt;code&gt;conda&lt;/code&gt; available. Test out that you have it. On UNIX platforms (Mac and Linux) open a terminal (if you are on Mac, you can hit Command-space and then type "Terminal" and hit enter). On Windows, go to the start menu and search for "Conda Prompt". Type into the terminal or command prompt:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;conda --version
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And it should print out the version, something like &lt;code&gt;conda 4.7.5&lt;/code&gt;. If it does not do that, then you did not install Anaconda successfully.&lt;/p&gt;
&lt;h3&gt;Create an Environment&lt;/h3&gt;
&lt;p&gt;After you have installed the &lt;code&gt;conda&lt;/code&gt; utility, you will need to make an "environment." An environment is a sandboxed installation of Python libraries and utilities. The purpose of an environment is to allow per project library dependencies. &lt;/p&gt;
&lt;p&gt;For example, I consult with different clients. If I have multiple clients over the years, they might use different versions of libraries. Say, for example, client A is using Pandas 0.19, client B Pandas 0.25, and client C Pandas 1.0.1. Pandas in generally is pretty good about backward compatibility, but it does have breaking changes. Environments allow me to install specific packages for each client project. When I need to work on client A's work, I activate the environment for that project and have access to Pandas 0.19. When I need to shift to client C, I activate the corresponding environment and have access to Pandas 1.0.1.&lt;/p&gt;
&lt;p&gt;To create an environment, you need to give it a name. For a machine learning class, you might create an environment named &lt;code&gt;mlclass&lt;/code&gt; (you can specify another name if you like). You can also specify a Python version for the environment. To &lt;strong&gt;create an environment with Python 3.7&lt;/strong&gt; from a terminal or Anaconda Prompt (on Windows) type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;conda create --name mlclass python=3.7
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can create as many environments as you like. I create them on a per-project basis. That way, I can jump into a project and make sure that I can work on it without dependency conflicts. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;After you create the environment, you should activate it&lt;/strong&gt;. This updates the PATH environment variable so that when you invoke &lt;code&gt;python&lt;/code&gt; or utilities, you use the executables found in the environment. Type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;conda activate mlclass
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After running this, your prompt should indicate that you are in the environment, and it will change to look like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(mlclass)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note that Anaconda, by default, stores its environments under your home directory. On my Mac, it would put it in &lt;code&gt;~/anaconda3/envs/mlclass&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Install Packages with Conda&lt;/h3&gt;
&lt;p&gt;At this point, you have installed &lt;code&gt;conda&lt;/code&gt;, created an environment, and activated the environment. You are now ready to install some packages. Here is &lt;strong&gt;a command to install some of the common data analysis packages&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;conda install notebook pandas scikit-learn seaborn xlrd districtdatalabs::yellowbrick py-xgboost notebook conda-forge::shap bokeh graphviz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The packages with colons in their names are specified as &lt;em&gt;channel::package&lt;/em&gt; name. Anaconda ships with certain packages, but libraries can create their own "channel" to ship different versions of their library (or even package their library for Anaconda) on a different cadence than the Anaconda release cycle.&lt;/p&gt;
&lt;p&gt;At this point, you should be ready to go with a basic installation. &lt;strong&gt;To launch Jupyter notebook type&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;jupyter notebook
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To learn more about the &lt;code&gt;conda&lt;/code&gt; tool, check out &lt;a href="https://docs.conda.io/projects/conda/en/latest/user-guide/index.html"&gt;the User Guide&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Installation with Python&lt;/h2&gt;
&lt;figure&gt;
&lt;img src='/static/img/pip-tldr.png' class='img-fluid' alt='Python TLDR'/&gt;
&lt;figcaption&gt;&lt;strong&gt;TLDR:&lt;/strong&gt; Use these commands on Linux or Mac if you do not want to use Anaconda. On Windows replace the second line with &lt;tt&gt;env\Scripts\activate&lt;/tt&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Note: If you are using Windows, it is recommended that you use Anaconda rather than this mechanism. Some of the scientific packages require installing and configuring a cross-compilation development environment, which can be annoying. If you are using a Mac and want to follow these instructions, it is recommended to install Python from Homebrew.&lt;/p&gt;
&lt;h3&gt;Install Python&lt;/h3&gt;
&lt;p&gt;If you are on Linux, use your package manager to install Python 3.x. On Mac, use Homebrew to install Python 3.x. If these instructions do not make sense to you, scroll up and use the instructions for Anaconda.&lt;/p&gt;
&lt;p&gt;After Python is installed, open a terminal and check the version. Type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;python3 --version
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It should say something like &lt;code&gt;python 3.7.3&lt;/code&gt;. Make sure that you installed Python 3 and not Python 2.&lt;/p&gt;
&lt;h3&gt;Create a Virtual Environment&lt;/h3&gt;
&lt;p&gt;Python 3 ships with the ability to create environments that are very similar to Anaconda environments. However, they are not the same. Python calls its environments "Virtual Environments", so I will follow suit here. A virtual environment will allow you to create a sandbox for Python on a per-project basis.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;To create a virtual environment named &lt;code&gt;env&lt;/code&gt;&lt;/strong&gt; in the current directory type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;python3 -m venv env
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;To activate this environment&lt;/strong&gt;, type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;source env/bin/activate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note that &lt;code&gt;source&lt;/code&gt; is a UNIX Bash command (so this will not work on Windows. If you really want to use Windows, even though I suggested against it with this mechanism, you would type &lt;code&gt;env\Scripts\activate.bat&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;At this point, your prompt should change to something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;(env)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Install Packages with Pip&lt;/h3&gt;
&lt;p&gt;With Python installed and your virtual environment activated, you are ready to install packages. We use the &lt;code&gt;pip&lt;/code&gt; tool to install packages from the &lt;a href="https://pypi.org"&gt;Python Package Index&lt;/a&gt;. If your virtual environment is activated, then &lt;code&gt;pip&lt;/code&gt; will install libraries into the virtual environment. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You should probably update pip with a new version&lt;/strong&gt;. Type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pip install -U pip
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;To install a base data science system&lt;/strong&gt; type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pip install notebook seaborn pandas scikit-learn xlrd yellowbrick xgboost shap bokeh graphviz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To launch Jupyter Notebook type the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;jupyter notebook
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There is a &lt;a href="https://pip.pypa.io/en/stable/user_guide/"&gt;User Guide for pip&lt;/a&gt; as well.&lt;/p&gt;
&lt;h2&gt;Other Options&lt;/h2&gt;
&lt;p&gt;Can you use Docker? Probably. The above are the simplest ways of getting your environment set up. There may be an existing Docker container you can leverage. But Docker is usually orthogonal to what I'm teaching. Also, the Docker images will probably be using one of the two techniques I described above.&lt;/p&gt;
&lt;p&gt;What about hosted services? Google COLAB is a great service (disclaimer: I'm a subscriber to their PRO account), but requires access to Google COLAB, which many of my clients do not have.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;Setting up a Python development environment is three lines of code once you have Python 3 or Anaconda installed. If you have questions about this, feel free to &lt;a href="https://twitter.com/__mharrison__"&gt;tweet them&lt;/a&gt;. I try to keep this page up to date as I point my clients to it.&lt;/p&gt;</content><category term="misc"/><category term="python"/><category term="anaconda"/></entry><entry><title>What I Use 2019 Edition</title><link href="https://www.metasnake.com/blog/what-i-use.html" rel="alternate"/><published>2019-11-20T00:00:00-07:00</published><updated>2019-11-20T00:00:00-07:00</updated><author><name>Matt Harrison</name></author><id>tag:www.metasnake.com,2019-11-20:/blog/what-i-use.html</id><summary type="html">&lt;p&gt;Physical gear I use&lt;/p&gt;</summary><content type="html">&lt;p&gt;It seems to be popular to share what gear you use. I'm pretty picky about some things, so I thought I would take a stab at it. Note that I'm just going to address physical hardware in this post, I'll save software for another post.&lt;/p&gt;
&lt;p&gt;&lt;img src='/static/img/desk.jpg' class='img-fluid' /&gt;&lt;/p&gt;
&lt;h2&gt;2015 Macbook Pro&lt;/h2&gt;
&lt;p&gt;I used Linux exclusively for over 15 years on ThinkPads, but due to the nature of my training and consulting got a Macbook in 2015. It is a decent piece of hardware. The screen went out on me a few years back, and now it seems the keyboard and trackpad are flaky sometimes. A few reboots seem to do the trick. Unless I'm training, I use an external keyboard and mouse, which oddly enough work even when the built-in devices do not. &lt;em&gt;Feb 2020 Update&lt;/em&gt; - I have &lt;a href="https://www.ifixit.com/Answers/View/313001/Keyboard+and+trackpad+don't+work,+loose+cable"&gt;replaced the cable for the trackpad&lt;/a&gt; which seems to have solved the problem. Annoying, but easy if you have the correct tools and spend five minutes watching Youtube.&lt;/p&gt;
&lt;p&gt;At the time it came out, the screen DPI was a wonder. Now it is a little more commonplace. I do most of my work on this machine. Again I will discuss software later. As of 2019, the 16inch version of this machine has reverted to using the same keyboard as I have. The butterfly keyboards of 2017-2019 were notoriously flaky, and I stayed away from those machines.&lt;/p&gt;
&lt;p&gt;The battery life is still decent on this. I take it with me when traveling, and it performs well. I like the aluminum body, which is unparalleled among laptop manufacturers. I wish I could upgrade the SSD and RAM like I could with my ThinkPads. Se la vie.&lt;/p&gt;
&lt;p&gt;My next laptop will probably be an Apple due to video editing software.&lt;/p&gt;
&lt;h2&gt;2017 Surface Book Pro&lt;/h2&gt;
&lt;p&gt;At some point, I realized that the vast majority of the world (and developers in said world) use Windows. I always missed my UNIX environment when forced to use Windows at work (in the NT days). Windows 10 is useable, and this device also travels with me (as both a backup and if I need to demo something on Windows).&lt;/p&gt;
&lt;p&gt;The device comes in handy as a tablet as well. I've used the stylus and found it to be nice when editing books. I was a technical reviewer for &lt;em&gt;Hands-On Unsupervised Learning Using Python&lt;/em&gt; and I liked being able to write on top of PDF's with the stylus.&lt;/p&gt;
&lt;p&gt;Another area where the Mac excels is the trackpad. It is far superior to the MS version. However, I much prefer the ThinkPad's TrackPoint to either. I know ... gasp, the terror!&lt;/p&gt;
&lt;h2&gt;Standing Desk&lt;/h2&gt;
&lt;p&gt;I started standing at work around 2011. My job at the time was pre-standing desk movement. So I needed to use an adapter on top of my sitting desk. I used an &lt;a href="https://amzn.to/2QzeKrD"&gt;Ergo Desktop Kangaroo Pro&lt;/a&gt; This worked ok. It was maybe not quite as stable but was able to transform from sitting to a standing position without falling over.&lt;/p&gt;
&lt;p&gt;I mostly work from my home office these days and use a &lt;a href="https://www.amazon.com/Tresanti-Adjustable-Height-Desk-1334060/dp/B081DBGJ8G/ref=sr_1_7?keywords=tresanti+desk&amp;amp;qid=1574288771&amp;amp;s=office-products&amp;amp;sr=1-7"&gt;Tresanti Desk&lt;/a&gt;. I purchased mine at Costco, and I have few regrets. I'm 6'4", and the top hieght works for me. It has a glass top which my kids have used to write notes to me with whiteboard markers. &lt;/p&gt;
&lt;p&gt;There are 3 USB outlets at the side, and no this is not a MIDI device, they are only used for charging. On that note, I have an &lt;a href="https://www.ikea.com/us/en/p/signum-cable-management-horizontal-silver-color-30200253/"&gt;IKEA Signum "Cable management"&lt;/a&gt; drilled into the bottom of the backside of the table. In the Signum is an &lt;a href="https://www.amazon.com/gp/product/B00C631EYU/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&amp;amp;psc=1"&gt;Anker Dual Display Universal Docking Station&lt;/a&gt;. As you can tell from the photo, I'm not particularly concerned with eliminating wires. But it would be nice to have USB hub functionality in the desk.&lt;/p&gt;
&lt;p&gt;Because it has a glass top mounting stands to it can prove challenging. My monitor stand works with it, but only because I could disassemble the clamp for it.&lt;/p&gt;
&lt;p&gt;My other issue with this desk is the size. When I'm running a remote training and using the Mac and Windows, it can get a little crowded. I also use physical notes, so almost every bit of space is used.&lt;/p&gt;
&lt;p&gt;I'm a huge fan of taking breaks during the day. Not only do they help your body; they help you with productivity. I recommend getting a standing desk. Do you have to stand eight hours a day? No. I used to stand most of the day. These days I sit most of the day because that feels better for my body. But I will still mix it up. I think the key is to be aware of your body and posture and take care of it.&lt;/p&gt;
&lt;p&gt;Another thing I recommend if you are going the standing route is to pick up a padded mat to stand on.&lt;/p&gt;
&lt;h2&gt;ErgoDox Keyboard&lt;/h2&gt;
&lt;p&gt;I picked up an ErgoDox keyboard when Drop (the company formerly known as MassDrop) offered them initially. I was using a Unicomp (with a TrackPoint!), but my fingers were telling me that I needed to do something else. Come to think of it, that time probably correlated to when I was writing the first edition of what is now &lt;em&gt;Illustrated Guide to Python 3&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I knew I wanted a keyboard that was ortholinear, mechanical, and split. Bonus points in that the firmware is opensource and you can program it how you want. This keyboard is an acquired taste, but I liked mine so much that when Drop offered them again, I picked up a second (partially out of fear that I would never be able to purchase one again, and partially because I wanted another for home use). Since that time, it appears that the DIY mechanical keyboard group has flourished. You can now purchase completely assembled models, and there are dozens of riffs on split keyboards.&lt;/p&gt;
&lt;p&gt;I do not use QWERTY on this keyboard, but rather the &lt;a href="https://normanlayout.info/"&gt;Norman layout&lt;/a&gt;. Again, this is another acquired taste, but it has worked out for me. Also, I have keys that have a dual purpose. For example, I use emacs a lot. So my left thumb has &lt;em&gt;Control&lt;/em&gt; under it. But if I tap it and release, it fires the &lt;em&gt;Escape&lt;/em&gt; key.&lt;/p&gt;
&lt;p&gt;I typically do not take this keyboard with me when traveling. I took it to PyCon once when it was novel, but it is not really portable (I have a travel case for it) in that it is bulky, and TSA gives you weird looks when you travel with it.&lt;/p&gt;
&lt;p&gt;Again, you need to take care of yourself. Your fingers, wrists, and arms can suffer damage from too much use or non-ergonomic use. Take note and do what feels best.&lt;/p&gt;
&lt;h2&gt;Clearly Superior Technologies Trackball&lt;/h2&gt;
&lt;p&gt;Award for best-named company of 1995 goes to CST. &lt;/p&gt;
&lt;p&gt;When I got my ErgoDox, I was considering modding it to add a TrackPoint. In the meantime, my previous blog had a couple of entries on the ErgoDox, and they were popular enough such that I sent Drop enough purchases of ErgoDoxen that they sent me a "Thank You" gift. The CST trackball mouse was in that gift box. It seemed to be the answer I was looking for. And it fits nicely in between the split keyboard.&lt;/p&gt;
&lt;p&gt;I have also added additional "buttons" that plug into the mouse. I have them situated so that I can tap them with my palm. The left palm is a command modifier, and the right palm is the spacemacs leader key.&lt;/p&gt;
&lt;p&gt;Apparently, the ball is the size of a billiard ball. I'm not a big pool player, but that seems like a fancy mod.&lt;/p&gt;
&lt;p&gt;I also have two of these trackballs (one for "work" and one for home). As of 2019, CST seems to have retired and sold the business. Whether these high-quality devices will remain in production by the new owner remains to be seen. They are no longer available on Amazon. eBay lists one at over $400!&lt;/p&gt;
&lt;p&gt;Again, listen to your body. If it tells you something when you are mousing about, maybe you should look into a change. A trackball certainly uses different body movements.&lt;/p&gt;
&lt;h2&gt;External Monitor&lt;/h2&gt;
&lt;p&gt;I bought an Auria 27 inch external monitor about ten years ago. At the time, it was a high DPI monitor that got good reviews for the price point. I will probably replace it with a 34 inch 4k monitor soon, but it has served me well.&lt;/p&gt;
&lt;h2&gt;Vivo Laptop Monitor Mount&lt;/h2&gt;
&lt;p&gt;I purchased the &lt;a href="https://www.amazon.com/VIVO-Motion-Monitor-Articulating-STAND-V102C/dp/B074GBF93N/ref=sr_1_4?keywords=vivo+monitor+stand+laptop&amp;amp;qid=1574293128&amp;amp;s=office-products&amp;amp;sr=1-4"&gt;Vivo Laptop Monitor Mount&lt;/a&gt; in an attempt to get a little more real estate on top of my desk. This is a sturdy product that I enjoy, not in spark joy type of enjoy, but it does the job. It also makes standing more ergonomic as it enables me to raise my screen higher.&lt;/p&gt;
&lt;h2&gt;Audio-Technica BPHS1 Headset and Mic&lt;/h2&gt;
&lt;p&gt;I do up to a dozen virtual trainings per month, and this mic has served me well. The &lt;a href="https://www.amazon.com/gp/product/B003D87JI2/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&amp;amp;psc=1"&gt;Audio-Technica BPHS1&lt;/a&gt; has a long cable which allows me to walk around when teaching and not have to worry about standing in front of a mic. I also have a Blue Yeti, but this mic is more of a set it and forget it type. I feel like I'm always fussing with the levels on the Blue Yeti.&lt;/p&gt;
&lt;p&gt;This is an XLR mic, so you will need a mic preamp like the &lt;a href="https://www.amazon.com/gp/product/B005EHILV4/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&amp;amp;psc=1"&gt;Behringer Xenyx 302USB&lt;/a&gt; to use it with a USB interface.&lt;/p&gt;
&lt;p&gt;I have a long power outlet attached to the Signum, and I hang the mic off of that when it is not in use.&lt;/p&gt;</content><category term="misc"/><category term="keyboard"/></entry></feed>