The question
Classify Penguin species from measurements and context. Compare a training-only measurements-only ablation to investigate reliance on geography/context.
data/ml-learning/ML-X05.csv Complete workflow and evidenceYour inputs
Challenge input · ML-X05
333 observations. One measured penguin. Load the CSV file yourself.
Download challenge input CSV · Original source dataset · Source and original dictionary
Ready to load: comma-delimited UTF-8, header row, no saved index. No filtering or target construction is required.
bill_length_mm | bill_depth_mm | flipper_length_mm | body_mass_g | sex | island | year | species |
|---|---|---|---|---|---|---|---|
| 39.1 | 18.7 | 181 | 3750 | male | Torgersen | 2007 | Adelie |
| 39.5 | 17.4 | 186 | 3800 | female | Torgersen | 2007 | Adelie |
| 40.3 | 18 | 195 | 3250 | female | Torgersen | 2007 | Adelie |
| 36.7 | 19.3 | 193 | 3450 | female | Torgersen | 2007 | Adelie |
| 39.3 | 20.6 | 190 | 3650 | male | Torgersen | 2007 | Adelie |
| 38.9 | 17.8 | 181 | 3625 | female | Torgersen | 2007 | Adelie |
| 39.2 | 19.6 | 195 | 4675 | male | Torgersen | 2007 | Adelie |
| 41.1 | 17.6 | 182 | 3200 | female | Torgersen | 2007 | Adelie |
Column meanings and units
Bill length/depth and flipper length: mm. Body mass: grams. Year and island: sampling context.
ML uses 333 complete cases. Removing incomplete records may change the represented population. Geographic context may not generalise to new islands.
Ready to load: comma-delimited UTF-8, header row, no saved index. No filtering or target construction is required.
| Column | Stored type |
|---|---|
bill_length_mm | float64 |
bill_depth_mm | float64 |
flipper_length_mm | int64 |
body_mass_g | int64 |
sex | object |
island | object |
year | int64 |
species | object |
How we validate this model
Reserve 20% of the declared population for the final test using split seed 42. Keep class proportions with a stratified split.
Use the same five stratified training folds, shuffled with seed 42, for reference comparison, candidates and selection. Use out-of-fold training predictions for diagnosis. Select with macro F1 and compare with a most-frequent-class reference. Accuracy is supplementary. Open final-test evidence after selection and diagnosis.
The file is available in the Python working folder. Load it yourself.
- Classify Penguin
speciesfrom measurements and context. - Compare a training-only measurements-only ablation to investigate reliance on geography/context.
cv_resultsreference_resultschosen_namematrixfinal_f1final_accuracyablation_resultsOutputs you create
cv_results- Dataframe indexed by the requested model IDs, with
initial_score,selected_scoreandsettingscolumns. - Scores are observed mean training-fold scores;
settingsdescribes the chosen recipe.
- Dataframe indexed by the requested model IDs, with
reference_resultscross_validateresult for the dummy reference; test_score contains five scores.
chosen_name- Model ID nominated from training evidence.
matrix- Confusion
matrixof training-only diagnostic predictions.
- Confusion
final_f1- Macro F1 on final-test class predictions.
final_accuracy- Final-test accuracy, supplementary to macro F1.
ablation_results- Five matching training-fold scores for the measurements-only ablation.
Deliverables
These conditions describe a complete workflow. Use the declared Python variables beside the editor; Check inspects evidence from your Run.
Python name key
Teal outlines name table columns. Violet left rules name Python objects. Dotted rules mark syntax, functions and parameters. Use each name exactly as shown.
Words in this task
DataFrame- a table with rows and columns
- numeric
- a number, rather than text
- dummy
- a simple reference model used for comparison
- folds
- training-data groups used to compare models on the same held-out rows
- out-of-fold
- predictions made for training rows by models that did not fit those rows
- aligned
- matched by row or category identity, rather than guessed position
- ablation
- a comparison that removes one input or part of a model
- residuals
- observed values minus predicted values
Data boundary
- Load the supplied challenge CSV, define the declared
X/yand keep aligned row identities through the split. - Keep learned preparation inside each training fit.
- Load the supplied challenge CSV, define the declared
Validation & selection
- Compare the requested
initialmodel families with a dummy reference on matching trainingfolds. - Evaluate the declared
settingswhere applicable and choose from training evidence.
- Compare the requested
Diagnosis
- Use out-of-fold training predictions to inspect residuals or class errors before opening the final test.
- Compare the measurements-only ablation on the same training
folds.
Final evidence
- Fit the nominated model on training rows and evaluate the reserved rows once.
- Report saved predictions, the requested metrics and labelled evidence
- Explain limitations without using the final test for further selection.
The playground workflow
Use the same data boundary as ML → Workflow: frame, split, explore, prepare, validate against a reference, diagnose, then make the final evaluation. Each step answers one question.
- Choose what to predictPredict penguin species from 7 selected inputs; each row is one penguin.
- Split data and save the test setWhich rows are available for learning, and which are being saved for the final check?
- Explore training dataDoes
bill_length_mmshow a training pattern related to penguin species? - Define the preparation recipeWhat preparation does this particular model need?
- Build the model pipelineCan a regularised linear score separate the classes?
- Validate the initial modelDo validation results stay reasonably similar across folds?
- Compare with a simple referenceDo the selected features beat a simple guess on the same training folds?
- Tune the modelDoes regularisation strength help the class boundary?
- Inspect validation errorsWhich classes are most often confused in training-only validation?
- Final testHow does the selected model's saved final penguin species result compare with the initial-model CV and any selected-setting CV for Palmer Penguins · Continuous + binary + categorical context? Use the training-only diagnostic or optional final confusion view to identify a class pattern, then name one limitation.
Data policy Keep target-derived inputs out of X. Use training-only selection for prediction.
Help Hints & explained solution
Choose the amount of help you need. Opening one hint does not reveal the others.
Hint 1 — Think
Strong scores can depend on a shortcut.
Hint 2 — Tools
OHE, StandardScaler, LogisticRegression, macro F1 and stratified CV.
Revisit: Classification checkpoint
Hint 3 — Approach
Compare C within the pipeline and inspect the context ablation using the same training folds.
Explained solution
This complete script replaces the editor contents. It includes the input setup and the workflow.
import numpy as np
import pandas as pd
df=pd.read_csv('data/ml-learning/ML-X05.csv')
from sklearn.base import clone
from sklearn.model_selection import train_test_split, StratifiedKFold, cross_validate, cross_val_predict, GridSearchCV
from sklearn.dummy import DummyClassifier
from sklearn.metrics import f1_score, accuracy_score, confusion_matrix
import matplotlib.pyplot as plt
import seaborn as sns
X=df[['bill_length_mm', 'bill_depth_mm', 'flipper_length_mm', 'body_mass_g', 'sex', 'island', 'year']]
y=df['species']
X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=.2,random_state=42,stratify=y)
folds=StratifiedKFold(n_splits=5,shuffle=True,random_state=42)
candidates={}
grids={}
# Prepare inputs and construct the candidate pipeline.
numeric_features = ['bill_length_mm', 'bill_depth_mm', 'flipper_length_mm', 'body_mass_g']
categorical_features = ['island', 'year']
encoded_binary_features = ['sex']
from sklearn.preprocessing import OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler
category_encoder = OneHotEncoder(handle_unknown='ignore', sparse_output=False, drop=None)
preprocessor = ColumnTransformer([('continuous', StandardScaler(), numeric_features), ('encoded', category_encoder, encoded_binary_features + categorical_features)], verbose_feature_names_out=False)
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
model = LogisticRegression(max_iter=2000, random_state=42)
pipeline = Pipeline([('prepare', preprocessor), ('model', model)])
model = pipeline
candidates['logistic']=model
grids['logistic']={'model__C': [0.1, 1.0, 10.0]}
# Validate initial candidates on matching training folds.
initial_results={name:cross_validate(candidate,X_train,y_train,cv=folds,scoring='f1_macro') for name,candidate in candidates.items()}
# Compare with a simple reference before tuning.
reference_results=cross_validate(DummyClassifier(strategy='most_frequent'),X_train,y_train,cv=folds,scoring='f1_macro')
rows=[]
selected={}
for name,candidate in candidates.items():
initial=initial_results[name]
grid=grids[name]
if grid:
search=GridSearchCV(candidate,grid,cv=folds,scoring='f1_macro',n_jobs=1)
search.fit(X_train,y_train)
selected[name]=search.best_estimator_
validation_score=float(search.best_score_)
settings=search.best_params_
else:
selected[name]=candidate
validation_score=float(np.mean(initial['test_score']))
settings='Keep defaults: no production search'
rows.append({'model':name,'initial_score':float(np.mean(initial['test_score'])),'selected_score':validation_score,'settings':str(settings)})
cv_results=pd.DataFrame(rows).set_index('model')
# Training-only contextual-feature ablation on identical folds.
from sklearn.linear_model import LogisticRegression
measurement_columns=['bill_length_mm','bill_depth_mm','flipper_length_mm','body_mass_g']
measurement_model=Pipeline([('scale',StandardScaler()),('model',LogisticRegression(max_iter=2000,random_state=42))])
ablation_results=cross_validate(measurement_model,X_train[measurement_columns],y_train,cv=folds,scoring='f1_macro')
# This solution nominates by mean training-fold score. Other evidence-based choices can be defensible.
chosen_name=cv_results.selected_score.idxmax()
chosen=selected[chosen_name]
oof_predictions=cross_val_predict(chosen,X_train,y_train,cv=folds)
diagnostic_y=y_train
class_labels=sorted(y_train.unique())
matrix=confusion_matrix(diagnostic_y,oof_predictions,labels=class_labels)
fig,ax=plt.subplots(figsize=(6,4))
sns.heatmap(matrix,annot=True,fmt='d',cmap='Blues',ax=ax,xticklabels=class_labels,yticklabels=class_labels)
ax.set(xlabel='Predicted class',ylabel='Actual class',title='Training-only confusion matrix')
fig.tight_layout()
fig.savefig('diagnostic.png',dpi=150,bbox_inches='tight')
final_model=clone(chosen).fit(X_train,y_train)
final_predictions=final_model.predict(X_test)
final_f1=f1_score(y_test,final_predictions,average='macro')
final_accuracy=accuracy_score(y_test,final_predictions)
print('Final macro F1:',final_f1,'; accuracy:',final_accuracy)
View input setup in this script
These opening lines are included in the complete script above. They load the challenge input.
import numpy as np
import pandas as pd
df=pd.read_csv('data/ml-learning/ML-X05.csv')Why these steps exist
- Scaling and encoding are fitted inside stratified folds. The measurements-only ablation uses those same folds, exposing dependence on context without consulting final species labels. OOF confusion and macro F1 qualify a potentially strong aggregate result.
Another valid approach
Equivalent ordinary Python is welcome. A defensible candidate or grouping need not match the solution’s choice; objective evidence must remain consistent.