What a DataFrame actually is
Index, columns, values, dtypes — the four parts every later method moves around.
df.indexdf.columnsdf.dtypesdf.shapedf["col"]df[["a", "b"]]Watch it happen
Play it through, or step back and forth yourself.
dfdf.indexthe row labelsdf.columnsthe column labelsdf.valuesthe raw 2-D blockdf.dtypesone type per column
This is a DataFrame: a table where both the rows and the columns carry labels. Almost everything confusing about pandas comes from forgetting that those labels exist. Let's pull it apart.
The idea
Most people meet pandas through a spreadsheet metaphor, and the metaphor holds for about ten minutes. Then something like filtered[1] throws a KeyError and the metaphor quietly stops working.
Here's the version that keeps working. A DataFrame is not a grid of cells with numbered rows. It's a set of columns, each one a typed array, glued to a shared set of row labels called the index. The index is a real object with real values. When you create a DataFrame without specifying one, pandas invents 0, 1, 2, … — and because those look exactly like positions, almost everyone assumes they are positions. They aren't, and the next lesson shows what happens when the two disagree.

One type per column
The other half of the picture is dtypes. Every column has exactly one type for all of its values. That's not a limitation, it's the trade that makes pandas fast: a column of int64 is one contiguous block of memory that numpy can rip through, not six million separate Python integers.
It also explains a wart you'll hit eventually — put a string into an integer column and the whole column changes type, because there's no such thing as one odd cell out.
Selecting: one bracket or two
df["cups"] gives you a Series — a single column, still carrying the index. df[["cups"]] gives you a DataFrame with one column. Same data, different container, and the difference matters constantly because Series and DataFrames have different methods. When you pass a list, you get a table back; when you pass a single label, you get a column back.

See it run
The lesson's code, ready to run and to fiddle with.
Putting the kettle on…
Starting up…
Worked example
not gradedAlready written and ready to go — press Run to see what it does, then change a number, a column name, anything, and run it again.
trydf is already loaded — six rows of chai sales.
Your turn
3 exercises. Write the code yourself, then press Check — a nudge and the answer are there if you want them.
Select just the cups column, as a Series.
Now select cups and revenue together, as a DataFrame with those two columns in that order.
Return the number of rows in df as a plain integer.
