Why Does pandas map Turn a Valid Code Into NaN?
Separate missing source values from codes your lookup dictionary does not recognize.
Why does map return NaN for a nonmissing value?
When you use a plain dictionary with Series.map, an input value absent from the dictionary keys becomes NaN. A code can therefore be present in the source but missing from the mapped output. Keep the original code and test dictionary membership separately from source nulls.
Build a reproducible channel audit
This synthetic extract has four distinct orders from the US, UK and Germany, with known amounts already in USD. A small channel dictionary recognizes web and app. The partner code is present but has not been added to that dictionary; a different order has no source code at all. The mapping values are nonmissing strings, and missing values are not dictionary keys in this fixture.
import pandas as pd
x=pd.DataFrame({'order_id':['US1','UK1','DE1','US2'], 'code':['web','app','partner',None], 'amount_usd':[100,80,60,40]})
labels={'web':'Website','app':'Mobile app'}
x['channel']=x['code'].map(labels)
x['mapping_status']='mapped'
x.loc[x['code'].isna(),'mapping_status']='missing input'
x.loc[x['code'].notna() & ~x['code'].isin(labels),'mapping_status']='unmapped code'
print(x.to_string(index=False))
Tested with pandas 2.2.3. Expected output:
order_id code amount_usd channel mapping_status
US1 web 100 Website mapped
UK1 app 80 Mobile app mapped
DE1 partner 60 NaN unmapped code
US2 None 40 NaN missing inputWhy are the two missing outputs different?
The $60 partner order needs a classification decision: is partner an approved new channel, an alias or an invalid value? The $40 order needs investigation of the source capture or extraction process. Filling both with a label such as Other would conceal these different causes unless Other is an explicitly defined business category.
The status column uses isna() to identify a missing input and isin(labels) to check dictionary keys. It does not infer the cause from the mapped value alone. If a real dictionary deliberately maps a known key to a missing value, audit that third case separately; this example assumes its mapped labels are all known.
How can this affect a revenue chart?
The source contains $280. Grouping by mapped channel with the default missing-key behavior in the tested environment reports only Website $100 and Mobile app $80: $180 in total. Keeping the missing group with dropna=False preserves another $100, but it still combines the unmapped $60 and missing-input $40.
Use the status breakdown during review:
print(x.groupby('mapping_status')['amount_usd'].sum())
# mapped 180
# missing input 40
# unmapped code 60These amounts reconcile to $280 without inventing a channel for unresolved orders. For the grouping behavior itself, see why missing group keys can hide revenue.
Should you normalize codes first?
Only under a documented policy. Leading spaces or case differences can prevent exact matches, but blindly lowercasing or stripping every identifier may erase meaningful distinctions in some systems. Preserve the raw value, create a separate normalized value if appropriate, and test the normalization with known examples before mapping.
A dictionary with custom default behavior can return a value for unknown keys instead of NaN. That changes the output but does not establish the correct business classification. Preserve a membership audit even when a default label is intentional. If you need multiple lookup attributes or key-uniqueness checks, consider a validated merge rather than hiding a complicated lookup in a dictionary.
Checks before publishing the report
Retain original codes, reconcile the USD total across mapping statuses, review newly observed codes, and separate missing-input counts from unmapped-code counts. Re-run the same fixture when the dictionary changes. Do not treat a zero count of missing output values as proof of correct attribution if defaults or fallback labels are in use.
For another transformation that creates missing outputs without losing source rows, see Series assignment and index alignment.
Source and verification
The official pandas Series.map reference documents plain-dictionary missing-key behavior and custom defaults. Six checks verified missing outputs, classification statuses, the two unresolved USD amounts, the $180 default grouped subtotal and the $280 total with missing groups retained. All figures are practice data.