Load a CSV into a pandas DataFrame and inspect its shape, columns, types and values before analysing it.
Why it matters
Almost every analysis starts the same way: someone hands you a file, usually a CSV, and asks a question about it. Before you can answer anything you need to get that file into a DataFrame and check what you actually have. Skipping that check is how analysts end up averaging a column that was secretly text.
The DataFrame in one minute
A pandas DataFrame is a table: rows, named columns, and an index (row labels, by default 0, 1, 2, ...). Each column is a Series, a one-dimensional array with a single data type (dtype), such as int64, float64, bool, datetime64 or text.
import pandas as pd
df = pd.DataFrame({
"sample": ["S1", "S2", "S3"],
"temp_c": [21.5, 22.1, 20.8],
})
df["temp_c"] # a Series
df["temp_c"].mean() # 21.466...
Loading a CSV
pd.read_csv reads a file path, a URL or any file-like object:
df = pd.read_csv("readings.csv")
df = pd.read_csv("https://example.org/data/readings.csv")
In the browser exercises there is no file system, so the data lives in a string and io.StringIO makes it look like a file:
import io
RAW = """station,date,temp_c,humidity
A,2026-03-01,4.5,81
B,2026-03-01,6.1,77
A,2026-03-02,5.2,79
"""
df = pd.read_csv(io.StringIO(RAW))
Options you will use often:
| Option | Use it when |
|---|---|
sep=";" | the file uses semicolons or tabs (sep="\t") |
usecols=["a", "b"] | you only need some columns |
parse_dates=["date"] | a column holds dates |
na_values=["-", "ERR"] | the file marks missing values with custom text (common markers such as empty cells, NA, n/a and NaN are recognised by default) |
dtype={"zip": str} | codes with leading zeros must stay text |
nrows=1000 | you want a quick look at a huge file |
encoding="latin-1" | you get a UnicodeDecodeError |
The first five checks
Run these every time you load data:
df.shape # (rows, columns), e.g. (3, 4)
df.head() # first 5 rows (df.tail() for the last)
df.columns # the column names
df.dtypes # the type of each column
df.info() # all of the above plus non-null counts
Then summarise the numbers:
df.describe() # count, mean, std, min, quartiles, max
df["station"].value_counts() # how often each value appears
df["station"].nunique() # number of distinct values
Each answer is a question about your data. Is the row count what you expected? Are the numeric columns really numeric? Does count in describe() show missing values? Does value_counts() reveal "A" and "a " as different stations?
Selecting numeric columns
select_dtypes filters columns by type, which is handy before summarising:
numeric = df.select_dtypes(include="number")
list(numeric.columns) # ['temp_c', 'humidity']
Reading dtypes
If a column you expected to be numeric shows as object or str, at least one value in it is not a clean number: a stray "ERR" or "-", a comma used as a decimal point, a unit such as "5 kg". pandas then keeps the whole column as text, and .mean() will fail or give nonsense. You will fix this in the next lesson; for now, notice it.
bad = pd.read_csv(io.StringIO("x\n1\n2\n-\n"))
bad.dtypes # x is text, because of "-"
fixed = pd.read_csv(io.StringIO("x\n1\n2\n-\n"), na_values=["-"])
fixed.dtypes # x float64, with NaN for the missing value
A worked example
df = pd.read_csv(io.StringIO(RAW), parse_dates=["date"])
print(df.shape) # (3, 4)
print(df.dtypes) # station text, date datetime64, temp_c float64, humidity int64
print(df["temp_c"].mean().round(2)) # 5.27
print(df["station"].value_counts()) # A 2, B 1
In four lines you know the size, the types, a headline number and the balance of stations.
Common mistakes
- Not looking at the data. Always run
head()andinfo()before computing anything. - Lost leading zeros. ZIP codes and IDs like
00742become742unless you passdtype={"zip": str}. - Header problems. If the first row is data, pass
header=Noneand setnames=[...]. If there are notes above the header, useskiprows. - Calling
df.shape().shapeis an attribute, not a method:df.shape. - Assuming dates are dates. Without
parse_datesorpd.to_datetime, a date column is just text.
Quick recap
pd.read_csvloads a file, URL orio.StringIOstring into a DataFrame.shape,head,dtypes,info,describeandvalue_countsare the first checks.- A numeric column showing as text means at least one dirty value.
select_dtypes(include="number")picks the numeric columns.
Try it
In the Do tab you will load a small weather-station CSV and record its shape, column names, numeric columns and a mean temperature.