Casting with astype()
Convert columns to int, float, string, boolean, and datetime using astype() and handle common conversion errors.
Casting with astype() is a free Pandas & NumPy Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Pandas & NumPy Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Introduction to astype()
Series.astype(dtype) converts a column from its current type to the type you specify. It returns a new Series (or DataFrame when called on a full DataFrame) without modifying the original. This is the primary Pandas tool for fixing dtype problems after loading data, and it can convert between numeric types, to strings, to booleans, and to the Categorical type.
import pandas as pd
df = pd.DataFrame({'age': ['25', '30', '35']})
print('Before:', df['age'].dtype) # object
df['age'] = df['age'].astype(int)
print('After:', df['age'].dtype) # int64
print(df['age'] + 1) # [26, 31, 36] — arithmetic now worksConverting to Numeric Types
The most common conversion is from object to a numeric type. You can cast to 'int64', 'int32', 'float64', 'float32', etc. If any value in the column cannot be converted, astype() raises a ValueError. Use pd.to_numeric(series, errors='coerce') instead when the column may contain non-numeric strings — it converts bad values to NaN rather than crashing.
import pandas as pd
df = pd.DataFrame({'price': ['10.5', '20.0', 'N/A', '30.5']})
# astype would crash on 'N/A'
# price_float = df['price'].astype(float) # ValueError!
# pd.to_numeric with errors='coerce' is safer
df['price_float'] = pd.to_numeric(df['price'], errors='coerce')
print(df)
# price price_float
# 0 10.5 10.5
# 1 20.0 20.0
# 2 N/A NaN
# 3 30.5 30.5Converting to String (object)
Casting a column to str (or 'object') converts every value to its string representation. This is useful when you need to concatenate a numeric column with a text column, or when you want to apply string methods to numeric data like zero-padding IDs. Pandas also has the newer 'string' dtype that offers better NA-handling for text columns.
import pandas as pd
df = pd.DataFrame({'id': [1, 2, 3], 'region': ['E', 'W', 'N']})
# Concatenate id and region into a composite key
df['key'] = df['id'].astype(str) + '_' + df['region']
print(df)
# id region key
# 0 1 E 1_E
# 1 2 W 2_W
# 2 3 N 3_NConverting to Boolean
Boolean conversion is useful when columns store True/False as integers (0/1) or as strings ('Yes'/'No'). Casting 0/1 integers with astype(bool) works directly: 0 becomes False, anything non-zero becomes True. For string 'Yes'/'No' columns, map first with a dictionary, then cast.
import pandas as pd
df = pd.DataFrame({
'active_int': [1, 0, 1, 0],
'active_str': ['Yes', 'No', 'Yes', 'No']
})
# Integer to bool
df['active_bool'] = df['active_int'].astype(bool)
# String to bool via mapping
df['active_bool2'] = df['active_str'].map({'Yes': True, 'No': False})
print(df[['active_bool', 'active_bool2']])
# active_bool active_bool2
# 0 True True
# 1 False FalseDowncasting Numeric Types
By default, Pandas uses 64-bit types. If your integer values fit in 32 or even 8 bits, you can downcast to a smaller type to halve (or quarter) memory usage. Use pd.to_numeric(series, downcast='integer') or explicitly cast with astype('int32'). This is a key optimisation for large datasets.
import pandas as pd
import numpy as np
df = pd.DataFrame({'count': np.random.randint(0, 200, 1_000_000)})
print('int64 bytes:', df['count'].nbytes) # 8,000,000
df['count_int16'] = df['count'].astype('int16') # max 32767, fits 0-200
print('int16 bytes:', df['count_int16'].nbytes) # 2,000,000
# Or let Pandas choose the smallest type automatically
df['count_auto'] = pd.to_numeric(df['count'], downcast='integer')
print('auto dtype:', df['count_auto'].dtype)Converting Full DataFrames with astype(dict)
You can convert multiple columns at once by passing a dictionary to df.astype() where keys are column names and values are target dtypes. This is cleaner than chaining individual column assignments and makes the type-conversion step self-documenting as a single block in your pipeline.
import pandas as pd
df = pd.DataFrame({
'age': ['25', '30'],
'salary': ['50000', '70000'],
'is_manager': ['1', '0']
})
df = df.astype({
'age': 'int32',
'salary': 'float64',
'is_manager': 'bool'
})
print(df.dtypes)
# age int32
# salary float64
# is_manager boolHandling Errors in astype()
astype() has no built-in error-tolerant mode (unlike pd.to_numeric). If a conversion fails, it raises a ValueError or OverflowError. The safe workflow is: (1) clean the column first (strip symbols, fill NaN), (2) then cast. Alternatively, use pd.to_numeric(errors='coerce') for numerics or write a small helper function that catches conversion errors.
import pandas as pd
# Clean then cast pattern
df = pd.DataFrame({'price': ['$1,200', '$800', '$450']})
# Step 1: remove non-numeric characters
df['price_clean'] = (
df['price']
.str.replace('$', '', regex=False)
.str.replace(',', '', regex=False)
)
# Step 2: safe cast
df['price_num'] = df['price_clean'].astype(float)
print(df)
# price price_clean price_num
# 0 $1,200 1200 1200.0
# 1 $800 800 800.0
# 2 $450 450 450.0Casting to Pandas StringDtype
The newer 'string' dtype (capital S variant or pd.StringDtype()) was introduced to provide first-class string support with proper NA handling — it stores missing strings as pd.NA rather than None or np.nan. It enables the .str accessor while preserving NA semantics better than the object dtype, and is recommended for new code targeting Pandas 2+.
import pandas as pd
df = pd.DataFrame({'name': ['Alice', None, 'Carol']})
# Convert to the modern string dtype
df['name'] = df['name'].astype('string')
print(df['name'].dtype) # string
print(df['name'].isna()) # proper NA detection
# 0 False
# 1 True
# 2 FalseOverflow Risks When Downcasting
When you downcast to a smaller integer type, values that exceed the type's range silently overflow and wrap around. For example, casting 300 to int8 (range -128 to 127) produces 44 without raising an error. Always verify that your actual data range fits within the target type before downcasting to avoid subtle corruption.
import pandas as pd
import numpy as np
df = pd.DataFrame({'value': [100, 200, 300, 127, 128]})
# int8 range: -128 to 127
df['value_i8'] = df['value'].astype('int8')
print(df)
# value value_i8
# 0 100 100
# 1 200 -56 <- overflow! 200-256 = -56
# 2 300 44 <- overflow! 300-256 = 44
# 3 127 127
# 4 128 -128 <- overflow!
# Always check range first
print(df['value'].max()) # 300 > 127 — int8 is UNSAFE hereVerifying Conversions with a Dtype Map
After performing multiple type conversions, validate the final schema by comparing the actual dtypes to an expected map. This assertion pattern catches mistakes like a column that failed to convert (e.g., because NaN prevented int conversion). Run these checks at the end of your data loading function as a lightweight schema test.
import pandas as pd
df = pd.DataFrame({
'user_id': [1, 2, 3],
'amount': [10.5, 20.0, 30.5],
'active': [True, False, True]
})
expected = {'user_id': 'int64', 'amount': 'float64', 'active': 'bool'}
for col, dtype in expected.items():
assert str(df[col].dtype) == dtype, (
f'{col}: expected {dtype}, got {df[col].dtype}'
)
print('Schema validation passed')Full Conversion Pipeline Example
Bringing it all together: here is a realistic post-read_csv conversion pipeline that cleans formatting, handles NaN safely, casts to optimal types, and validates the result. This pattern — clean, cast, validate — should be a standard part of every data ingestion function.
import pandas as pd
raw = pd.DataFrame({
'user_id': ['101', '102', '103'],
'revenue': ['$1,200', '$800', '$2,500'],
'active': ['Yes', 'No', 'Yes']
})
df = (
raw
.assign(
user_id=raw['user_id'].astype('int32'),
revenue=pd.to_numeric(
raw['revenue'].str.replace('[$,]', '', regex=True)
),
active=raw['active'].map({'Yes': True, 'No': False})
)
)
print(df.dtypes)
# user_id int32
# revenue float64
# active boolQuick Check
Test your understanding of casting with astype().
Lesson Recap
In this lesson you learned: astype(dtype) converts a column or entire DataFrame to a new type, pd.to_numeric(errors='coerce') is safer for columns with non-numeric strings, and passing a dictionary to astype() converts multiple columns at once. Downcast carefully to avoid overflow, and always validate the final schema with assertions. Next up we explore the memory-efficient Categorical dtype.
Frequently asked questions
Is the “Casting with astype()” lesson free?
Yes — the full text of “Casting with astype()” is free to read here on the web, and the Pandas & NumPy Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Pandas & NumPy Academy course, upgrade to CoddyKit PRO.
What will I learn in “Casting with astype()”?
Convert columns to int, float, string, boolean, and datetime using astype() and handle common conversion errors. You practise Pandas & NumPy Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Pandas & NumPy Academy?
No prior experience is required. Pandas & NumPy Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Casting with astype()” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Pandas & NumPy Academy lesson?
Yes. Every Pandas & NumPy Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Inspecting Column Data Types
- Casting with astype()
- Categorical Data Type
- Parsing Dates Correctly