Selecting columns
What it is
df["col"] returns a Series; df[["a", "b"]] returns a DataFrame. Attribute access (df.col) works only for names that are valid identifiers and do not collide with methods.
Why it matters
Choosing between Series and one-column DataFrame deliberately avoids a class of shape errors downstream, particularly when passing features to scikit-learn.
In the real world: A dashboard needs only customer ID, plan and monthly spend from a 200-column table. Selecting just those keeps it fast and clear.
Visual example
SelectionThe brackets decide the shape: a list of names gives a DataFrame, one name gives a Series.
The shapes
df[["f1", "f2"]] → (3, 2)
df["target"] → (3,)
Why this matters
scikit-learn expects X as a 2-D table and y as a 1-D Series. Getting the brackets right avoids a whole class of shape errors.
Common misconception
Wrong idea: df["f1"] and df[["f1"]] are the same thing.
Correct idea: one name gives a Series of shape (n,); a list gives a DataFrame of shape (n, k), even with one name in it.
y = df["target"] # Series, shape (n,) <- what sklearn wants for y
X = df[["f1", "f2"]] # DataFrame, shape (n, 2) <- what it wants for XRelying on df.count or df.max style attribute access for real columns with those names — you get the method, not the data, and the failure is confusing.