Types and Parsing
Coerce Bad Numbers
Parse a mixed list of numeric and non-numeric strings, converting invalid
entries to None rather than raising. By hand, wrap int(s) in a
try/except ValueError and append None on failure. With pandas,
pd.to_numeric(errors='coerce') turns every unparseable value into NaN
in one call.
By hand
For each string, attempt int(s) inside a try block. If the conversion
raises ValueError, catch it and append None instead. The trace shows
result growing with integers on valid strings and None on invalid ones.
strings = ['12', 'x', '7', 'n/a', '28']
result = []
for s in strings:
try:
result.append(int(s))
except ValueError:
result.append(None)
print('RESULT:', result)
strings ← ['12', 'x', '7', 'n/a', '28']
1strings = ['12', 'x', '7', 'n/a', '28']2result = []values this step['12', 'x', '7', 'n/a', '28']stringsresult ← []
1strings = ['12', 'x', '7', 'n/a', '28']2result = []3for s in strings:values this step[]results ← '12'
2result = []3for s in strings:4 try:values this step'12'stry:
3for s in strings:4 try:5 result.append(int(s))result ← [12]
4try:5 result.append(int(s))6except ValueError:values this step[] → [12]results ← 'x'
2result = []3for s in strings:4 try:values this step'12' → 'x'stry:
3for s in strings:4 try:5 result.append(int(s))result.append(int(s))
4try:5 result.append(int(s))6except ValueError:except ValueError:
5 result.append(int(s))6except ValueError:7 result.append(None)result ← [12, None]
6 except ValueError:7 result.append(None)8print('RESULT:', result)values this step[12] → [12, None]results ← '7'
2result = []3for s in strings:4 try:values this step'x' → '7'stry:
3for s in strings:4 try:5 result.append(int(s))result ← [12, None, 7]
4try:5 result.append(int(s))6except ValueError:values this step[12, None] → [12, None, 7]results ← 'n/a'
2result = []3for s in strings:4 try:values this step'7' → 'n/a'stry:
3for s in strings:4 try:5 result.append(int(s))result.append(int(s))
4try:5 result.append(int(s))6except ValueError:except ValueError:
5 result.append(int(s))6except ValueError:7 result.append(None)result ← [12, None, 7, None]
6 except ValueError:7 result.append(None)8print('RESULT:', result)values this step[12, None, 7] → [12, None, 7, None]results ← '28'
2result = []3for s in strings:4 try:values this step'n/a' → '28'stry:
3for s in strings:4 try:5 result.append(int(s))result ← [12, None, 7, None, 28]
4try:5 result.append(int(s))6except ValueError:values this step[12, None, 7, None] → [12, None, 7, None, 28]resultfor s in strings:
2result = []3for s in strings:4 try:stdout ← RESULT: [12, None, 7, None, 28]
7 result.append(None)8print('RESULT:', result)values this stepRESULT: [12, None, 7, None, 28]stdout
With pandas
pd.to_numeric(df['x'], errors='coerce') attempts to parse each value;
strings that cannot be converted become NaN. The integer values are upcast
to float64 to accommodate NaN. The snapshot shows the raw float Series
(with nan positions), and result normalises NaN → None with
math.isnan for parity with the naive half.
import math
import pandas as pd
from dalib.display import set_display
set_display()
strings = ['12', 'x', '7', 'n/a', '28']
df = pd.DataFrame({'x': strings})
s = pd.to_numeric(df['x'], errors='coerce')
result = [int(v) if not math.isnan(v) else None for v in s.tolist()]
print('index:', s.index.tolist())
print('dtype:', s.dtype)
print('values raw:', s.tolist())
print('RESULT:', result)
index: [0, 1, 2, 3, 4]
dtype: float64
values raw: [12.0, nan, 7.0, nan, 28.0]
RESULT: [12, None, 7, None, 28]
Implementation notes
errors='coerce'is the key switch:errors='raise'(default) would raise on the first invalid string, same asastype;errors='ignore'returns the original strings for unparseable entries.- The
float64upcast is the same NaN-forces-float pattern seen indiff-previous-rowandmerge-left— integer columns cannot storeNaN. - Use
pd.isna(s)ormath.isnan(v)to detect the coerced positions after the call. - Cross-reference:
cast-numeric-strings(this chapter) for the strictastypeapproach when all values are guaranteed clean.