Code review of a scikit-learn-style transformer, its tests and a shell test script
Company: Capital One
Role: Data Scientist
Category: Software Engineering Fundamentals
Difficulty: medium
Interview Round: Onsite
In a code-review and testing round for a data science role, the interviewer shows you data-preparation code written as scikit-learn-style classes with `fit` and `transform` methods, together with the shell script that runs the tests. You are asked to review the code, explain why it is organized as classes, write tests for it, and explain how the `.sh` script works.
The report describes the round only as code review and testing of functions that abstract scikit-learn-style classes, plus a `.sh` file; it does not reproduce the code. This version supplies a small representative class and script so the review can be practiced. The class is meant to be fitted once on training data and then applied to validation, test and production data.
**`prep.py`**
```python
import pandas as pd
class MeanImputeScaler:
"""Fill missing values with the training mean, then standardize each column."""
def __init__(self, columns):
self.columns = columns
def fit(self, df):
self.means = df[self.columns].mean()
self.stds = df[self.columns].std()
def transform(self, df):
for col in self.columns:
df[col] = df[col].fillna(df[col].mean())
df[col] = (df[col] - self.means[col]) / self.stds[col]
return df
def fit_transform(self, df):
self.fit(df)
return self.transform(df)
```
**`run_tests.sh`**
```bash
#!/bin/bash
pip install -r requirements.txt
python -m pytest tests/
echo "All tests passed"
```
### Clarifying Questions
- Will the class run inside a scikit-learn `Pipeline`, cross-validation or `GridSearchCV`, or is it only called by hand?
- How should a column that is constant in the training data be handled: mapped to 0, dropped, or rejected with an error?
- Should `transform` fail when a fitted column is missing from its input, and should extra columns pass through untouched?
- Where does `run_tests.sh` run (in CI, on laptops, or both), and in which Python environment?
### Part 1 — Review the class
Review `MeanImputeScaler` as you would a pull request. For each problem you find, explain what goes wrong when a model is trained and then served with this class, rank the problems by severity, and propose a fix. Then write the corrected class.
```hint Follow the data
Trace a training DataFrame through `fit`, then a one-row scoring DataFrame with a missing value through `transform`. Which statistics does each line use, and where were they computed?
```
```hint What the caller gets back
Look at what each method returns, and at the state of the DataFrame the caller passed in once the call finishes.
```
#### What This Part Should Cover
- Defects that make training, validation and serving see different inputs, and why they rank highest
- Breaks in the fit/transform contract that stop chaining and pipeline tools from working
- Numerical and input edge cases, and the errors a user would see
- A corrected class that fixes each defect
### Part 2 — Why classes
A teammate asks why this is a class at all, since a single function `clean(df)` would be shorter. Explain why the class-based fit/transform design is preferred in data science code, and when a plain function is still the right choice.
```hint Two moments in a model's life
Think about what has to carry over from the moment the model is trained to the moment it scores new data, and what holds it in between.
```
#### What This Part Should Cover
- Where learned statistics live, and what that means for leakage and for serving
- How a shared interface lets steps compose with validation and tuning tools
- Persistence and testability
- When a stateless function is enough
### Part 3 — Write the tests
Write pytest tests for your corrected class. List the behaviors the suite should cover, show at least four tests in code, and explain how you would measure coverage and what a coverage number does not tell you.
```hint Fit on one frame, score another
Several of the defects from Part 1 cannot show up in a test that fits and transforms the same DataFrame.
```
#### What This Part Should Cover
- Exact expected values on small hand-computed inputs
- Tests aimed at each defect from Part 1, including the production scoring case
- Edge cases and error paths
- How coverage is measured and its limits
### Part 4 — The shell script
Explain what a `.sh` file is and the ways `run_tests.sh` can be run. Then say whether the script does its job when CI runs it, and rewrite it.
```hint One number decides
CI decides pass or fail from a single number the script hands back when it finishes. Which command produces that number here?
```
#### What This Part Should Cover
- What a shell script is, its first line, and how execute permission affects the way it is run
- Exit status and how CI uses it
- The defect in this script and a corrected version
- Environment and reproducibility concerns
### What a Strong Answer Covers
- Prioritizes defects that silently change model inputs over style comments
- Ties each review comment to a concrete consequence for training, validation or serving
- Tests organized around behaviors and defects rather than around line coverage
- Working knowledge of the scikit-learn estimator conventions and the reasons behind them
- A constructive review tone that explains why each change matters and proposes the fix
### Follow-up Questions
- How would you make the class work with `GridSearchCV`, which copies estimators by reading their constructor parameters?
- The model scores data both in a nightly batch job and in a real-time service. How would you guarantee both apply exactly the same transformation?
- Your tests reach 100% line coverage, yet a defect like the one in `transform` could still ship. How?
- How would you test the full pipeline (preprocessing plus model) without making the suite slow or flaky?
Overview: A data science code-review exercise built around a scikit-learn-style transformer class with fit and transform methods and the shell script that runs its tests. It tests reviewing the class for correctness, explaining why class-based design is preferred in data science code, writing pytest tests with real coverage, and explaining how the script reports failure.
Read the full Capital One Data Scientist interview experience this question came from