Skip to content
Laviyx Learn

Try

Python for Data course menu

pandas Data Types: astype, to_numeric, to_datetime and category

Fix column types in pandas: check dtypes, convert with astype, clean numbers stored as text with to_numeric, parse dates with to_datetime, use the category type to save memory, and nullable integer and string types.

Intermediate9 min readUpdated
On this page

Every column has a dtype. When a column has the wrong type, calculations fail or give nonsense: numbers stored as text sort alphabetically and cannot be summed, and dates stored as text cannot be compared by month. Fixing types is a core cleaning step.

Checking types#

Python
import pandas as pd

raw = pd.DataFrame({
    "order_id": ["001", "002", "003", "004"],
    "price":    ["1,200", "850", "2,499", "n/a"],
    "quantity": ["2", "1", "3", "1"],
    "ordered":  ["05/01/2026", "09/01/2026", "11/02/2026", "20/02/2026"],
    "status":   ["paid", "paid", "pending", "paid"],
})
print(raw.dtypes)
print(raw["quantity"].sum())      # text joined together, not added!
Output
order_id    object
price       object
quantity    object
ordered     object
status      object
dtype: object
2131

Everything was read as text (object), so "summing" the quantities just joins the strings.

astype for clean values#

When every value converts cleanly, astype does the job:

Python
import pandas as pd

quantity = pd.Series(["2", "1", "3", "1"])
q = quantity.astype(int)
print(q.dtype, q.sum())
print(pd.Series([1.0, 2.0]).astype(int).tolist(), pd.Series([1, 0, 1]).astype(bool).tolist())
Output
int64 7
[1, 2] [True, False, True]

to_numeric for messy numbers#

astype(float) fails on values like "1,200" or "n/a". Clean the text first, then use pd.to_numeric with errors="coerce", which turns anything still invalid into NaN:

Python
import pandas as pd

price = pd.Series(["1,200", "850", "2,499", "n/a"])
try:
    price.astype(float)
except ValueError as e:
    print("Error:", e)

clean = pd.to_numeric(price.str.replace(",", ""), errors="coerce")
print(clean)
Output
Error: could not convert string to float: '1,200'
0    1200.0
1     850.0
2    2499.0
3       NaN
dtype: float64

After coercing, check how many values became NaN (clean.isna().sum()): each one is a value you could not read.

to_datetime for dates#

pd.to_datetime turns text into real timestamps. Give it the format so that day and month are never confused (05/01 could be 5 January or 1 May):

Python
import pandas as pd

ordered = pd.Series(["05/01/2026", "09/01/2026", "11/02/2026", "20/02/2026"])
dates = pd.to_datetime(ordered, format="%d/%m/%Y")
print(dates)
print(dates.dt.month.tolist(), dates.dt.day_name().tolist())
print((dates.max() - dates.min()).days, "days between first and last")
Output
0   2026-01-05
1   2026-01-09
2   2026-02-11
3   2026-02-20
dtype: datetime64[ns]
[1, 1, 2, 2] ['Monday', 'Friday', 'Wednesday', 'Friday']
46 days between first and last

Common format codes: %d day, %m month, %Y four-digit year, %y two-digit year, %H:%M hours and minutes, %b month name like Jan. More in Dates and Time Series.

The category type#

A text column with few distinct values (statuses, cities, sizes) can be stored as category: each value is stored once and rows hold small codes. It uses less memory and can have a meaningful order:

Python
import pandas as pd

status = pd.Series(["paid", "pending", "paid", "refunded", "paid"] * 20000)
as_category = status.astype("category")
print(status.memory_usage(deep=True), as_category.memory_usage(deep=True))
print(as_category.cat.categories.tolist())

sizes = pd.Series(["M", "S", "L", "M"]).astype(pd.CategoricalDtype(["S", "M", "L"], ordered=True))
print(sizes.sort_values().tolist(), (sizes > "S").tolist())
Output
5440132 100406
['paid', 'pending', 'refunded']
['S', 'M', 'M', 'L'] [True, False, True, True]

The category column uses far less memory. With an ordered category, sorting and comparisons follow S < M < L instead of alphabetical order.

Nullable types: Int64 and string#

A regular integer column cannot hold NaN (NaN is a float), so one missing value turns a whole column into floats. pandas' nullable types fix that, using <NA> for missing values:

Python
import pandas as pd

ages = pd.Series([25, None, 31])
print(ages.dtype, ages.tolist())

ages_int = pd.Series([25, None, 31], dtype="Int64")      # capital I
print(ages_int.dtype, ages_int.tolist())

names = pd.Series(["Asha", None], dtype="string")
print(names.dtype, names.str.upper().tolist())
Output
float64 [25.0, nan, 31.0]
Int64 [25, <NA>, 31]
string ['ASHA', <NA>]

convert_dtypes() converts a whole DataFrame to these nullable types in one step.

Putting it together#

Python
import pandas as pd

raw = pd.DataFrame({
    "order_id": ["001", "002", "003", "004"],
    "price":    ["1,200", "850", "2,499", "n/a"],
    "quantity": ["2", "1", "3", "1"],
    "ordered":  ["05/01/2026", "09/01/2026", "11/02/2026", "20/02/2026"],
    "status":   ["paid", "paid", "pending", "paid"],
})
clean = raw.assign(
    price=pd.to_numeric(raw["price"].str.replace(",", ""), errors="coerce"),
    quantity=raw["quantity"].astype(int),
    ordered=pd.to_datetime(raw["ordered"], format="%d/%m/%Y"),
    status=raw["status"].astype("category"),
)
print(clean.dtypes)
print((clean["price"] * clean["quantity"]).sum())
Output
order_id            object
price              float64
quantity             int64
ordered     datetime64[ns]
status            category
dtype: object
10747.0

order_id stays as text on purpose: it is a label, not a number, and its leading zeros matter.

Common mistakes#

Practice#

Practice exercise

Clean pd.Series(["₹1,250", "₹980", "free", "₹2,100"]) into numbers, treating "free" as 0. Print the cleaned values as integers and their total.

Show hint

Remove ₹ and , with str.replace, use to_numeric(errors="coerce"), then fillna(0) and astype(int).

Show solution
Python
import pandas as pd

prices = pd.Series(["₹1,250", "₹980", "free", "₹2,100"])
numbers = pd.to_numeric(prices.str.replace("₹", "").str.replace(",", ""), errors="coerce")
numbers = numbers.fillna(0).astype(int)
print(numbers.tolist(), numbers.sum())
Output
[1250, 980, 0, 2100] 4330

Key takeaway#

Next: Cleaning Text Columns.

Finished this lesson?