Exercise 6.4
Unit Converter for Log Data
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:
| Quantity | oilfield | metric |
|---|---|---|
| depth | ft | m |
| density | g/cc | kg/m3 |
| porosity | frac | pct |
| temp | degF | degC |
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.
Stuck? Reveal hints one at a time — they progress from nudge to near-solution.
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.