How do I get pandas to choose better types for my columns?
Short answer
convert_dtypes moves columns to the nullable types, so integers stay integers even with missing values and text becomes a proper string dtype. It is a good tidy-up after reading messy data.
The short version
convert_dtypes() converts each column to the best available nullable type. Integer columns stay integers even when they contain missing values, and text columns become a proper string dtype instead of the vague object. It is a useful tidy-up step after loading messy data.
What it does
import pandas as pd
df = pd.DataFrame({"a": [1, None]})
df.dtypes # float64 , the None forced it to float
df.convert_dtypes().dtypes # Int64 , a nullable integer
Without conversion, a single missing value drags an integer column to float, so your counts and identifiers become 1.0 and 2.0. convert_dtypes uses the nullable Int64 type, which holds integers and missing values, so the numbers stay whole.
Why the object dtype is unhelpful
A text column normally has dtype object, which means "arbitrary Python objects" and tells you nothing. It could contain strings, or a mixture of strings and numbers, or anything at all. The string dtype introduced by convert_dtypes is explicit, catches type mistakes earlier, and makes the .str methods behave more predictably with missing values.
When to use it
Straight after reading a file is the natural place, once you have parsed the dates and handled placeholders.
df = (
pd.read_csv("orders.csv", na_values=["", "NA", "-"])
.convert_dtypes()
)
This gives you a frame where the types reflect what the data actually is, which makes every subsequent step safer.
The caveats
It is not a silver bullet. Two things to know.
First, it will not convert a column of numbers stored as text into numbers, because that requires parsing, not just a type change. You still need pd.to_numeric for that, and convert_dtypes will happily leave a numeric-looking text column as string.
Second, some older libraries do not fully understand the nullable dtypes and may complain or behave oddly when handed an Int64 column. If a downstream tool objects, convert back at that boundary with astype.
Doing it per column
You do not have to convert everything at once. For a single column where you specifically need integers with missing values, cast directly.
df["count"] = pd.to_numeric(df["count"], errors="coerce").astype("Int64")
Note the capital I. The lowercase int64 is the old, non-nullable type and will raise if the column contains missing values.
Check the result
As with any type change, look at what you got.
df.dtypes
Types are the foundation everything else rests on. A column that is silently text when you thought it was numeric, or float when you thought it was integer, will cause a subtle failure somewhere downstream. Spending a minute confirming the types after loading is one of the highest-value habits in data work.