1.4.6 · D5Python & Scientific Computing
Question bank — Pandas DataFrames and Series basics
For hands-on drills see 1.4.07-Pandas-data-cleaningand-manipulation; for the array layer underneath see 1.4.01-NumPy-arrays-and-vectorization.
True or false — justify
A Series is just a Python dictionary with a nicer print.
False — a dict has no fixed order guarantee across all operations and no dtype; a Series keeps a numpy-backed, single-dtype array plus an ordered
index, so it supports positional access and vectorised math a dict cannot.Every column in a DataFrame must have the same dtype.
False — each column is its own Series so columns may differ (int, float, object). Only within a single column must the dtype be uniform.
Two Series added together line up by position, like numpy arrays.
False — they align by index label, not position. Non-matching labels produce
NaN, so s1 + s2 can be longer than either input and full of holes if labels differ.df['score'] returns a copy you can safely modify.
False — column selection usually returns a view onto the same data; assigning into it may or may not write back, which is exactly why pandas raises the
SettingWithCopyWarning.The row index of a DataFrame is always 0, 1, 2, ….
False — that default
RangeIndex only appears when you supply no index. It can be strings, dates, or even duplicated values.len(df) gives the number of columns.
False —
len(df) is the number of rows (the length of the index). Use df.shape[1] or len(df.columns) for columns.Filtering with a boolean Series keeps the rows where the condition is False.
False — it keeps rows where the boolean is
True; the alignment is by index, and rows with NaN in the condition are treated as False.Sorting a Series scrambles the link between labels and values.
False — the whole point is that labels stick. After
sort_values() each value still carries its original index label to its new position.Spot the error
df[1] to grab the second row.
Error — single-bracket integer indexing looks for a column named
1, not row position 1. For the second row use df.iloc[1].df.loc[0:2] returns two rows (positions 0 and 1), just like list slicing.
Error —
.loc slicing is label-based and inclusive of the end label, so df.loc[0:2] returns three rows (labels 0, 1, 2), unlike .iloc[0:2] which is exclusive.df.iloc['s2', 'score'] to read Bob's score when the index is ['s1','s2','s3'].
Error —
.iloc only accepts integer positions, not labels. Use df.loc['s2','score'] or df.iloc[1, 1].s['Feb'] = 18000 where s has integer index but you meant month names.
Error — with an integer index,
s['Feb'] would try to add a new label 'Feb', silently growing the Series instead of updating an existing month.pd.Series([1,2,3], index=['a','b']).
Error — the
index has fewer labels than values (2 vs 3). Pandas raises a length-mismatch ValueError; index and data must be the same length.df[df['score'] > 80 and df['grade'] == 'A'].
Error — Python's
and can't operate element-wise on Series. Use & with parentheses: df[(df['score'] > 80) & (df['grade'] == 'A')].df.mean() on a DataFrame with a text column throws an error.
Error — by default
mean skips non-numeric columns and just averages the numeric ones; it does not crash on the text column.Why questions
Why does df['name'] return a Series but df[['name']] return a DataFrame?
A single string selects one column, so pandas hands back the 1-D Series; a list of names (even a list of one) asks for a sub-table, so you get a 2-D DataFrame.
Why do we ever need both .loc and .iloc — isn't one enough?
They answer different questions:
.loc means "the row called X" (semantic labels), .iloc means "the row at position X" (order). When labels are non-integer these are unambiguous, but when the index is integers the two can disagree, so both must exist.Why does adding two Series with partly-overlapping labels create NaN?
Alignment fills in every label present in either Series; where one side has no value for a label there is nothing to add, so pandas marks it missing (
NaN) rather than guessing a zero.Why is building a DataFrame from a dict-of-lists so common?
It mirrors "column-oriented" thinking — each key is a variable/feature and its list is that column's values, which is exactly the mental model used in 2.1.03-Feature-engineering-basics.
Why does list-of-dicts sometimes produce NaN columns?
Pandas takes the union of all keys across records as columns; any record missing a key gets
NaN in that slot, so gaps in the source data surface as missing cells.Why does chained assignment like df[df.score>80]['grade'] = 'A' fail to update df?
The first bracket makes a temporary filtered copy; the assignment edits that throwaway object, not
df. Use a single .loc call: df.loc[df.score>80, 'grade'] = 'A'.Why keep labels attached to data at all, instead of relying on row order?
So sorting, filtering, joining and merging can re-align by identity, eliminating off-by-one bugs — the value never loses track of which row it belongs to.
Edge cases
What is the dtype of a Series holding [1, 2, None]?
float64 — None/NaN cannot live in an integer array, so pandas up-casts the whole column to float so it can represent the missing value.What does pd.Series([]) (empty) have for a dtype?
An empty Series has no data to infer from, so it defaults to
object (older pandas) or raises a warning suggesting you specify dtype= explicitly.If two rows share the same index label, what does df.loc['dup'] return?
A sub-DataFrame of all matching rows, not a single row — duplicate labels are allowed, so
.loc can return more than one row for one label.What happens to a boolean filter when the condition column contains NaN?
Comparisons with
NaN yield False (actually the mask holds NaN→treated as False), so those rows are dropped — silently excluding missing-data rows unless you handle them first.df.drop('col', axis=1) — does the original df change?
No —
drop returns a new object by default (inplace=False); the original keeps its column unless you reassign or pass inplace=True.What does df['col'] return if 'col' is not a column name?
A
KeyError — unlike a dict's .get, single-bracket column access has no silent default and raises immediately. (See the 'col' gotcha of confusing string keys with variables.)What is the shape of a DataFrame with 0 rows but 3 defined columns?
(0, 3) — the column structure exists even with no data, which is why appending rows or reading an empty CSV still yields usable, typed columns.Recall One-line rescue for the top three traps
Alignment ::: Series/DataFrame math lines up by index label, never by position.
loc vs iloc ::: .loc = by label (end-inclusive), .iloc = by integer position (end-exclusive).
Chained assignment ::: Do writes in a single .loc[rows, cols] = value, never df[...][...] = value.