Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ jobs:
# To cancel previous actions that could run on this PR
steps:
- name: Check out repository
uses: actions/checkout@v5
uses: actions/checkout@v6

- name: Install the latest version of uv
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@v8.1.0
with:
version: "latest"
python-version: 3.13
Expand All @@ -42,7 +42,7 @@ jobs:

- name: Deploy preview
id: deploy-preview
uses: rossjrw/pr-preview-action@v1.6.2
uses: rossjrw/pr-preview-action@v1.8.1
with:
source-dir: ./_site/
preview-branch: ${{ env.PREVIEW_BRANCH }}
Expand All @@ -51,7 +51,7 @@ jobs:
pr_number: ${{ github.event.pull_request.number }}

- name: Comment PR (custom)
uses: marocchino/sticky-pull-request-comment@v2
uses: marocchino/sticky-pull-request-comment@v3
with:
header: pr-preview
message: |
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ jobs:
steps:

- name: Check out repository
uses: actions/checkout@v5
uses: actions/checkout@v6

- name: Install the latest version of uv
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@v8.1.0
with:
version: "latest"
python-version: 3.13
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Key variables include:
| `dist_tosea` | Distance to the coastline |
| `n_garage`, `n_pool`, `n_terrace`, ... | Outbuildings and amenities |

> See the full variable dictionary in [the dedicated page](intro_data.Qmd).
> See the full variable dictionary in [the dedicated page](subject/1-intro_data.qmd).

### 2. Pre-processing

Expand Down Expand Up @@ -155,7 +155,7 @@ In a similar way, the **fallback script is adapted manually.**
To run the solution, run `uv run solution/main.py`.
**This script runs all subscripts, logs models to MLFlow, updates data and back-up models in the S3 storage. It doesn't launch a local API.**

To **launch a local API**, run `uvicorn solution.api:app --reload`. You need to have your models stored in MLFlow for it to run properly.
To **launch a local API**, run `uv run uvicorn solution.api:app --reload`. You need to have your models stored in MLFlow for it to run properly.

## Contributing

Expand Down
2 changes: 1 addition & 1 deletion intermediate_solutions/2_preprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ def outlier_transform(y, lower=0.1, upper=0.9):
# %%

df["prop_type"] = pd.Categorical(
df["prop_type"],
df["prop_type"].astype(str),
categories=["1", "2"],
ordered=False
).rename_categories({"1": "House", "2": "Flat"})
Expand Down
4 changes: 4 additions & 0 deletions intermediate_solutions/3_GB.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ def print_metrics(model, split, X=X_train, y=y_train):
)


# %%
import warnings
warnings.filterwarnings("ignore", message=".*sklearn.utils.parallel.delayed.*")

# %%

from sklearn.model_selection import GridSearchCV
Expand Down
4 changes: 4 additions & 0 deletions intermediate_solutions/3_RF.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,10 @@ def rf_error_oob_plot(X_train,
"regressor__RF__max_depth" : [8, 13],
}

# %%
import warnings
warnings.filterwarnings("ignore", message=".*sklearn.utils.parallel.delayed.*")

# %%

from sklearn.model_selection import GridSearchCV
Expand Down
11 changes: 8 additions & 3 deletions subject/2-preprocessing.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,19 @@ To have a better understanding of what we will do, here is an overview of the pr

![Overview of the pre-processing](../img/pre-processing.png)

You can start from the script `main.py` stored in the folder `starting_point/`.

If you want, you can also directly use the complete script of this step.
It is stored in `intermediate_solutions/2_preprocessing.py`.

# What are data inputs ?

::: {.callout-note appearance="simple"}
## Watch out

All data inputs are available on the following url : `https://minio.lab.sspcloud.fr/projet-funathon/`
All data inputs are available in subfolders of the following url : `https://minio.lab.sspcloud.fr/projet-funathon/`. Without the proper url, this link won't work.

You have to load the file `2026/project1/data/1_input/transactions_EN.parquet` for transactions.
You have to load the file stored in the subfolder `2026/project1/data/1_input/transactions_EN.parquet` for the data transactions.

:::

Expand Down Expand Up @@ -386,7 +391,7 @@ df = df.dropna()
#| code-overflow: scroll

df["prop_type"] = pd.Categorical(
df["prop_type"],
df["prop_type"].astype(str),
categories=["1", "2"],
ordered=False
).rename_categories({"1": "House", "2": "Flat"})
Expand Down
21 changes: 20 additions & 1 deletion subject/3-GB_model.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ Now that we have trained and evaluated a Random Forest model, we will train a **

A methodological guide on ensemble methods by Insee is available [here](https://inseefrlab-github-io.translate.goog/DT_methodes_ensemblistes/chapters/chapter2/4-boosting.html?_x_tr_sl=fr&_x_tr_tl=en&_x_tr_hl=en&_x_tr_pto=wapp). If you are unfamiliar with gradient boosting, we recommend reading it before proceeding.

You can start from the script `main.py` stored in the folder `starting_point/`.

If you want, you can also directly use the complete script of this step.
It is stored in `intermediate_solutions/3_GB.py`.

# Concepts of Gradient Boosting

Like Random Forests, **Gradient Boosting** is an ensemble method that combines many decision trees. However, the two methods differ fundamentally in how those trees are built and combined.
Expand Down Expand Up @@ -290,6 +295,20 @@ When using `GridSearchCV`, the parameter names must match those of the estimator
To retrieve all fold scores after fitting, use `cv_results_` — it is a dict that contains `mean_train_score`, `mean_test_score`, and the corresponding parameter values.
:::

::: {.callout-tip title="Filter error messages"}

When doing your gridsearch, you may have many error messages about `sklearn.utils.parallel.delayed` that should be used with `sklearn.utils.parallel.Parallel`.
This error does not matter here.
To filter this error, just add the following lines of code before running your gridsearch :


```{python}
import warnings
warnings.filterwarnings("ignore", message=".*sklearn.utils.parallel.delayed.*")
```

:::

```{python}
#| code-fold: true
#| code-summary: See the solution
Expand Down Expand Up @@ -409,7 +428,7 @@ plot_results_cv("max_iter", df_step1)

If the best value of `max_iter` is the largest value tested (500), consider extending the grid before moving to the next step.

In the end, we chose the hyperparameters 500 fot he number of iterations : going beyond doesn't improve the score.
In the end, we chose the hyperparameters 500 fot the number of iterations : going beyond doesn't improve the score.
For the learning rate, 0.25 is a good value.

```{python}
Expand Down
25 changes: 24 additions & 1 deletion subject/3-RF_model.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ In the first part of this project, we prepared the data to train the model. We r

An Insee working document on ensemble methods is available [here](https://inseefrlab-github-io.translate.goog/DT_methodes_ensemblistes/chapters/chapter2/3-random_forest.html?_x_tr_sl=fr&_x_tr_tl=en&_x_tr_hl=en&_x_tr_pto=wapp). If you are unfamiliar with random forests, we recommend reading this document before processing.

You can start from the script `main.py` stored in the folder `starting_point/`.

If you want, you can also directly use the complete script of this step.
It is stored in `intermediate_solutions/3_RF.py`.

# Concepts of Random Forests

**Random Forests** extend [bagging](https://inseefrlab-github-io.translate.goog/DT_methodes_ensemblistes/chapters/chapter2/2-bagging.html?_x_tr_sl=fr&_x_tr_tl=en&_x_tr_hl=en&_x_tr_pto=wapp) by introducing an additional level of randomness: at each node, the splitting rule is determined using only a **randomly selected subset of features**. This further **reduces correlation between trees**, thereby **lowering the variance of the aggregated model's predictions**.
Expand Down Expand Up @@ -448,7 +453,7 @@ oob_error_ntrees

## Tuning all others hyperparameters with cross validation

**Cross-validation** is a key step in model training : it is a technique used to evaluate the model's ability to generalize to unseendata, by splitting the dataset into multiple folds (typically 5) and iteratively using each fold as a validation set while the remaining folds are used for training. It also allows you to compare different set of hyperparameters and select the configuration that yields the best predictive performance.
**Cross-validation** is a key step in model training : it is a technique used to evaluate the model's ability to generalize to unseen data, by splitting the dataset into multiple folds (typically 5) and iteratively using each fold as a validation set while the remaining folds are used for training. It also allows you to compare different set of hyperparameters and select the configuration that yields the best predictive performance.

Note that in the Preprocessing section, you saw how to build a Pipeline. In this exercise, we will use a Pipeline again. The first exercise didn't use it to let you practice scikit-learn tools documented [here](https://scikit-learn.org/stable/modules/compose.html#pipelines-and-composite-estimators).

Expand All @@ -472,6 +477,7 @@ y_test = pd.read_parquet("https://minio.lab.sspcloud.fr/projet-funathon/2026/pr
#| echo: false
#| output: false

# To speed up computation time to render the site
X_train = X_train.sample(frac=0.1, random_state=RANDOM_STATE)
y_train = y_train[X_train.index]

Expand Down Expand Up @@ -506,6 +512,21 @@ param_grid = {

2. Using the [Grid Search documentation](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html), **set up and run cross-validated hyperparameter tuning for the RF model**. Note that training the model should last around 10 minutes. You can sample the dataset if you want to have a faster training.

::: {.callout-tip title="Filter error messages"}

When doing your gridsearch, you may have many error messages about `sklearn.utils.parallel.delayed` that should be used with `sklearn.utils.parallel.Parallel`.
This error does not matter here.
To filter this error, just add the following lines of code before running your gridsearch :


```{python}
import warnings
warnings.filterwarnings("ignore", message=".*sklearn.utils.parallel.delayed.*")
```

:::


```{python}
#| code-fold: true
#| code-summary: See the solution
Expand All @@ -528,6 +549,8 @@ grid_search = GridSearchCV(
grid_search.fit(X_train, y_train)
```



3. From the fitted `grid_search` object, **retrieve the best hyperparameters found for the model.**

```{python}
Expand Down
5 changes: 5 additions & 0 deletions subject/4-metrics.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ Training a model is only half the work. Before drawing any conclusions or deploy

Before evaluating our trained models, you will discover some metrics and plots to measure the quality of the predictions.

You can start from the script `main.py` stored in the folder `starting_point/`.

If you want, you can also directly use the complete script of this step.
It is stored in `intermediate_solutions/4_metrics.py`.

# How can you evaluate the model's inference ?

## Regression metrics
Expand Down
11 changes: 8 additions & 3 deletions subject/6-deployment.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ format:

So far, we have trained and evaluated a housing price prediction model, and tracked our experiments with MLFlow. The final step of a machine learning pipeline is to make the model **available to end users**, so that it can produce predictions on new data without requiring anyone to re-run training code.

You can start from the script `main.py` stored in the folder `intermediate_solutions/5_api.py`.

If you want, you can also directly use the complete script of this step.
It is stored in `solution/api.py`.

In this chapter, we build a local **REST API** using [FastAPI](https://fastapi.tiangolo.com/) that wraps our trained model. A user (or another service) will be able to send a POST request describing a property — floor area, location, number of rooms, etc. — and receive a predicted price in return.

The overall architecture we are aiming for:
Expand Down Expand Up @@ -81,22 +86,22 @@ def read_root():
**Save this file, name it `api.py` and run it with:**

```{.bash filename="terminal"}
uvicorn api:app --reload
uv run uvicorn api:app --reload
```

The `--reload` flag restarts the server automatically whenever you save changes to `api.py`, which is very convenient during development.

If you saved your file into a specific folder, you can access it with the following command :

```{.bash filename="terminal"}
uvicorn folder.script_name:app --reload
uv run uvicorn folder.script_name:app --reload
```

For example, you can launch the api with the following code.
It serves as a fall-back option.

```{.bash filename="terminal"}
uvicorn intermediate_solutions.5_api:app --reload
uv run uvicorn intermediate_solutions.5_api:app --reload
```

**Then open [http://localhost:8000](http://localhost:8000) in your browser. You should see the JSON response `"Housing price prediction API is running"`.**
Expand Down
31 changes: 24 additions & 7 deletions subject/introduction.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -65,38 +65,43 @@ This project includes four steps (listed in the banner at the top of the page):

The final script is stored in the `solution/` folder.
A `main.py` script calls on other sub-scripts, following the different steps of the project.
If you want to toy around with hyperparameters,
To run it, just run `uv run solution/main.py` and it will execute all the steps at once.

To run the final API, run `uvicorn solution.app:app --reload`.
To run the final API, run `uv run uvicorn solution.app:app --reload`.

# Project initialization

## Technical requirements

- You need to have an account on [Insee's Onyxia platform](https://datalab.sspcloud.fr/), called SSPCloud (for *cloud platform for the French Official Statistical System*). When you are on this webpage, you should see something similar to this image once you're logged in. To change the language, you can do so on the bottom right part of the webpage (see the orange arrow on the screen shot below).
- You need to have an account on [Insee's Onyxia platform](https://datalab.sspcloud.fr/), called SSPCloud (for *cloud platform for the French Official Statistical System*). When you are on this webpage, you should see something similar to this image once you're logged in. You can select your preferred language in the bottom right hand corner (see the orange arrow on the screen shot below).

![Home page of <https://datalab.sspcloud.fr/>](../img/onyxia_home.png)

- You also need to have a Github account. Your Github credentials (username, email and token) should be registered in your [Insee's Onyxia](https://datalab.sspcloud.fr/) account in the My account/Git tab.

## Initialize your MLFlow service

Launch a MLflow service by clicking on the below button with your Onyxia account opened: <a href="https://datalab.sspcloud.fr/launcher/automation/mlflow?autoLaunch=true" target="_blank" rel="noopener"><img src="https://custom-icon-badges.demolab.com/badge/SSP%20Cloud-Launch_MLFlow-blue?logo=mlflow&logoColor=white" alt="Onyxia"/></a>
If you have already opened a MLFlow service, you can skip this step.

Launch a MLflow service by clicking on the following button below with your Onyxia account opened <a href="https://datalab.sspcloud.fr/launcher/automation/mlflow?autoLaunch=true" target="_blank" rel="noopener"><img src="https://custom-icon-badges.demolab.com/badge/SSP%20Cloud-Launch_MLFlow-blue?logo=mlflow&logoColor=white" alt="Onyxia"/></a>.

## Fork the project with `Git` {{< fa brands git-alt >}}

First, you need to fork the funathons's project on Github by clicking on [this link](https://github.com/AIML4OS/funathon-project1/fork). For convenience, **please not to change the repository name**. Write down the owner's name `OWNER_NAME` for the next step.
Decide on whether you want to work each one in your own repo or if you want to work in the same git repo for the whole team.
To improve collaborative work, we **recommend using a shared repo and working in different branches**. This way, you can use git's opportunities.

If you have only one repo, one person of your team has to fork the funathons's project on Github by clicking on [this link](https://github.com/AIML4OS/funathon-project1/fork). For convenience, **please not to change the repository name**. Write down the owner's name `OWNER_NAME` for the next step.

![Forking a github project](../img/github_fork.png)

If you decide to work each one in your repo, every one in the team forks the project in his/her own repo with his/her own owner's name.

## Open a VS Code on SSPCloud


To launch the project, open a VS Code service with the following button: <a href="https://datalab.sspcloud.fr/launcher/ide/vscode-python?name=AIML4OS-funathon-project1&version=2.5.5&s3=region-79669f20&git.cache=«5000»&networking.user.enabled=true&autoLaunch=true" target="_blank" rel="noopener"><img src="https://custom-icon-badges.demolab.com/badge/SSP%20Cloud-Launch_with_VSCode-blue?logo=vsc&amp;logoColor=white" alt="Onyxia"/></a>.

In the VS Code service, open a terminal (`CTRL` + `MAJ` + `C` or in the file menu go to `Terminal > New Terminal`). Clone the project repository with the following command after replacing `OWNER_NAME` with your name on Github from the previous step:
In the VS Code service, open a terminal (`CTRL` + `MAJ` + `C` or in the file menu go to `Terminal > New Terminal`). Clone the project repository with the following command after replacing `OWNER_NAME` with the name of the owner of the repo where you'll be working from the previous step:

```{.bash}
OWNER_NAME="AIML4OS" # Change your Github name here
Expand Down Expand Up @@ -155,12 +160,24 @@ onyxia@vscode-python-882151-0:~/work$

After installing dependencies with `uv`, you need to configure the Python interpreter so that the installed packages are properly recognized. This will allow you to run Python scripts in parts, similar to working in a Jupyter notebook.

To do this, open the command palette `Show and Run commands` or press `Ctrl+Shift+P`, then select **`Python: select interpreter`**, then click on `Enter interpreter path`. Finally, enter the following path, which corresponds to the Python interpreter generated by `uv`:
To do this, open the command palette `Show and Run commands` or press `F1` or `Ctrl+Shift+P`, then select **`Python: select interpreter`**, then click on `Enter interpreter path`. Finally, enter the following path, which corresponds to the Python interpreter generated by `uv`:

```{.bash}
/home/onyxia/work/funathon-project1/.venv/bin/python3.13
```

## Running scripts

You need to use `uv` to run a Python script using uv's managed environment.
`uv` will manage all the dependancies of your script.
To do so, you need to be in the working directory where the `pyproject.toml` file is stored.

To run the script in starting point for example, run the following command:

```{.bash}
~/work/funathon-project1$ uv run starting_point/main.py
```

# Next step
Congrats, you're all set-up now.

Expand Down
Loading