This lesson on Combining DataFrames: SQL-Style Relational Merges is hands-on and example-driven. You will learn to combine disparate datasets using Pandas' powerful merge() function, mirroring SQL join logic. You will be able to select the appropriate join type (inner, outer, left, right) to control which rows are preserved and how to resolve column name conflicts in the resulting DataFrame.
What You'll Be Able To Do
- Execute SQL-style joins between two Pandas DataFrames using a common key.
- Select the appropriate
howparameter (inner, outer, left, right) to achieve desired row preservation. - Identify and handle missing data (NaN) resulting from non-matching keys in outer joins.
- Resolve duplicate column names by specifying custom suffixes during the merge operation.
- Utilize the
indicatorflag to track the origin (left, right, or both) of merged rows.
Detailed Concept Walkthrough
1. Relational Merging Fundamentals
pd.merge() combines two DataFrames based on shared values in a specified key column, acting like a database join. This ensures related data is accurately paired regardless of row index.
- Mechanism: The function requires two DataFrames and the
onparameter, which specifies the column containing the common key used for matching rows. - Under the Hood: Unlike simple concatenation or index alignment,
mergeexplicitly looks up and matches key values across the two tables. - Best Practice: Ensure the key column specified in
onhas consistent data types and spelling across both DataFrames for accurate matching.
import pandas as pd
df1 = pd.DataFrame({'city': ['New York', 'Chicago'], 'temp': [21, 20]})
df2 = pd.DataFrame({'city': ['New York', 'Chicago'], 'humidity': [68, 65]})
# Basic merge on the 'city' column
merged_df = pd.merge(df1, df2, on='city')
print(merged_df)
Key Takeaway: Merging uses key values, not row indices, to accurately combine related data from different sources.
2. Controlling Row Preservation (Join Types)
The how parameter determines which rows are included in the result based on whether their keys exist in the left, right, or both input DataFrames. This controls the scope of the resulting dataset.
- Mechanism: The default
how='inner'performs an intersection, keeping only rows where the key exists in both DataFrames. - Mental Model:
how='outer'performs a union, keeping all rows from both DataFrames and filling non-matching columns withNaN(Not a Number). - Execution Flow:
how='left'preserves all rows from the first (left) DataFrame (df1), whilehow='right'preserves all rows from the second (right) DataFrame (df2). - Syntax Rule: The
howargument must be explicitly set to 'outer', 'left', or 'right' if the default 'inner' behavior is not desired.
df1 = pd.DataFrame({'city': ['NY', 'Orlando'], 'temp': [21, 35]})
df2 = pd.DataFrame({'city': ['NY', 'SF'], 'humidity': [68, 75]})
# Outer join preserves all keys, filling missing data with NaN
merged_outer = pd.merge(df1, df2, on='city', how='outer')
print(merged_outer)
Key Takeaway: Choose the join type based on whether you need to preserve data unique to the left, right, or both input tables.
3. Suffixes and Indicators
When DataFrames share column names (other than the merge key), Pandas automatically appends suffixes to distinguish them; the indicator flag tracks row origin.
- Mechanism: Pandas automatically appends
_x(left) and_y(right) to conflicting non-key column names by default. - Best Practice: Use the
suffixesargument to provide meaningful labels (e.g.,suffixes=('_A', '_B')) for improved readability. - Practical Use: Setting
indicator=Trueadds a column named_mergeto the result, showing if the row came from 'left_only', 'right_only', or 'both'.
df_a = pd.DataFrame({'city': ['NY'], 'temp': [21]})
df_b = pd.DataFrame({'city': ['NY'], 'temp': [25]})
# Custom suffixes resolve the conflicting 'temp' column
result = pd.merge(df_a, df_b, on='city', suffixes=('_temp_A', '_temp_B'))
print(result)
Key Takeaway: Always anticipate column conflicts and use
suffixesfor clarity, andindicator=Truefor tracking data provenance.
Topics Covered in Combining DataFrames: SQL-Style Relational Merges
- Setup and Goal (0:00 - 0:45) — The instructor introduces two DataFrames (temperature and humidity) and the goal of combining them into a single table.
- Basic pd.merge() (0:45 - 1:30) — The basic syntax for
pd.merge()is shown, demonstrating that it matches data by key value (city) rather than row index. - Inner Join Default (1:30 - 2:50) — The default behavior is shown to be an inner join (intersection), keeping only the keys common to both DataFrames.
- Outer Join (Union) (2:50 - 3:55) — The
how='outer'argument is introduced to perform a union, preserving all keys and filling non-matching columns with NaN. - Left and Right Joins (3:55 - 5:20) — Left join preserves all rows from the first DataFrame, while right join preserves all rows from the second DataFrame.
- Tracking Row Origin (5:20 - 6:10) — Setting
indicator=Trueadds the_mergecolumn, which specifies if a row originated from the left, right, or both DataFrames. - Handling Column Conflicts (6:10 - 7:30) — When non-key columns are repeated, Pandas automatically appends
_xand_ysuffixes to distinguish them. - Custom Suffixes (7:30 - 8:00) — The
suffixesargument is used to override the default_xand_ywith custom, descriptive labels.
Python Cheat Sheet
-
pd.merge(df1, df2, on='key')— Combines two DataFrames on a common columnpd.merge(df1, df2, on='city') -
how='inner'— Keeps only rows with keys in both DataFramespd.merge(df1, df2, on='city', how='inner') -
how='outer'— Keeps all rows from both DataFrames (union)pd.merge(df1, df2, on='city', how='outer') -
how='left'— Keeps all rows from the first (left) DataFramepd.merge(df1, df2, on='city', how='left') -
suffixes=('_x', '_y')— Customizes labels for conflicting column namespd.merge(df1, df2, on='city', suffixes=('_temp', '_hum')) -
indicator=True— Adds a column showing the origin of each rowpd.merge(df1, df2, on='city', how='outer', indicator=True)
Comparison Table
| Join Type | Set Theory Equivalent | Rows Included | Missing Data |
|---|---|---|---|
| Inner (Default) | Intersection | Keys present in both | None |
| Outer | Union | Keys present in either | NaN in non-matching columns |
| Left | Left set plus intersection | All rows from left DF | NaN for unmatched right data |
| Right | Right set plus intersection | All rows from right DF | NaN for unmatched left data |
Common Pitfalls
- Mistake: Assuming
pd.mergeuses row index alignment by default. Avoid: Always specify the common key using theon='column'parameter. - Mistake: Forgetting that 'left' and 'right' are determined by argument order.
Avoid: Remember
df1is left anddf2is right inpd.merge(df1, df2, ...). - Mistake: Ignoring repeated column names in the source DataFrames.
Avoid: Use the
suffixesparameter to clearly label columns liketemp_Aandtemp_B. - Mistake: Using an inner join when trying to find unmatched records.
Avoid: Use
how='outer'orhow='left'/'right'to preserve non-matching keys.
FAQs
- What is the default join type if I don't specify
how? The default ishow='inner', which only returns rows where the key exists in both DataFrames (intersection). - Why do I see
NaNvalues in my merged DataFrame?NaNappears when you use an outer, left, or right join, and a row from one table has no matching key in the other table. - How can I tell which DataFrame a specific row came from after an outer merge?
Set
indicator=Truein themergecall; this adds a column named_mergeshowing 'left_only', 'right_only', or 'both'. - If both DataFrames have a 'temp' column, how does Pandas handle the conflict?
Pandas automatically appends
_xto the left column and_yto the right column, unless you specify custom suffixes.