Exerciseschevron_rightChapter 6chevron_right6.4
fitness_center

Exercise 6.4

Unit Converter for Log Data

Level 2
Chapter 6: Petroleum Data Sources
descriptionProblem

Logs from different vendors and vintages arrive in different units: one service company reports density in g/cc, another in kg/m³; an international partner logs depth in metres while your database expects feet. Mixing them silently corrupts every downstream calculation. So you standardise on one system before anything else.

The starter gives a metric-units log df and a units dict mapping each column to its current unit. Write standardize_log_units(df, units, target="oilfield") that returns a copy with every column converted to the target system's canonical unit:

Quantityoilfieldmetric
depthftm
densityg/cckg/m3
porosityfracpct
tempdegFdegC

Conversions: 1 ft = 0.3048 m · 1 g/cc = 1000 kg/m³ · fraction × 100 = pct · °C = (°F − 32) × 5/9. A column already in the target unit is left untouched. The function must not mutate the caller's DataFrame.

lightbulbHints (0/3)

Stuck? Reveal hints one at a time — they progress from nudge to near-solution.

codeYour solution
main.py
visibilityReveal reference solutionexpand_more

Try solving it yourself first — the hints walk you through it. The solution below is one valid approach; yours may differ and still be correct.

import pandas as pd

df = pd.DataFrame({
    "DEPTH": [1000.0, 2000.0],
    "RHOB":  [2400.0, 2500.0],
    "NPHI":  [18.0, 22.0],
    "TEMP":  [60.0, 80.0],
})
units = {"DEPTH": "m", "RHOB": "kg/m3", "NPHI": "pct", "TEMP": "degC"}

M_PER_FT = 0.3048

# Which physical quantity each unit measures.
QUANTITY = {
    "ft": "depth", "m": "depth",
    "g/cc": "density", "kg/m3": "density",
    "frac": "porosity", "pct": "porosity",
    "degF": "temp", "degC": "temp",
}

# Canonical unit per quantity in each target system.
TARGET_UNITS = {
    "oilfield": {"depth": "ft", "density": "g/cc", "porosity": "frac", "temp": "degF"},
    "metric":   {"depth": "m", "density": "kg/m3", "porosity": "pct", "temp": "degC"},
}

# Pairwise conversions (from_unit, to_unit).
CONV = {
    ("ft", "m"): lambda x: x * M_PER_FT,
    ("m", "ft"): lambda x: x / M_PER_FT,
    ("g/cc", "kg/m3"): lambda x: x * 1000.0,
    ("kg/m3", "g/cc"): lambda x: x / 1000.0,
    ("frac", "pct"): lambda x: x * 100.0,
    ("pct", "frac"): lambda x: x / 100.0,
    ("degF", "degC"): lambda x: (x - 32.0) * 5.0 / 9.0,
    ("degC", "degF"): lambda x: x * 9.0 / 5.0 + 32.0,
}


def standardize_log_units(df, units, target="oilfield"):
    out = df.copy()
    targets = TARGET_UNITS[target]
    for col, current in units.items():
        wanted = targets[QUANTITY[current]]
        if current != wanted:
            out[col] = CONV[(current, wanted)](out[col])
    return out


print(standardize_log_units(df, units, "oilfield").to_string(index=False))

lockCopying code is a Full Access feature.