The DataFrame is home base
Session 2 gave you the NumPy array - one typed block of numbers. A pandas DataFrame is what you get when you give those arrays names, an index, and the ability to sit side by side in a table. It is where every remaining session lives: cleaning, grouping, joining, charting, and modeling all happen on the DataFrame. Get fluent moving around it and everything downstream gets easier. Everything today builds directly on the boolean masks and dtypes you just learned - pandas simply wraps them in labels.
value_counts, describe, nunique - to answer "what are the top job titles and hiring locations?"
Series and DataFrame 5 min live
Two structures, and the second is just many of the first stacked together. A Series is one labeled column: an index plus its values. A DataFrame is a dict of Series that all share one index - which is why columns line up row-for-row even after you filter or sort them.
LiveSeries: a labeled array2 min▶
A Series is a NumPy array (from Session 2) with an index bolted on. The values still have a single dtype and still support vectorized math and boolean masks - you've just gained labels, so you can ask for an element by name, not only by position.
When you run jobs["title"] on the LinkedIn data, you get a Series of 124,000 titles with the row index preserved. That preserved index is what lets you filter to "remote roles" and still line those rows up against their salaries and companies later - nothing drifts out of order.
Self-studyDataFrame: aligned columns2 min read▶
You'll rarely build a DataFrame by hand - read_csv does it for you - but seeing the dict-of-Series construction demystifies it. Every column shares the same index, so pandas can align them automatically even after reordering.
df.index, and reset it to a plain column with df.reset_index() when you need it as data.
Selecting: loc, iloc, and columns 5 min live
This is the one thing every pandas beginner trips on, so we slow down. There are two ways to pull rows out: .loc works by label, .iloc works by integer position. Confuse them and you either get an error or, worse, the wrong rows silently.
LiveColumns first, then loc vs iloc3 min▶
Selecting a column is the everyday move: df["salary"] returns a Series, and a list of names df[["title", "salary"]] returns a smaller DataFrame. Note the double brackets - a list inside the brackets - whenever you want more than one column back as a table.
.loc slices are inclusive of the end label; .iloc slices exclude the end position, just like normal Python. df.loc[0:4] gives five rows; df.iloc[0:4] gives four. When in doubt, print the shape.
Self-studyThe selection pattern table2 min read▶
| You want | Write | Returns |
|---|---|---|
| One column | df["salary"] | Series |
| Several columns | df[["title", "salary"]] | DataFrame |
| One cell by label | df.loc[10, "salary"] | a scalar |
| Rows + cols by label | df.loc[0:4, ["title"]] | DataFrame (end inclusive) |
| Rows + cols by position | df.iloc[0:5, 0:2] | DataFrame (end excluded) |
| Rows matching a condition | df.loc[df["remote"]] | filtered DataFrame |
Filtering, summaries, and maps 4 min live
Now the payoff. Filtering is the Session 2 boolean mask, now on a DataFrame. Summary functions collapse a column to an answer. And map/apply transform a column into a new one. Put them together and you can interrogate the LinkedIn data.
LiveBoolean filtering - and the parentheses rule2 min▶
Pass a boolean mask into the brackets and pandas keeps only the rows where it's True. Combine conditions with & (and) and | (or) - never Python's and/or - and wrap each condition in parentheses, because & binds tighter than > and will misfire without them.
LiveSummary functions + map/apply2 min▶
Summary functions turn a column into an answer: .mean(), .describe() (a whole stats block at once), .unique() and .nunique() (distinct values and how many), and the analyst's favorite, .value_counts(), which tallies each distinct value sorted from most to least common.
Run value_counts on the LinkedIn title column and you meet the dataset's messiest reality: "Data Analyst", "Data analyst", "Sr. Data Analyst", and "Data Analyst II" all count separately. Seeing that tally is the moment you understand why Session 4 spends real time normalizing titles - the counts lie until you clean them.
Load and build a working subset ★ 8 min · everyone builds
Load postings.csv, then cut it down to the columns we actually care about this session.
Inspect the subset: dtypes and head. Then practice iloc vs loc on it live.
.copy() can trigger pandas' "SettingWithCopyWarning" when you later assign into it. Copying up front keeps the raw frame pristine (a Session 1 habit) and silences the warning.
Filter to data roles, count the leaders ★ 8 min · everyone builds
This is the first real "answer a question" moment. Filter the postings down to data / analytics / AI roles by matching the title text.
Then value_counts the top titles and top locations in that slice.
The na=False matters: some titles are missing, and without it str.contains returns NaN for those rows and the mask breaks. This is the everyday texture of real data work - a tiny flag that separates code that runs from code that errors on row 5,000. You'll hit this exact pattern all course long.
Build a derived column ★ 5 min · follow along
Create a new column from existing ones and assign it back with df["newcol"] = .... We'll flag remote roles.
str.contains(...) is vectorized and fast (it's NumPy underneath - Session 2). .apply(lambda ...) loops row by row in Python, so save it for logic that has no vectorized form. On 124k rows the difference is noticeable.
This week ◐ 40 min total
- Do Kaggle Pandas lessons 1-3 exercises (Creating/Reading/Writing, Indexing & Selecting, Summary Functions & Maps). They're free and mirror today exactly.
- Answer the headline question on the real data: what are the top 10 job titles and the top 10 hiring locations across all postings? Save the two
value_countsoutputs - Session 6 will chart them. - Practice loc vs iloc until it's automatic: pull the same three cells three different ways and confirm they match.
- Filter twice: once with a numeric threshold on salary, once combining two conditions with
&and parentheses. Print the shape each time. - Read McKinney ch5 (Getting Started with pandas) - the canonical, free, open-access reference for everything today.
Three questions before you go 🎯 ◐ 90 seconds
1 · What's the difference between .loc and .iloc?
loc reads like a name (row labeled 0), iloc reads like a counter (the first row). Boolean masks go with loc.
2 · How do you keep rows where salary > 100000 AND the role is remote?
On Series you use & / |, not Python's and/or, and each condition needs its own parentheses because & binds tightly.
3 · What does value_counts() do?
It's the fastest way to see the shape of a categorical column - and on the messy title column it also reveals why cleaning is coming in Session 4.
Official sources covered
This session teaches the working content of the free Kaggle Pandas micro-course, the official pandas user guide, and Wes McKinney's open-access Python for Data Analysis (3e). Certificates and graded exercises stay on those platforms - links provided.