Selecting & Filtering Data
.loc and .iloc are how you pull specific rows and columns out of a DataFrame — one works by label, the other by position, and mixing them up is the most common early source of confusion in pandas.
Selecting a column
import pandas as pd
df = pd.DataFrame({
"name": ["Maya", "Sam", "Priya", "Leo"],
"score": [88, 92, 79, 95]
})
print(df["score"])
0 88 1 92 2 79 3 95 Name: score, dtype: int64
df["score"] pulls out a single column as a Series. df.score works too when the column name is a valid Python identifier, but df["score"] is the safer habit — it also works for column names with spaces or that collide with DataFrame method names.
.loc: select by label
.loc[row_labels, column_labels] selects using the actual index and column names:
print(df.loc[1, "name"]) print(df.loc[0:2, ["name", "score"]])
Sam
name score
0 Maya 88
1 Sam 92
2 Priya 79.iloc: select by position
.iloc[row_positions, column_positions] ignores labels entirely and counts from 0, exactly like list indexing:
print(df.iloc[1, 0]) print(df.iloc[0:2, :])
Sam name score 0 Maya 88 1 Sam 92
.loc and .iloc often return the same thing, which hides the difference — until you filter, sort, or set a custom index, at which point row label 5 and row position 5 can point at completely different rows. Prefer .iloc when you mean "the Nth row" and .loc when you mean "the row labeled X."Boolean filtering
Passing a True/False Series back into df[...] keeps only the rows where it's True — this is how you filter a DataFrame with a condition:
print(df[df["score"] >= 90])
name score 1 Sam 92 3 Leo 95
Combining conditions uses & and |, not Python's and/or — and each condition needs its own parentheses:
print(df[(df["score"] >= 90) & (df["name"] != "Sam")])
name score 3 Leo 95