Getting data in
read_csv, and the four calls to run before you trust a single row.
pd.read_csvparse_datesdtype=usecols.info()to_parquetWatch it happen
Play it through, or step back and forth yourself.
pd.read_csv("orders.csv")pd.read_csv("orders.csv") and you have a DataFrame. It takes a path, a URL, or anything file-like, and it guesses a great deal — the delimiter, the header row, and every column's type.
The idea
pd.read_csv takes a path, a URL, or anything file-like, and hands back a DataFrame. It also guesses a great deal — the delimiter, the header row, and every column's type — which is why the next paragraph matters more than this one.
Look at it before you trust it
Four calls, every time, before writing any analysis:
df.head() # do the values look like what you expected?
df.shape # did you get all the rows?
df.dtypes # is anything text that should be a number or a date?
df.info() # dtypes, non-null counts and memory, all at onceThen df.describe() for ranges — a -999 hiding in a column of ages shows up here — and df.isna().sum() for how much is missing, per column.
Five seconds of looking prevents the failure mode where you build an entire analysis on a date column that's actually strings.

Tell it what you meant
Fixing types on the way in is cheaper than fixing them afterwards:
pd.read_csv(
"orders.csv",
parse_dates=["date"], # real timestamps, not strings
dtype={"cups": "Int64"}, # nullable integer, not float
index_col="date", # use it as the index straight away
)
Files that fight back
Real CSVs are rarely tidy, and there's a keyword for each way they misbehave:
sep=";" # a different delimiter
skiprows=3 # junk above the header
header=None, names=[...] # no header row at all
na_values=["N/A", "-"] # what counts as missing in this file
decimal="," # European decimal commas
thousands="," # 1,234 as a number
encoding="latin-1" # when UnicodeDecodeError appearsna_values is the one people miss. If a file writes missing data as "N/A" or "-", pandas reads it as text — and your numeric column silently becomes strings.
Big files
usecols=["date", "cups"] # only the columns you need
nrows=1000 # sample while developing
chunksize=100_000 # stream it in piecesusecols is the biggest easy win — most analyses touch a handful of columns out of dozens.
Other sources, and writing back
pd.read_excel / read_json / read_parquet / read_sql / read_html
df.to_csv("out.csv", index=False) # index=False, nearly always
df.to_parquet("out.parquet") # smaller, faster, keeps dtypesTwo habits worth forming. Pass index=False to to_csv unless the index means something, or you'll grow a stray Unnamed: 0 column every round trip. And for anything you'll read more than once, use Parquet — it's columnar, compressed, and preserves dtypes exactly, so none of the guessing above has to happen again.
Practice
Write it yourself. The answer is there when you want it.
Putting the kettle on…
Starting up…
Write it yourself
not gradedRead orders.csv back and print the dtypes pandas guessed. Then read the same file again, parsing date as a date and asking for cups as Int64, and print those dtypes beside them. Finish with info() on the typed frame.
Your turn
4 exercises. Write the code yourself, then press Check — a nudge and the answer are there if you want them.
Read "orders.csv" and return its shape.
Read "orders.csv" parsing date as a real date, and return the dtypes.
Read only the date and cups columns from "orders.csv", and return the result's columns.
After reading "orders.csv", return how many values are missing per column.
