Data Analyst Interview
Menu
Browse in your language. All mock interviews, preparation sessions and feedback are in English only.

Keep Leading Zeros in Python CSV Imports

Python · CSV data quality

Keep Leading Zeros in Python CSV Imports

A worked US ZIP-code and UK postcode example for analysts cleaning customer exports.

Quick answer: Treat postal codes and customer identifiers as text. Python’s default csv.DictReader preserves values such as 02108 as strings; converting them to integers removes leading zeros. Keep the original field, create a separate normalized field, and distinguish missing values from invalid or unverified values.

Why did 02108 become 2108?

A digit-only field is not necessarily a quantity. Adding two postal codes has no analytical meaning, and an identifier such as 0017 can be different from 17 under the source system’s contract. If you run int('02108'), the resulting number is 2108. Converting that number back to a string does not recover the original representation.

Our synthetic customer export combines US ZIP-style values, a ZIP+4-style value and a UK postcode-style value. These examples demonstrate preservation and normalization; they do not validate an address or establish that a customer lives there.

Run this dependency-free Python example

The sample assumes every record has the three declared columns. It preserves leading zeros in both the customer ID and postal code. Empty postal fields become None in the normalized column, while the raw field remains available for an audit.

import csv
from io import StringIO

source = StringIO("""customer_id,country,postal_code
0017,US,02108
0018,US,00501
0019,US,02108-1234
0020,GB,sw1a 1aa
0021,US,
""")
rows = list(csv.DictReader(source))
for row in rows:
    row['postal_code_raw'] = row['postal_code']
    value = row['postal_code'].strip()
    row['postal_code_clean'] = (
        value.upper() if value else None
    )

for row in rows:
    print(row['customer_id'], row['country'],
          repr(row['postal_code_clean']))

assert rows[0]['postal_code_clean'] == '02108'
assert rows[1]['postal_code_clean'] == '00501'
assert rows[2]['postal_code_clean'] == '02108-1234'
assert rows[3]['postal_code_clean'] == 'SW1A 1AA'
assert rows[4]['postal_code_clean'] is None
assert rows[0]['customer_id'] == '0017'

Expected output

0017 US '02108'
0018 US '00501'
0019 US '02108-1234'
0020 GB 'SW1A 1AA'
0021 US None

The assertions test both leading-zero examples, the hyphenated value, case normalization, missing data and the customer identifier. The code does not discard the customer with a missing postcode. Whether that record belongs in a geographic report is a separate denominator decision.

Normalization is not validation

Trimming surrounding whitespace and uppercasing letters makes this small sample easier to compare. It does not check whether a postcode exists, whether its country is correct, or whether an address is deliverable. A value such as ABC would still survive these operations.

For production data, record a separate validation status using the country’s rules and an appropriate reference source. Preserve punctuation and internal spacing until you have a documented reason to transform them. For European markets, do not apply a five-digit US assumption to every country.

Use the country together with the normalized postal code when joining to a geographic reference table. Require that table to have the intended key uniqueness, then count unmatched and multiply matched records before calculating regional revenue. A successful text import alone does not make a join correct.

Can you repair codes that already lost their zeros?

Only when the source contract makes the repair unambiguous. Padding 2108 to five characters may restore 02108 for a field known to contain exactly five-digit US ZIP codes. It is not a safe universal repair for customer IDs, international postal codes or truncated ZIP+4 values. Return to the original export when possible and log any approved reconstruction rule.

Do not replace missing data with 00000. That creates an apparent code rather than preserving the fact that the code is unknown. Likewise, treating all missing locations as one real region can distort a geographic dashboard.

What changes when reading a real file?

Replace StringIO with an opened file using the verified encoding and newline=''. Python’s CSV documentation recommends that newline setting for file objects. Confirm the header names and reject or quarantine malformed records: a missing column can produce None where this sample expects a string, and extra columns need an explicit handling rule.

Keep text types through downstream database loads and exports. Re-import a small round-trip sample and compare the identifiers exactly. A later tool that infers numeric types can undo an otherwise correct import.

Explain the analytical impact

In an interview or review, connect the type decision to a concrete failure: damaged postal codes can fail reference joins and leave revenue unassigned. Report the number of missing, unmatched and ambiguous records, then compare totals before and after the join. The goal is a traceable dataset, not merely an import that runs without an exception.

Continue with parsing US and UK dates without guessing, checking merge cardinality, and auditing missing customer IDs.

Source: Python CSV documentation describes the default text parsing, dictionary reader and file-opening behavior. The customer records and checks here are original synthetic learning examples.

Leave a Reply

Discover more from Data Analyst Interview

Subscribe now to keep reading and get access to the full archive.

Continue reading

✉ WhatsApp