Theory
The whole sheet is too much sheet
marks.csv is now a DataFrame of the whole college. The principal, as ever, wants slices: only the score column, only DBMS rows, only the students above 60 in DBMS.
In Unit 1 you did this in SQL: SELECT picked columns, WHERE picked rows.
pandas has the same two moves, wearing brackets instead of keywords, and the translation is nearly word for word. Master the brackets and every SQL instinct you built starts working in Python.
Theory
The stencil over the sheet
Imagine laying a stencil over the printed marksheet: cut a vertical slot and only one column shows; cut it wider and two columns show.
For rows, the stencil is smarter: you write a condition on it (score > 60), it turns each row transparent (True) or opaque (False), and only transparent rows remain visible. pandas calls that stencil a boolean mask, and it is the single most-used idea in all of data analysis.
Theory
Columns: one bracket or two
One column: df['score'] returns a Series (a single labelled column).
Several columns: df[['roll', 'score']]: note the double brackets: the inner pair is a Python list of names, and the result is a smaller DataFrame.
The dot form df.score also works when the name is a clean identifier, but fails on names with spaces and shadows real methods: bracket form is the safe habit.
SQL translation: the column list of SELECT.
Practical
SELECT and WHERE, pandas edition
import pandas as pd
df = pd.read_csv('marks.csv') # roll, subject, score
# columns (SQL: SELECT score / SELECT roll, score)
scores = df['score'] # Series: ONE column
pair = df[['roll', 'score']] # DataFrame: note the DOUBLE brackets
# rows by condition (SQL: WHERE score > 60)
mask = df['score'] > 60 # a Series of True/False
passed = df[mask] # only the True rows survive
# usually written in one line:
dbms_top = df[(df['subject'] == 'DBMS') & (df['score'] > 60)]
# ^ parentheses around EACH condition, & not 'and'
# IN-style membership (SQL: city IN (...))
locals_ = df[df['city'].isin(['Surat', 'Navsari'])]
# combine both moves: rows, then columns
print(df[df['subject'] == 'DBMS'][['roll', 'score']])
At a glance
SQL to pandas, the translation table
| SQL | pandas |
|---|---|
| SELECT score FROM marks | df['score'] |
| SELECT roll, score FROM marks | df[['roll', 'score']] |
| WHERE score > 60 | df[df['score'] > 60] |
| WHERE a AND b | df[(a) & (b)] |
| WHERE city IN ('Surat', ...) | df[df['city'].isin([...])] |
Think first
Read the mask like the machine
df has 4 rows with scores 55, 78, 91, 60. Work out, in order: what Series does df['score'] > 60 produce, and which rows survive df[df['score'] > 60]? Careful with the 60.
Show the answer
The mask is [False, True, True, False]: 55 fails, 78 and 91 pass, and 60 fails because the test is strictly greater-than (60 > 60 is False).
Surviving rows: the two with 78 and 91.
Every mask question reduces to this two-step: build the True/False column first, then keep the True rows. If the boundary value matters, check the operator: > vs >= is where the marks hide.
Quiz
df[(df['subject'] == 'DBMS') and (df['score'] > 60)] raises ValueError: The truth value of a Series is ambiguous. What is the fix?
- Use & instead of and, keeping the parentheses around each condition
- Remove the parentheses around the conditions
- Replace == with = in the subject test
- Convert the DataFrame to a list first
Show the answer
Use & instead of and, keeping the parentheses around each condition
Python's and tries to squash each whole Series into a single True/False, which is meaningless for a column of booleans: pandas needs the element-wise operators: & (and), | (or), ~ (not), and BECAUSE of their precedence, each condition stays in parentheses. Removing parentheses makes it worse; = is assignment, not comparison. This exact error message is pandas' most-Googled beginner moment: now you can read it.
Watch out
The bracket and operator traps
df['roll', 'score'] (single bracket, two names): KeyError: pandas hunts ONE column named by that tuple. Two columns need the list: df[['roll', 'score']].
and/or/not on masks: ValueError: use &, |, ~ with parentheses.
Series vs DataFrame: df['score'] is a Series, df[['score']] a one-column DataFrame: methods differ slightly; know which you asked for.
Theory
ResultDesk's slicing is done
The weak-student report is now one line: df[(df['subject'] == 'DBMS') & (df['score'] < 40)][['roll', 'score']]. Next lesson feeds these slices into the statistics they were cut for: mean, median, mode, variance, standard deviation: the numbers that turn a marksheet into a verdict, and a preview of BCA302.
Summary
Key takeaways
- df['col'] → one column (Series); df[['a', 'b']] → several columns (DataFrame, double brackets).
- A boolean mask (df['score'] > 60) is a True/False Series; df[mask] keeps the True rows: pandas' WHERE.
- Combine masks with & | ~, each condition in parentheses; and/or raise ValueError.
- isin([...]) is the IN of pandas.
- Rows-then-columns chains read like SQL: filter, then select.
- Memory hook: a stencil over the sheet: slots for columns, true/false windows for rows.