Skip to learning content

DATA SCIENCE PYTHON PLAYGROUND

Machine Learning · Learn / Refresh

← All challenges
ML-X04 · Time-ordered prediction · 45–60 minutes

Predict in the direction of time

multiple_linear · regression_tree · validation · reference · final-test discipline

Complete workflow and evidence

The question

Compare linear and tree workflows for later Seoul hourly bike demand. Use the declared weather and calendar scenario and state prediction-time availability assumptions.

data/ml-learning/ML-X04.csv Complete workflow and evidence

Your inputs

Challenge input · ML-X04

8760 observations. One hourly rental observation in Seoul. 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. Rows are already ordered by parsed Date then Hour. Keep this chronological order; reserve the last 20%.

ML-X04 · first 8 prepared rows
DateTemperature(°C)Humidity(%)Wind speed (m/s)Visibility (10m)Solar Radiation (MJ/m2)Rainfall(mm)Snowfall (cm)HolidayHourSeasonsRented Bike Count
01/12/2017-5.2372.22000000No Holiday0Winter254
01/12/2017-5.5380.82000000No Holiday1Winter204
01/12/2017-63912000000No Holiday2Winter173
01/12/2017-6.2400.92000000No Holiday3Winter107
01/12/2017-6362.32000000No Holiday4Winter78
01/12/2017-6.4371.52000000No Holiday5Winter100
01/12/2017-6.6351.32000000No Holiday6Winter181
01/12/2017-7.4380.92000000No Holiday7Winter460

Column meanings and units

Rented Bike Count: rentals in an hour. Temperature/dew point: °C. Humidity: %. Wind: m/s. Visibility: tens of metres. Solar radiation: MJ/m². Rainfall: mm. Snowfall: cm.

Functioning Day is service operation, not weekday status. Observed same-hour weather is explanatory input; forecasting requires weather forecasts available at prediction time. ML uses chronological splitting.

Ready to load: comma-delimited UTF-8, header row, no saved index. No filtering or target construction is required. Rows are already ordered by parsed Date then Hour. Keep this chronological order; reserve the last 20%.

Input schema
ColumnStored type
Dateobject
Temperature(°C)float64
Humidity(%)int64
Wind speed (m/s)float64
Visibility (10m)int64
Solar Radiation (MJ/m2)float64
Rainfall(mm)float64
Snowfall (cm)float64
Holidayobject
Hourint64
Seasonsobject
Rented Bike Countint64

How we validate this model

Order the declared population by time. Reserve the final 20% of rows; use the earlier 80% for development.

Use five forward validation folds without shuffling. Diagnose the last training-validation block. Select with negative RMSE (larger is better) and compare with a training-mean reference. Report final RMSE in original target units. Open final-test evidence after selection and diagnosis.

The file is available in the Python working folder. Load it yourself.

Your task
  1. Compare linear and tree workflows for later Seoul hourly bike demand.
  2. Use the declared weather and calendar scenario and state prediction-time availability assumptions.
cv_resultsreference_resultschosen_nameresidualsfinal_rmse

Outputs you create

cv_results
  1. Dataframe indexed by the requested model IDs, with initial_score, selected_score and settings columns.
  2. Scores are observed mean training-fold scores; settings describes the chosen recipe.
reference_results
  1. cross_validate result for the dummy reference; test_score contains five scores.
chosen_name
  1. Model ID nominated from training evidence.
residuals
  1. Training-only actual, predicted and actual-minus-predicted residual evidence.
final_rmse
  1. Root mean squared error in original target units.

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
aligned
matched by row or category identity, rather than guessed position
residuals
observed values minus predicted values
RMSE
root mean squared error: an error measure that gives larger errors more weight
  1. Data boundary

    1. Load the supplied challenge CSV, define the declared X/y and keep aligned row identities through the split.
    2. Keep learned preparation inside each training fit.
  2. Validation & selection

    1. Compare the requested initial model families with a dummy reference on matching training folds.
    2. Evaluate the declared settings where applicable and choose from training evidence.
  3. Diagnosis

    1. Diagnose the last forward validation block
    2. Keep later final rows sealed.
  4. Final evidence

    1. Fit the nominated model on training rows and evaluate the reserved rows once.
    2. Report saved predictions, the requested metrics and labelled evidence
    3. 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.

  1. Choose what to predictPredict later bike-rental demand from 10 selected inputs; rows stay in chronological order.
  2. Split data and save the test setWhich rows are available for learning, and which are being saved for the final check?
  3. Explore training dataDoes temperature show a training pattern related to bike-rental demand?
  4. Define the preparation recipeWhat preparation does this particular model need?
  5. Build the model pipelineWhich if/then splits form useful numeric prediction groups?
  6. Validate the initial modelDo validation results stay reasonably similar across folds?
  7. Compare with a simple referenceDo the selected features beat a simple guess on the same training folds?
  8. Tune the modelHow deep should the tree grow?
  9. Inspect validation errorsDo training-only residuals form a roughly random cloud around zero?
  10. Final testHow does the saved final bike-rental demand error compare with the initial-model CV and any selected-setting CV across later time windows for Seoul Bike Sharing Demand · Continuous + binary + categorical, and which inputs would actually be available for a future prediction?

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

Future observations must not teach the past.

Hint 2 — Tools

Chronological slicing, TimeSeriesSplit, mixed preparation and last-block diagnosis.

Revisit: Respect time · Regression checkpoint

Hint 3 — Approach

Sort by date/hour; reserve the final period; compare forward-validation evidence and diagnose the last training block.

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-X04.csv')
from sklearn.base import clone
from sklearn.model_selection import train_test_split, TimeSeriesSplit, cross_validate, cross_val_predict, GridSearchCV
from sklearn.dummy import DummyRegressor
from sklearn.metrics import root_mean_squared_error

import matplotlib.pyplot as plt
import seaborn as sns
X=df[['Temperature(°C)', 'Humidity(%)', 'Wind speed (m/s)', 'Visibility (10m)', 'Solar Radiation (MJ/m2)', 'Rainfall(mm)', 'Snowfall (cm)', 'Holiday', 'Hour', 'Seasons']]
y=df['Rented Bike Count']
cut=int(len(df)*.8)
X_train,X_test=X.iloc[:cut],X.iloc[cut:]
y_train,y_test=y.iloc[:cut],y.iloc[cut:]
folds=TimeSeriesSplit(n_splits=5)
candidates={}
grids={}
# Prepare inputs and construct the candidate pipeline.
numeric_features = ['Temperature(°C)', 'Humidity(%)', 'Wind speed (m/s)', 'Visibility (10m)', 'Solar Radiation (MJ/m2)', 'Rainfall(mm)', 'Snowfall (cm)']
categorical_features = ['Hour', 'Seasons']
encoded_binary_features = ['Holiday']
from sklearn.preprocessing import OneHotEncoder
from sklearn.compose import ColumnTransformer
category_encoder = OneHotEncoder(handle_unknown='ignore', sparse_output=False, drop='first')
preprocessor = ColumnTransformer([('continuous', 'passthrough', 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 LinearRegression
model = LinearRegression()
pipeline = Pipeline([('prepare', preprocessor), ('model', model)])
model = pipeline
candidates['multiple_linear']=model
grids['multiple_linear']=None
# Prepare inputs and construct the candidate pipeline.
numeric_features = ['Temperature(°C)', 'Humidity(%)', 'Wind speed (m/s)', 'Visibility (10m)', 'Solar Radiation (MJ/m2)', 'Rainfall(mm)', 'Snowfall (cm)']
categorical_features = ['Hour', 'Seasons']
encoded_binary_features = ['Holiday']
from sklearn.preprocessing import OneHotEncoder
from sklearn.compose import ColumnTransformer
category_encoder = OneHotEncoder(handle_unknown='ignore', sparse_output=False, drop=None)
preprocessor = ColumnTransformer([('continuous', 'passthrough', numeric_features), ('encoded', category_encoder, encoded_binary_features + categorical_features)], verbose_feature_names_out=False)
from sklearn.pipeline import Pipeline
from sklearn.tree import DecisionTreeRegressor
model = DecisionTreeRegressor(random_state=42)
pipeline = Pipeline([('prepare', preprocessor), ('model', model)])
model = pipeline
candidates['regression_tree']=model
grids['regression_tree']={'model__max_depth': [3, 5, None]}
# Validate initial candidates on matching training folds.
initial_results={name:cross_validate(candidate,X_train,y_train,cv=folds,scoring='neg_root_mean_squared_error') for name,candidate in candidates.items()}
# Compare with a simple reference before tuning.
reference_results=cross_validate(DummyRegressor(strategy='mean'),X_train,y_train,cv=folds,scoring='neg_root_mean_squared_error')
rows=[]
selected={}
for name,candidate in candidates.items():
    initial=initial_results[name]
    grid=grids[name]
    if grid:
        search=GridSearchCV(candidate,grid,cv=folds,scoring='neg_root_mean_squared_error',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')
# 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]
train_indices,validation_indices=list(folds.split(X_train))[-1]
diagnostic_model=clone(chosen).fit(X_train.iloc[train_indices],y_train.iloc[train_indices])
diagnostic_X=X_train.iloc[validation_indices]
diagnostic_y=y_train.iloc[validation_indices]
oof_predictions=diagnostic_model.predict(diagnostic_X)
residuals=pd.DataFrame({'actual':diagnostic_y,'predicted':oof_predictions,'residual':diagnostic_y-oof_predictions})
fig,ax=plt.subplots(figsize=(6,4))
sns.scatterplot(x=residuals.predicted,y=residuals.residual,s=12,ax=ax)
ax.axhline(0,color='black')
ax.set(xlabel='Training-validation prediction',ylabel='Residual',title='Training-only residuals')
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_rmse=root_mean_squared_error(y_test,final_predictions)
print('Final RMSE:',final_rmse)
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-X04.csv')

Why these steps exist

  • The supplied file already fixes the chronological population. The final period stays later than development rows; forward folds and last-block diagnosis preserve that ordering during selection. Weather availability must still be justified for the intended prediction time.

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.

Ctrl/⌘+Enter: Run · Tab: indent · Esc then Tab: leave editor

Python loads when you run. Code and results stay in this activity only.

Run your code to inspect its output. Check uses that same run.