Pandas dtypes
Pandas dtypes: int64, float64, object, category, datetime64[ns], Int64 (nullable), and choosing the right one.
Pandas — dtypes
EXAMPLE
import pandas as pd
import numpy as np
# ===== Default inference =====
df = pd.DataFrame({
'id': [1, 2, 3],
'name': ['Alex', 'Sam', None],
'score': [9.5, 8.0, None],
'active': [True, False, True],
'date': ['2024-04-10', '2024-04-11', '2024-04-12'],
})
print(df.dtypes)
# id int64
# name object
# score float64
# active bool
# date object <- string by default!
# Parse dates explicitly:
df['date'] = pd.to_datetime(df['date'])
# date datetime64[ns]
# ===== Common dtypes =====
# int8/16/32/64 signed integers
# uint8/16/32/64 unsigned integers
# float32/64 floats
# bool boolean
# object Python objects (usually strings)
# string[python] dedicated string dtype (Pandas 1.0+)
# category enum-like; saves memory + speeds up groupby
# datetime64[ns] datetimes (tz-naive)
# datetime64[ns, tz] tz-aware
# timedelta64[ns] durations
# Nullable types (Pandas 1.0+; capital first letter):
# Int8, Int16, Int32, Int64 nullable ints
# UInt8, ..., UInt64
# Float32, Float64
# boolean nullable bool
# string nullable string
# ===== Why nullable types matter =====
# Standard int64 cannot hold NaN. If you have nulls, Pandas upcasts to float64.
# Use Int64 (capital) to keep integer semantics with NaN support:
df['id_nullable'] = pd.array([1, None, 3], dtype='Int64')
# ===== Cast =====
df['score'] = df['score'].astype('float32')
df['name'] = df['name'].astype('string')
# Convert dates:
df['date'] = pd.to_datetime(df['date'])
# Convert to category (saves a LOT of memory on repeated strings):
df['city'] = df['city'].astype('category')
# Numeric coercion (errors -> NaN):
df['x'] = pd.to_numeric(df['x'], errors='coerce')
# ===== Inspect memory =====
df.memory_usage(deep=True)
df.info(memory_usage='deep')
# ===== Category dtype =====
cats = pd.Series(['a', 'b', 'a', 'c'], dtype='category')
cats.cat.categories # Index(['a', 'b', 'c'])
cats.cat.codes # 0, 1, 0, 2 (compact)
# Use ordered categories for proper sorting:
sizes = pd.Categorical(['S', 'L', 'M'], categories=['S', 'M', 'L'], ordered=True)
pd.Series(sizes).sort_values()
# ===== Reading with explicit dtypes =====
# Faster + less memory if you know the schema:
df = pd.read_csv('data.csv',
dtype={'id': 'Int64', 'name': 'string', 'score': 'float32', 'city': 'category'},
parse_dates=['date'])
# ===== Arrow-backed dtypes (Pandas 2+) =====
# pip install pyarrow
df = pd.read_csv('data.csv', dtype_backend='pyarrow')
# string[pyarrow], int64[pyarrow], etc.
# Faster + smaller than NumPy-backed object strings.
# ===== Datetime details =====
df['date'].dt.year
df['date'].dt.day_name()
df['date'].dt.tz_localize('UTC') # add tz
df['date'].dt.tz_convert('Australia/Sydney')
# ===== Patterns to internalise =====
# - Explicit dtypes on read_csv -> faster + smaller
# - 'category' for low-cardinality strings
# - 'Int64' (nullable) over int64 + NaN -> float surprise
# - 'datetime64[ns, UTC]' for tz-aware times
# ===== Pitfalls =====
# - 'object' dtype for strings -> slow + memory-hungry; use 'string' or pyarrow
# - Implicit upcasting (int + NaN -> float) silently broadens
# - Category + new values added without registering them -> KeyError
# - dt accessor on object dtype -> errors; convert with pd.to_datetime first
Why it matters
dtypes are where Pandas performance lives. Pin them on read_csv, use category for repeated strings, datetime64[ns, tz] for times, nullable Int64 when ints can be NaN. Pandas 2 pyarrow backend is faster + smaller — opt in for any large dataset.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
import pandas as pd
df['age'] = df['age'].astype('Int64') # nullable int
df['date'] = pd.to_datetime(df['date'])
df['cat'] = df['cat'].astype('category')
Try it Yourself »
Discussion
Loading…