Handling Text & Categorical Attributes
What you’ll learn
- why most ML algorithms need numbers, not text categories
OrdinalEncoderOrdinalEncoder— encoding categories as integers- the hidden problem
OrdinalEncoderOrdinalEncoderintroduces OneHotEncoderOneHotEncoder— encoding categories as binary vectors- when one-hot encoding stops being practical
The one text column: ocean_proximity
Everything so far has been numeric except ocean_proximityocean_proximity. It holds a limited set
of repeated string values — <1H OCEAN<1H OCEAN, INLANDINLAND, NEAR OCEANNEAR OCEAN, NEAR BAYNEAR BAY, ISLANDISLAND —
which makes it a categorical attribute rather than free text. Most ML algorithms
prefer numbers, so this needs converting.
housing_cat = housing[["ocean_proximity"]]
print(housing_cat.head(10))housing_cat = housing[["ocean_proximity"]]
print(housing_cat.head(10))OrdinalEncoder: categories to integers
The simplest conversion maps each category to an integer:
from sklearn.preprocessing import OrdinalEncoder
ordinal_encoder = OrdinalEncoder()
housing_cat_encoded = ordinal_encoder.fit_transform(housing_cat)
print(housing_cat_encoded[:5])
print(ordinal_encoder.categories_)from sklearn.preprocessing import OrdinalEncoder
ordinal_encoder = OrdinalEncoder()
housing_cat_encoded = ordinal_encoder.fit_transform(housing_cat)
print(housing_cat_encoded[:5])
print(ordinal_encoder.categories_)This works, but it introduces an assumption most algorithms make automatically: that
nearby numbers are more similar. That’s true for genuinely ordered categories
(“bad”, “average”, “good”, “excellent”), but ocean_proximityocean_proximity isn’t ordered — category
00 (<1H OCEAN<1H OCEAN) and category 44 (NEAR OCEANNEAR OCEAN) aren’t inherently “close” just because
00 and 44 are far apart numerically, and category 00 and 11 aren’t inherently
similar just because their integers are adjacent.
OneHotEncoder: one binary column per category
The standard fix is one-hot encoding: create one binary column per category, set
to 11 when a row belongs to that category and 00 otherwise. Only one column is “hot”
(1) per row — the rest are “cold” (0).
from sklearn.preprocessing import OneHotEncoder
cat_encoder = OneHotEncoder()
housing_cat_1hot = cat_encoder.fit_transform(housing_cat)
print(housing_cat_1hot.toarray()[:5])
print(cat_encoder.categories_)from sklearn.preprocessing import OneHotEncoder
cat_encoder = OneHotEncoder()
housing_cat_1hot = cat_encoder.fit_transform(housing_cat)
print(housing_cat_1hot.toarray()[:5])
print(cat_encoder.categories_)By default, OneHotEncoderOneHotEncoder returns a sparse matrix — it only stores the location
of non-zero entries instead of every zero, which matters a lot once you have
categorical columns with hundreds or thousands of categories. Call .toarray().toarray() only
when you actually need a dense NumPy array (e.g., to print or inspect it).
flowchart LR A["ocean_proximity
(text categories)"] --> B["OrdinalEncoder
0, 1, 2, 3, 4"] A --> C["OneHotEncoder
one binary column per category"] B --> D["Implies false ordering
(0 vs 4 look 'far apart')"] C --> E["No false ordering,
more columns"]
When one-hot encoding isn’t practical
If a categorical attribute has a huge number of possible values (a country code, a user ID, a product SKU), one-hot encoding explodes into a huge number of mostly-zero columns, which can slow down training. In that case, consider:
- replacing the category with a related numeric feature (e.g., country code → population and GDP per capita)
- learning a low-dimensional embedding per category (common in deep learning — each category’s representation is learned during training, not fixed up front)
For a handful of categories like ocean_proximityocean_proximity, though, plain one-hot encoding is
the right default.
🧪 Try It Yourself
Exercise 1 – Ordinal-encode a categorical column
Exercise 2 – One-hot encode and inspect categories
Exercise 3 – Convert a sparse matrix to a dense array
Next
Continue to Feature Scaling (Normalization & Standardization) — with every column numeric now, the next problem is that they’re all on wildly different scales.
If this helped you, consider buying me a coffee ☕
Buy me a coffeeWas this page helpful?
Let us know how we did
