Logistic regression wants numbers. City names (Nairobi) need a numeric encoding. OneHotEncoder makes one column per category. ColumnTransformer applies different transformers to numeric vs categorical columns.
Goal
One-hot encode cities, then build a ColumnTransformer for a mixed kiosk table.
OneHotEncoder
from sklearn.preprocessing import OneHotEncoder
cities = np.array(["Nairobi", "Mombasa", "Nairobi", "Kisumu"]).reshape(-1, 1)
enc = OneHotEncoder(sparse_output=False, handle_unknown="ignore")
out = enc.fit_transform(cities)
print(enc.get_feature_names_out(["city"]))
print(out)handle_unknown="ignore" turns an unseen city on test into a row of zeros instead of an error.
ColumnTransformer
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder, StandardScaler
df = pd.DataFrame(
{
"city": ["Nairobi", "Nairobi", "Mombasa", "Mombasa", "Kisumu", "Kisumu"],
"units": [12, 7, 9, 4, 11, 3],
"price": [10.5, 22.0, 10.5, 10.5, 22.0, 10.5],
"high": [1, 1, 0, 0, 1, 0],
}
)
X = df[["city", "units", "price"]]
y = df["high"]
prep = ColumnTransformer(
[
("cat", OneHotEncoder(sparse_output=False, handle_unknown="ignore"), ["city"]),
("num", StandardScaler(), ["units", "price"]),
]
)
Xt = prep.fit_transform(X)
print(prep.get_feature_names_out())
print(Xt.round(2))
print("y", y.tolist())Remainder columns are dropped by default. List every feature you want to keep.
Tip
Trees can use OrdinalEncoder (integer codes). Linear models prefer one-hot so “Kisumu = 2” is not treated as twice Nairobi.