From e4b7266871973be3b4e6d2c745cb8e26bbef42e9 Mon Sep 17 00:00:00 2001 From: Aruket Date: Tue, 6 May 2025 19:54:52 +0200 Subject: [PATCH 01/16] beginners guide creation and "how to" fix --- examples/plot_beginners_guide.py | 89 +++++++++++++++++++++++++++++++ examples/plot_how_to_use_skada.py | 3 +- 2 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 examples/plot_beginners_guide.py diff --git a/examples/plot_beginners_guide.py b/examples/plot_beginners_guide.py new file mode 100644 index 00000000..54b86935 --- /dev/null +++ b/examples/plot_beginners_guide.py @@ -0,0 +1,89 @@ +""" +Beginners Guide +=============== + +This is an introduction page to SKADA: SciKit Adaptation for beginners. +SKADA is an open-source library focusing on domain adaptation methods that goes +hand in hand with scikit-learn. + +In this page, we will present the key concepts and methods for starting to use SKADA +and how to use them. + +* :ref:`Shifted dataset creation`: + * :ref:`Covariate shift` + * :ref:`Conditional shift` + * :ref:`Subspace shift` + +* :ref:`Methods` + * :ref:`Reweighting` + * :ref:`Mapping` + * :ref:`Subspace` + +* :ref:`Summary` + +""" + +# Author: Maxence Barneche +# +# License: BSD 3-Clause + +# %% +# Creating a shifted dataset +# -------------------------- +# +# In SKADA, + +# %% +# Dataset with covariate shift +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# + +# %% +# Dataset with target shift +# ~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# + +# %% +# Dataset with conditional shift +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# + +# %% +# Dataset with subspace shift +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# + +# %% +# Adaptation methods +# ------------------ +# +# + +# %% +# Source dataset reweighting +# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# + +# %% +# Source to target mapping +# ~~~~~~~~~~~~~~~~~~~~~~~~ +# +# + +# %% +# Subspace mapping +# ~~~~~~~~~~~~~~~~ +# +# + +# %% +# Results summary +# --------------- +# +# diff --git a/examples/plot_how_to_use_skada.py b/examples/plot_how_to_use_skada.py index 53ba4d68..e44544bc 100644 --- a/examples/plot_how_to_use_skada.py +++ b/examples/plot_how_to_use_skada.py @@ -97,7 +97,6 @@ # DA estimator in a pipeline # ----------------------------- # - # SKADA estimators can be used as the final estimator of a scikit-learn pipeline. # Again, the only difference is that the :code:`sample_domain` array must be passed # by name during in fit. @@ -121,7 +120,7 @@ # Here is an example with the CORAL and GaussianReweight adapters. # # .. WARNING:: - +# # Note that as illustrated below for reweighting adapters, one needs a # subsequent estimator that takes :code:`sample_weight` as an input parameter. # This can be done using the :code:`set_fit_request` method of the estimator From e86b4dd38499255e59ef4693bb6551e6459420e5 Mon Sep 17 00:00:00 2001 From: Aruket Date: Wed, 7 May 2025 11:08:34 +0200 Subject: [PATCH 02/16] Added examples and explanation for shifts --- examples/plot_beginners_guide.py | 181 ++++++++++++++++++++++++++++--- 1 file changed, 168 insertions(+), 13 deletions(-) diff --git a/examples/plot_beginners_guide.py b/examples/plot_beginners_guide.py index 54b86935..40273c12 100644 --- a/examples/plot_beginners_guide.py +++ b/examples/plot_beginners_guide.py @@ -10,10 +10,10 @@ and how to use them. * :ref:`Shifted dataset creation`: - * :ref:`Covariate shift` - * :ref:`Conditional shift` - * :ref:`Subspace shift` + * :ref:`Covariate shift` + * :ref:`Conditional shift` + * :ref:`Subspace shift` * :ref:`Methods` * :ref:`Reweighting` @@ -22,41 +22,196 @@ * :ref:`Summary` +For better readability, only the use of SKADA is provided and the plotting code +with matplotlib is hidden (but is available in the source file of the example). """ # Author: Maxence Barneche # # License: BSD 3-Clause +# %% +# Necessary imports + +# sphinx_gallery_start_ignore +import matplotlib.pyplot as plt +import numpy as np + +# sphinx_gallery_end_ignore +from skada import source_target_split +from skada.datasets import make_shifted_datasets + +# %% + +# sphinx_gallery_start_ignore +fig_size = (7.5, 3.625) + + +def decision_borders_plot(X, model): + # Create a meshgrid + x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1 + y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1 + xx, yy = np.meshgrid( + np.linspace(x_min, x_max, num=100), np.linspace(y_min, y_max, num=100) + ) + + # Predict on every point of the meshgrid + Z = model.predict(np.c_[xx.ravel(), yy.ravel()]) + Z = Z.reshape(xx.shape) + + # Plot decision borders + plt.contourf(xx, yy, Z, alpha=0.4, cmap="tab10", vmax=9) + + +def source_target_comparison(X, y, sample_domain, title, prediction=False, model=None): + Xs, Xt, ys, yt = source_target_split(X, y, sample_domain=sample_domain) + plt.subplot(1, 2, 1) + plt.scatter( + Xs[:, 0], Xs[:, 1], c=ys, cmap="tab10", vmax=9, label="Source", alpha=0.8 + ) + + plt.xticks([]) + plt.yticks([]) + plt.title("Source data") + if prediction: + decision_borders_plot(X, model) + ax = plt.axis() + + plt.subplot(1, 2, 2) + plt.scatter( + Xt[:, 0], Xt[:, 1], c=yt, cmap="tab10", vmax=9, label="Target", alpha=0.8 + ) + plt.xticks([]) + plt.yticks([]) + plt.title("Target data") + if prediction: + decision_borders_plot(X, model) + plt.axis(ax) + + plt.suptitle(title) + + +# sphinx_gallery_end_ignore + # %% # Creating a shifted dataset # -------------------------- # -# In SKADA, +# Data shift occurs when there is a change in data distribution. It can come from +# from a change in the input dataset, the target variable or the latent relations +# between the two. +# +# This implies that a model trained on an original dataset, (called source) +# will have a decrease in performance when predicting on the shifted dataset +# (called target). +# We will see the different methods used to deal with data shift +# in the :ref:`methods` section. +# +# DA datasets provided by SKADA are organized as follows: +# +# * :code:`X` is the input data, including the source and the target samples +# * :code:`y` is the output data to be predicted (labels on target samples are not +# used when fitting the DA estimator) +# * :code:`sample_domain` encodes the domain of each sample (integer >=0 for +# source and <0 for target) +# +# To create a shifted dataset, use the method :code:`make_shifted_dataset` +# from the `skada.datasets` module. + +X, y, sample_domain = make_shifted_datasets( + n_samples_source=20, n_samples_target=20, random_state=42 +) # %% -# Dataset with covariate shift -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# To split the dataset between the source and the target dataset, use +# :code:`source_target_split` from the main module + +Xs, Xt, ys, yt = source_target_split(X, y, sample_domain=sample_domain) +# %% +# .. NOTE:: +# +# For reproducibility, we will use the seed 42 throughout the guide. +# For simplicity, we will use a small (20) number of samples +# in both source and target. Feel free to change these arguments to your liking once +# you have a good understanding of the process. # +# .. NOTE:: # +# Though SKADA can manage multidomain datasets, we will only generate simple 2D +# DA datasets with a single source domain and a single target domain in this guide. +# +# There are four main types of shift available with SKADA. +# To specify the type of shift, adjust the :code:`shift` argument in +# :code:`make_shifted_datasets`. By default, this argument is set to +# :code:`covariate_shift` +# +# Example of covariate shift +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Covariate shift is characterised by a change of distribution +# in one or more of the independent variables from the input data. + +X, y, sample_domain = make_shifted_datasets( + n_samples_source=20, n_samples_target=20, shift="covariate_shift", random_state=42 +) + +# sphinx_gallery_start_ignore +plt.figure(1, fig_size) +source_target_comparison(X, y, sample_domain, "Example covariate shift") +plt.tight_layout() +# sphinx_gallery_end_ignore # %% -# Dataset with target shift +# Example of target shift # ~~~~~~~~~~~~~~~~~~~~~~~~~ # -# +# Target shift (or prior probability shift) is characterised by a change in +# target variable distribution while the source data distribution remains the same. + +X, y, sample_domain = make_shifted_datasets( + n_samples_source=20, n_samples_target=20, shift="target_shift", random_state=42 +) + +# sphinx_gallery_start_ignore +plt.figure(2, fig_size) +source_target_comparison(X, y, sample_domain, "Example target shift") +plt.tight_layout() +# sphinx_gallery_end_ignore # %% -# Dataset with conditional shift +# Example of conditional shift # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # -# +# Conditional shift (or concept drift) is characterised by a change in the +# relation between input and output variables. + +X, y, sample_domain = make_shifted_datasets( + n_samples_source=20, n_samples_target=20, shift="conditional_shift", random_state=42 +) + +# sphinx_gallery_start_ignore +plt.figure(3, fig_size) +source_target_comparison(X, y, sample_domain, "Example conditional shift") +plt.tight_layout() +# sphinx_gallery_end_ignore # %% -# Dataset with subspace shift +# Example of subspace shift # ~~~~~~~~~~~~~~~~~~~~~~~~~~~ # -# +# Subspace shift is characterised by a change in data distribution where there exists +# a subspace such that the projection of the data on that +# subspace keeps the same distribution + +X, y, sample_domain = make_shifted_datasets( + n_samples_source=20, n_samples_target=20, shift="subspace", random_state=42 +) + +# sphinx_gallery_start_ignore +plt.figure(4, fig_size) +source_target_comparison(X, y, sample_domain, "Example subspace shift") +plt.tight_layout() +# sphinx_gallery_end_ignore # %% # Adaptation methods From 7a7a659d4f27f9617c2dba8180a31d6659ddee5f Mon Sep 17 00:00:00 2001 From: Aruket Date: Wed, 7 May 2025 14:15:26 +0200 Subject: [PATCH 03/16] added beginners guide to sphinx index --- docs/source/index.rst | 1 + examples/plot_beginners_guide.py | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/source/index.rst b/docs/source/index.rst index 132d1683..a0726bbe 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -17,6 +17,7 @@ Contents :maxdepth: 1 self + auto_examples/plot_beginners_guide auto_examples/plot_how_to_use_skada quickstart all diff --git a/examples/plot_beginners_guide.py b/examples/plot_beginners_guide.py index 40273c12..651eb5be 100644 --- a/examples/plot_beginners_guide.py +++ b/examples/plot_beginners_guide.py @@ -29,6 +29,7 @@ # Author: Maxence Barneche # # License: BSD 3-Clause +# sphinx_gallery_thumbnail_number = 4 # %% # Necessary imports From 9103f2419fc1a3b8c406d1883aac46f483ad48fa Mon Sep 17 00:00:00 2001 From: Aruket Date: Wed, 7 May 2025 16:56:49 +0200 Subject: [PATCH 04/16] Added most of the adaptation methods --- examples/plot_beginners_guide.py | 181 ++++++++++++++++++++++++++++--- 1 file changed, 167 insertions(+), 14 deletions(-) diff --git a/examples/plot_beginners_guide.py b/examples/plot_beginners_guide.py index 651eb5be..ed0c70ce 100644 --- a/examples/plot_beginners_guide.py +++ b/examples/plot_beginners_guide.py @@ -10,7 +10,7 @@ and how to use them. * :ref:`Shifted dataset creation`: - * :ref:`Covariate shift` * :ref:`Target shift` * :ref:`Conditional shift` * :ref:`Subspace shift` @@ -18,7 +18,7 @@ * :ref:`Methods` * :ref:`Reweighting` * :ref:`Mapping` - * :ref:`Subspace` + * :ref:`Subspace` * :ref:`Summary` @@ -29,7 +29,7 @@ # Author: Maxence Barneche # # License: BSD 3-Clause -# sphinx_gallery_thumbnail_number = 4 +# sphinx_gallery_thumbnail_number = 6 # %% # Necessary imports @@ -37,15 +37,20 @@ # sphinx_gallery_start_ignore import matplotlib.pyplot as plt import numpy as np +from sklearn.linear_model import LogisticRegression # sphinx_gallery_end_ignore -from skada import source_target_split +from sklearn.neighbors import KernelDensity +from sklearn.svm import SVC + +import skada from skada.datasets import make_shifted_datasets +from skada.utils import extract_source_indices # %% # sphinx_gallery_start_ignore -fig_size = (7.5, 3.625) +fig_size = (8, 4) def decision_borders_plot(X, model): @@ -64,11 +69,20 @@ def decision_borders_plot(X, model): plt.contourf(xx, yy, Z, alpha=0.4, cmap="tab10", vmax=9) -def source_target_comparison(X, y, sample_domain, title, prediction=False, model=None): - Xs, Xt, ys, yt = source_target_split(X, y, sample_domain=sample_domain) +def source_target_comparison( + X, y, sample_domain, title, prediction=False, model=None, size=25 +): + Xs, Xt, ys, yt = skada.source_target_split(X, y, sample_domain=sample_domain) plt.subplot(1, 2, 1) plt.scatter( - Xs[:, 0], Xs[:, 1], c=ys, cmap="tab10", vmax=9, label="Source", alpha=0.8 + Xs[:, 0], + Xs[:, 1], + s=size, + c=ys, + cmap="tab10", + vmax=9, + label="Source", + alpha=0.8, ) plt.xticks([]) @@ -127,7 +141,7 @@ def source_target_comparison(X, y, sample_domain, title, prediction=False, model # To split the dataset between the source and the target dataset, use # :code:`source_target_split` from the main module -Xs, Xt, ys, yt = source_target_split(X, y, sample_domain=sample_domain) +Xs, Xt, ys, yt = skada.source_target_split(X, y, sample_domain=sample_domain) # %% # .. NOTE:: # @@ -218,28 +232,167 @@ def source_target_comparison(X, y, sample_domain, title, prediction=False, model # Adaptation methods # ------------------ # +# As stated before, a model trained on a source dataset will have a decrease +# in performance when evaluated on a shifted target dataset. Thus, there is a need +# to train the model again to account for the shift in data distribution. +# +# In some cases, the source is the only data fully available, as the target may not +# have been classified yet. A common solution is to adapt the source data. +# +# For every shift, there is a method to adapt the source data to train the model on. # - -# %% # Source dataset reweighting # ~~~~~~~~~~~~~~~~~~~~~~~~~~ # +# A common method for dealing with covariate shift is reweighting the source data. +# +# SKADA handles this with multiple reweighting methods: +# +# * Density Reweighting +# * Gaussian Reweighting +# * Discr. Reweighting +# * KLIEPReweight +# * Nearest Neighbor reweighting +# * Kernel Mean Matching +# +# Each method estimates the weight for the source dataset for an estimator +# to predict labels from the target dataset. # +# Using a simple :code:`LogisticRegression` classifier, +# we can see that the estimator is not optimal on the target dataset. + +X, y, sample_domain = make_shifted_datasets( + n_samples_source=20, n_samples_target=20, shift="covariate_shift", random_state=42 +) +Xs, Xt, ys, yt = skada.source_target_split(X, y, sample_domain=sample_domain) + +base_classifier = LogisticRegression().set_fit_request(sample_weight=True) +base_classifier.fit(Xs, ys) + +# compute the accuracy of the model +accuracy = base_classifier.score(Xt, yt) + +# sphinx_gallery_start_ignore +plt.figure(5, fig_size) +source_target_comparison( + X, + y, + sample_domain, + "Predictions without reweighting", + prediction=True, + model=base_classifier, +) +plt.tight_layout() +print("Accuracy on target:", accuracy) +# sphinx_gallery_end_ignore + +# %% +# The reweighting is done by transforming the source dataset using an instance of +# the :code:`Adapter` class provided by SKADA. + +# We define the classifier as a da pipeline from the base classifier +clf = skada.DensityReweight( + base_estimator=base_classifier, weight_estimator=KernelDensity(bandwidth=0.5) +) + +clf.fit(X, y, sample_domain=sample_domain) + +# To extract the weights, we take the weight estimator from the pipeline +weight_estimator = clf[0].get_estimator() +idx = extract_source_indices(sample_domain) +# then compute the weights corresponding to the source dataset +weights = weight_estimator.compute_weights(X, sample_domain=sample_domain)[idx] + +# comput the accuracy of the newly obtained model +accuracy = clf.score(Xt, yt) + +# sphinx_gallery_start_ignore +weights = 15 * weights +plt.figure(6, fig_size) +source_target_comparison( + X, + y, + sample_domain, + "Prediction on reweighted dataset", + prediction=True, + model=clf, + size=weights, +) +plt.tight_layout() +print("Accuracy on target:", accuracy) +# sphinx_gallery_end_ignore + # %% # Source to target mapping # ~~~~~~~~~~~~~~~~~~~~~~~~ # +# The traditional way of dealing with conditional shift is via mapping. # +X, y, sample_domain = make_shifted_datasets( + n_samples_source=20, n_samples_target=20, shift="concept_drift", random_state=42 +) + +Xs, Xt, ys, yt = skada.source_target_split(X, y, sample_domain=sample_domain) + +# %% +# +# +# # %% -# Subspace mapping +# Subspace methods # ~~~~~~~~~~~~~~~~ # +# The goal of a subspace method is to project data from its original space into a +# lower dimensional subspace. Subspace methods are particularly effective when dealing +# with subspace shift, when the source and target data have the same distribution when +# projected onto a subspace. +# +# There are multiple methods available in SKADA: # +# * Subspace alignment +# * Transfer Component Analysis +# * Transfer Joint Matching +# * Transfer Subspace Learning +# +# Without domain adaptation, the estimator will have difficulties on the target + +X, y, sample_domain = make_shifted_datasets( + n_samples_source=20, n_samples_target=20, shift="subspace", random_state=42 +) + +Xs, Xt, ys, yt = skada.source_target_split(X, y, sample_domain=sample_domain) + +# setting and fitting the estimator on the source data +base_classifier = SVC() +base_classifier.fit(Xs, ys) + +# accuracy on target data +accuracy = base_classifier.score(Xt, yt) + +# sphinx_gallery_start_ignore +plt.figure(9, fig_size) +source_target_comparison( + X, y, sample_domain, "Prediction on dataset", True, base_classifier +) +plt.tight_layout() +print("Accuracy on target:", accuracy) +# sphinx_gallery_end_ignore + +# %% +# Now, we will illustrate what happens when using the Transfer Subspace Learning method +clf = skada.TransferSubspaceLearning(base_classifier, n_components=1) +clf.fit(X, y, sample_domain=sample_domain) +accuracy = clf.score(Xt, yt) + +# sphinx_gallery_start_ignore +plt.figure(10, fig_size) +source_target_comparison(X, y, sample_domain, "Prediction on dataset", True, clf) +plt.tight_layout() +print("Accuracy on target:", accuracy) +# sphinx_gallery_end_ignore # %% # Results summary # --------------- -# -# From 8c1ed19792754f47c3416a2cd2a054bb1585a642 Mon Sep 17 00:00:00 2001 From: Aruket Date: Wed, 7 May 2025 17:12:48 +0200 Subject: [PATCH 05/16] updated for compatibility with current version changed conditional_shift to concept_drift so that the current skada version holds. Will be changed back as soon as the correct version gets out --- examples/plot_beginners_guide.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/plot_beginners_guide.py b/examples/plot_beginners_guide.py index ed0c70ce..8599cad6 100644 --- a/examples/plot_beginners_guide.py +++ b/examples/plot_beginners_guide.py @@ -201,7 +201,7 @@ def source_target_comparison( # relation between input and output variables. X, y, sample_domain = make_shifted_datasets( - n_samples_source=20, n_samples_target=20, shift="conditional_shift", random_state=42 + n_samples_source=20, n_samples_target=20, shift="concept_drift", random_state=42 ) # sphinx_gallery_start_ignore From 2ee72ad40e5556f2fdf578c34c48e1281335f588 Mon Sep 17 00:00:00 2001 From: Aruket Date: Fri, 9 May 2025 11:26:35 +0200 Subject: [PATCH 06/16] Added summary plot --- examples/plot_beginners_guide.py | 122 ++++++++++++++++++++++++------- 1 file changed, 94 insertions(+), 28 deletions(-) diff --git a/examples/plot_beginners_guide.py b/examples/plot_beginners_guide.py index 8599cad6..c392022b 100644 --- a/examples/plot_beginners_guide.py +++ b/examples/plot_beginners_guide.py @@ -53,6 +53,13 @@ fig_size = (8, 4) +def print_scores_as_table(scores): + max_len = max(len(k) for k in scores.keys()) + for k, v in scores.items(): + print(f"{k}{' '*(max_len - len(k))} | ", end="") + print(f"{v*100}{' '*(6-len(str(v*100)))}%") + + def decision_borders_plot(X, model): # Create a meshgrid x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1 @@ -69,41 +76,30 @@ def decision_borders_plot(X, model): plt.contourf(xx, yy, Z, alpha=0.4, cmap="tab10", vmax=9) -def source_target_comparison( - X, y, sample_domain, title, prediction=False, model=None, size=25 -): - Xs, Xt, ys, yt = skada.source_target_split(X, y, sample_domain=sample_domain) - plt.subplot(1, 2, 1) +def plot_full_data(X, y, title, prediction=False, model=None, size=25): plt.scatter( - Xs[:, 0], - Xs[:, 1], - s=size, - c=ys, - cmap="tab10", - vmax=9, - label="Source", - alpha=0.8, + X[:, 0], X[:, 1], s=size, c=y, cmap="tab10", vmax=9, label="Target", alpha=0.8 ) - plt.xticks([]) plt.yticks([]) - plt.title("Source data") if prediction: decision_borders_plot(X, model) - ax = plt.axis() + if title is not None: + plt.title(title) + + +def source_target_comparison( + X, y, sample_domain, title, prediction=False, model=None, size=25 +): + Xs, Xt, ys, yt = skada.source_target_split(X, y, sample_domain=sample_domain) + + plt.subplot(1, 2, 1) + plot_full_data(Xs, ys, "Source data", prediction, model, size) plt.subplot(1, 2, 2) - plt.scatter( - Xt[:, 0], Xt[:, 1], c=yt, cmap="tab10", vmax=9, label="Target", alpha=0.8 - ) - plt.xticks([]) - plt.yticks([]) - plt.title("Target data") - if prediction: - decision_borders_plot(X, model) - plt.axis(ax) + plot_full_data(Xt, yt, "Target data", prediction, model) - plt.suptitle(title) + plt.suptitle(title, fontsize=16) # sphinx_gallery_end_ignore @@ -201,7 +197,7 @@ def source_target_comparison( # relation between input and output variables. X, y, sample_domain = make_shifted_datasets( - n_samples_source=20, n_samples_target=20, shift="concept_drift", random_state=42 + n_samples_source=20, n_samples_target=20, shift="conditional_shift", random_state=42 ) # sphinx_gallery_start_ignore @@ -331,7 +327,7 @@ def source_target_comparison( # X, y, sample_domain = make_shifted_datasets( - n_samples_source=20, n_samples_target=20, shift="concept_drift", random_state=42 + n_samples_source=20, n_samples_target=20, shift="conditional_shift", random_state=42 ) Xs, Xt, ys, yt = skada.source_target_split(X, y, sample_domain=sample_domain) @@ -396,3 +392,73 @@ def source_target_comparison( # %% # Results summary # --------------- + +# sphinx_gallery_start_ignore +plt.figure(10, (15, 7.5)) +shift_list = ["covariate_shift", "target_shift", "conditionl_shift", "subspace"] +clfs = { + "covariate_shift": LogisticRegression().set_fit_request(sample_weight=True), + "target_shift": LogisticRegression(), + "conditionl_shift": SVC(), + "subspace": SVC(), +} +shift_acc_before = {} +shift_acc_after = {} + +for indx, shift in enumerate(shift_list): + X, y, sd = make_shifted_datasets(20, 20, shift, random_state=42) + Xs, Xt, ys, yt = skada.source_target_split(X, y, sample_domain=sd) + shift_name = shift.capitalize().replace("_", " ") + + plt.subplot(3, 5, 2 + indx) + plot_full_data(Xt, yt, shift_name) + + base_clf = clfs[shift] + base_clf.fit(Xs, ys) + shift_acc_before[shift_name] = base_clf.score(Xt, yt) + plt.subplot(3, 5, 7 + indx) + plot_full_data(Xt, yt, None, True, base_clf) + + if shift == "covariate_shift": + clf = skada.DensityReweight( + base_estimator=base_clf, weight_estimator=KernelDensity(bandwidth=0.5) + ) + + elif shift == "target_shift": + ... + + elif shift == "conditionl_shift": + ... + + elif shift == "subspace": + clf = skada.TransferSubspaceLearning(base_clf, n_components=1) + + clf.fit(X, y, sample_domain=sd) + shift_acc_after[shift_name] = clf.score(Xt, yt) + plt.subplot(3, 5, 12 + indx) + plot_full_data(Xt, yt, None, True, clf) + +X, y, sd = make_shifted_datasets(20, 20, random_state=42) +Xs, Xt, ys, yt = skada.source_target_split(X, y, sample_domain=sd) +plt.subplot(3, 5, 1) +plot_full_data(Xs, ys, "Source data") +plt.ylabel("Data", fontsize=15) + +clf = SVC() +clf.fit(Xs, ys) +plt.subplot(3, 5, 6) +plot_full_data(Xs, ys, None, True, clf) +plt.ylabel("Before DA", fontsize=15) + +plt.subplot(3, 5, 11) +plot_full_data(Xs, ys, None, True, clf) +plt.ylabel("After DA", fontsize=15) + +plt.suptitle("Summary plot", fontsize=20) +plt.tight_layout() + +print("Accuracy scores before Domain Adaptation:") +print_scores_as_table(shift_acc_before) +print("\nAfter Domain Adaptation:") +print_scores_as_table(shift_acc_after) +# sphinx_gallery_end_ignore From e5722cafdd531de3dcaba6cbcae12a19a41259b5 Mon Sep 17 00:00:00 2001 From: Aruket Date: Fri, 9 May 2025 11:37:34 +0200 Subject: [PATCH 07/16] code-breaking typo fix --- examples/plot_beginners_guide.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/plot_beginners_guide.py b/examples/plot_beginners_guide.py index c392022b..8abbce89 100644 --- a/examples/plot_beginners_guide.py +++ b/examples/plot_beginners_guide.py @@ -395,11 +395,11 @@ def source_target_comparison( # sphinx_gallery_start_ignore plt.figure(10, (15, 7.5)) -shift_list = ["covariate_shift", "target_shift", "conditionl_shift", "subspace"] +shift_list = ["covariate_shift", "target_shift", "conditional_shift", "subspace"] clfs = { "covariate_shift": LogisticRegression().set_fit_request(sample_weight=True), "target_shift": LogisticRegression(), - "conditionl_shift": SVC(), + "conditional_shift": SVC(), "subspace": SVC(), } shift_acc_before = {} @@ -427,7 +427,7 @@ def source_target_comparison( elif shift == "target_shift": ... - elif shift == "conditionl_shift": + elif shift == "conditional_shift": ... elif shift == "subspace": From e8af9d47a9423f059f10d8ed16def1b7fa1acf74 Mon Sep 17 00:00:00 2001 From: Aruket Date: Fri, 9 May 2025 13:57:46 +0200 Subject: [PATCH 08/16] Added projection representation and mapping --- examples/plot_beginners_guide.py | 174 +++++++++++++++++++++++++------ 1 file changed, 144 insertions(+), 30 deletions(-) diff --git a/examples/plot_beginners_guide.py b/examples/plot_beginners_guide.py index 8abbce89..98a4099f 100644 --- a/examples/plot_beginners_guide.py +++ b/examples/plot_beginners_guide.py @@ -29,7 +29,7 @@ # Author: Maxence Barneche # # License: BSD 3-Clause -# sphinx_gallery_thumbnail_number = 6 +# sphinx_gallery_thumbnail_number = 13 # %% # Necessary imports @@ -47,8 +47,6 @@ from skada.datasets import make_shifted_datasets from skada.utils import extract_source_indices -# %% - # sphinx_gallery_start_ignore fig_size = (8, 4) @@ -76,10 +74,13 @@ def decision_borders_plot(X, model): plt.contourf(xx, yy, Z, alpha=0.4, cmap="tab10", vmax=9) -def plot_full_data(X, y, title, prediction=False, model=None, size=25): - plt.scatter( - X[:, 0], X[:, 1], s=size, c=y, cmap="tab10", vmax=9, label="Target", alpha=0.8 - ) +def plot_full_data( + X, y, title, prediction=False, model=None, size=25, second_color=False +): + if not second_color: + plt.scatter(X[:, 0], X[:, 1], s=size, c=y, cmap="tab10", vmax=9, alpha=0.8) + else: + plt.scatter(X[:, 0], X[:, 1], s=size, c=y, alpha=0.8) plt.xticks([]) plt.yticks([]) if prediction: @@ -94,9 +95,13 @@ def source_target_comparison( Xs, Xt, ys, yt = skada.source_target_split(X, y, sample_domain=sample_domain) plt.subplot(1, 2, 1) + plt.xlim(X[:, 0].min() - 1, X[:, 0].max() + 1) + plt.ylim(X[:, 1].min() - 1, X[:, 1].max() + 1) plot_full_data(Xs, ys, "Source data", prediction, model, size) plt.subplot(1, 2, 2) + plt.xlim(X[:, 0].min() - 1, X[:, 0].max() + 1) + plt.ylim(X[:, 1].min() - 1, X[:, 1].max() + 1) plot_full_data(Xt, yt, "Target data", prediction, model) plt.suptitle(title, fontsize=16) @@ -224,6 +229,60 @@ def source_target_comparison( plt.tight_layout() # sphinx_gallery_end_ignore +# %% +# The subspace (projected on the positive diagonal) + +# sphinx_gallery_start_ignore +Xs, Xt, ys, yt = skada.source_target_split(X, y, sample_domain=sample_domain) + +clf = skada.TransferJointMatching(SVC(), n_components=1) +clf.fit(X, y, sample_domain=sample_domain) + +subspace_estimator = clf.steps[-2][1].get_estimator() +Xs_sub = subspace_estimator.transform( + Xs, + # mark all samples as sources + sample_domain=np.ones(Xs.shape[0]), + allow_source=True, +) +Xt_sub = subspace_estimator.transform(Xt) +Xs_sub *= 9 +mean = Xs_sub.mean() +Xs_sub = Xs_sub - mean +Xs_sub = -Xs_sub + mean +Xs_sub = np.c_[Xs_sub, Xs_sub] + +plt.figure(5, fig_size) +plt.subplot(1, 2, 1) +plot_full_data(Xs, ys, "Source data (projected)") +plot_full_data(Xs_sub, ys, None) +for i in range(len(Xs)): + plt.plot( + [Xs[i, 0], Xs_sub[i, 0]], + [Xs[i, 1], Xs_sub[i, 0]], + "-g", + alpha=0.2, + zorder=0, + ) + +plt.subplot(1, 2, 2) +Xt_sub *= 9 +mean = Xt_sub.mean() +Xt_sub = Xt_sub - mean +Xt_sub = -Xt_sub + mean +Xt_sub = np.c_[Xt_sub, Xt_sub] +plot_full_data(Xt, yt, "Target data (projected)") +plot_full_data(Xt_sub, yt, None) +for i in range(len(Xt)): + plt.plot( + [Xt[i, 0], Xt_sub[i, 0]], + [Xt[i, 1], Xt_sub[i, 0]], + "-g", + alpha=0.2, + zorder=0, + ) +# sphinx_gallery_end_ignore + # %% # Adaptation methods # ------------------ @@ -240,7 +299,8 @@ def source_target_comparison( # Source dataset reweighting # ~~~~~~~~~~~~~~~~~~~~~~~~~~ # -# A common method for dealing with covariate shift is reweighting the source data. +# A common method for dealing with covariate and target shift is reweighting +# the source data. # # SKADA handles this with multiple reweighting methods: # @@ -269,7 +329,7 @@ def source_target_comparison( accuracy = base_classifier.score(Xt, yt) # sphinx_gallery_start_ignore -plt.figure(5, fig_size) +plt.figure(6, fig_size) source_target_comparison( X, y, @@ -286,7 +346,7 @@ def source_target_comparison( # The reweighting is done by transforming the source dataset using an instance of # the :code:`Adapter` class provided by SKADA. -# We define the classifier as a da pipeline from the base classifier +# Define the classifier as a domain adaptation (DA) pipeline from the base classifier clf = skada.DensityReweight( base_estimator=base_classifier, weight_estimator=KernelDensity(bandwidth=0.5) ) @@ -304,7 +364,7 @@ def source_target_comparison( # sphinx_gallery_start_ignore weights = 15 * weights -plt.figure(6, fig_size) +plt.figure(7, fig_size) source_target_comparison( X, y, @@ -323,19 +383,63 @@ def source_target_comparison( # Source to target mapping # ~~~~~~~~~~~~~~~~~~~~~~~~ # -# The traditional way of dealing with conditional shift is via mapping. +# The traditional way of dealing with conditional and target shift is via +# mapping the source data to the target data. # +# First, let's look at what happens wen we try to fit an estimator on the target X, y, sample_domain = make_shifted_datasets( n_samples_source=20, n_samples_target=20, shift="conditional_shift", random_state=42 ) - Xs, Xt, ys, yt = skada.source_target_split(X, y, sample_domain=sample_domain) +# setting and fitting the estimator on the source data +base_classifier = SVC() +base_classifier.fit(Xs, ys) + +# accuracy on target data +accuracy = base_classifier.score(Xt, yt) + +# sphinx_gallery_start_ignore +plt.figure(8, fig_size) +source_target_comparison( + X, y, sample_domain, "Prediction without mapping", True, base_classifier +) +plt.tight_layout() +print("Accuracy on target:", accuracy) +# sphinx_gallery_end_ignore + # %% -# -# -# +# Mapping consist of mapping point from the source data to point from the target data +# using optimal transport methods. This is done automatically +# by the :code:`OTMapping` method. + +clf = skada.OTMapping(base_classifier) +clf.fit(X, y, sample_domain=sample_domain) + +# sphinx_gallery_start_ignore +n_tot_source = Xs.shape[0] +n_tot_target = Xt.shape[0] +adapter = clf.named_steps["otmappingadapter"].get_estimator() +T = adapter.ot_transport_.coupling_ +T = T / T.max() + +plt.figure(9) +plot_full_data(Xs, ys, "Mapping source (orange, blue) to target (yellow, purple)") +plot_full_data(Xt, yt, None, second_color=True) +for i in range(n_tot_source): + for j in range(n_tot_target): + if T[i, j] > 0: + plt.plot( + [Xs[i, 0], Xt[j, 0]], + [Xs[i, 1], Xt[j, 1]], + "-g", + alpha=T[i, j] * 0.5, + zorder=0, + ) + +plt.figure(10, fig_size) +source_target_comparison(X, y, sample_domain, "Predictions after mapping", True, clf) # %% # Subspace methods # ~~~~~~~~~~~~~~~~ @@ -368,7 +472,7 @@ def source_target_comparison( accuracy = base_classifier.score(Xt, yt) # sphinx_gallery_start_ignore -plt.figure(9, fig_size) +plt.figure(11, fig_size) source_target_comparison( X, y, sample_domain, "Prediction on dataset", True, base_classifier ) @@ -383,7 +487,7 @@ def source_target_comparison( accuracy = clf.score(Xt, yt) # sphinx_gallery_start_ignore -plt.figure(10, fig_size) +plt.figure(12, fig_size) source_target_comparison(X, y, sample_domain, "Prediction on dataset", True, clf) plt.tight_layout() print("Accuracy on target:", accuracy) @@ -394,11 +498,11 @@ def source_target_comparison( # --------------- # sphinx_gallery_start_ignore -plt.figure(10, (15, 7.5)) +plt.figure(13, (15, 7.5)) shift_list = ["covariate_shift", "target_shift", "conditional_shift", "subspace"] clfs = { "covariate_shift": LogisticRegression().set_fit_request(sample_weight=True), - "target_shift": LogisticRegression(), + "target_shift": LogisticRegression().set_fit_request(sample_weight=True), "conditional_shift": SVC(), "subspace": SVC(), } @@ -410,13 +514,16 @@ def source_target_comparison( Xs, Xt, ys, yt = skada.source_target_split(X, y, sample_domain=sd) shift_name = shift.capitalize().replace("_", " ") - plt.subplot(3, 5, 2 + indx) - plot_full_data(Xt, yt, shift_name) + plt.subplot(4, 5, 2 + indx) + plot_full_data(X, y, shift_name) + + plt.subplot(4, 5, 7 + indx) + plot_full_data(Xt, yt, None) base_clf = clfs[shift] base_clf.fit(Xs, ys) shift_acc_before[shift_name] = base_clf.score(Xt, yt) - plt.subplot(3, 5, 7 + indx) + plt.subplot(4, 5, 12 + indx) plot_full_data(Xt, yt, None, True, base_clf) if shift == "covariate_shift": @@ -425,32 +532,39 @@ def source_target_comparison( ) elif shift == "target_shift": - ... + clf = skada.DensityReweight( + base_clf, weight_estimator=KernelDensity(bandwidth=0.5) + ) elif shift == "conditional_shift": - ... + clf = skada.OTMapping(base_clf) elif shift == "subspace": clf = skada.TransferSubspaceLearning(base_clf, n_components=1) clf.fit(X, y, sample_domain=sd) shift_acc_after[shift_name] = clf.score(Xt, yt) - plt.subplot(3, 5, 12 + indx) + plt.subplot(4, 5, 17 + indx) plot_full_data(Xt, yt, None, True, clf) X, y, sd = make_shifted_datasets(20, 20, random_state=42) Xs, Xt, ys, yt = skada.source_target_split(X, y, sample_domain=sd) -plt.subplot(3, 5, 1) + +plt.subplot(4, 5, 1) +plot_full_data(Xs, ys, "Source data") +plt.ylabel("Full dataset", fontsize=15) + +plt.subplot(4, 5, 6) plot_full_data(Xs, ys, "Source data") -plt.ylabel("Data", fontsize=15) +plt.ylabel("Observed data", fontsize=15) clf = SVC() clf.fit(Xs, ys) -plt.subplot(3, 5, 6) +plt.subplot(4, 5, 11) plot_full_data(Xs, ys, None, True, clf) plt.ylabel("Before DA", fontsize=15) -plt.subplot(3, 5, 11) +plt.subplot(4, 5, 16) plot_full_data(Xs, ys, None, True, clf) plt.ylabel("After DA", fontsize=15) From 0744163656363ee768dc22f94fde08e8c44b94f5 Mon Sep 17 00:00:00 2001 From: Aruket Date: Fri, 9 May 2025 15:03:54 +0200 Subject: [PATCH 09/16] added missing line for sphinx formatting --- examples/plot_beginners_guide.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/plot_beginners_guide.py b/examples/plot_beginners_guide.py index 98a4099f..ee069ce8 100644 --- a/examples/plot_beginners_guide.py +++ b/examples/plot_beginners_guide.py @@ -359,7 +359,7 @@ def source_target_comparison( # then compute the weights corresponding to the source dataset weights = weight_estimator.compute_weights(X, sample_domain=sample_domain)[idx] -# comput the accuracy of the newly obtained model +# compute the accuracy of the newly obtained model accuracy = clf.score(Xt, yt) # sphinx_gallery_start_ignore @@ -440,6 +440,8 @@ def source_target_comparison( plt.figure(10, fig_size) source_target_comparison(X, y, sample_domain, "Predictions after mapping", True, clf) +# sphinx_gallery_end_ignore + # %% # Subspace methods # ~~~~~~~~~~~~~~~~ From ce47e1402adf76423acddfcaf599f992730968e4 Mon Sep 17 00:00:00 2001 From: Aruket Date: Fri, 9 May 2025 16:09:02 +0200 Subject: [PATCH 10/16] fixed shifting of decision boundary plots --- examples/plot_beginners_guide.py | 93 ++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 40 deletions(-) diff --git a/examples/plot_beginners_guide.py b/examples/plot_beginners_guide.py index ee069ce8..0891c3b7 100644 --- a/examples/plot_beginners_guide.py +++ b/examples/plot_beginners_guide.py @@ -15,7 +15,7 @@ * :ref:`Conditional shift` * :ref:`Subspace shift` -* :ref:`Methods` +* :ref:`Methods`: * :ref:`Reweighting` * :ref:`Mapping` * :ref:`Subspace` @@ -74,17 +74,13 @@ def decision_borders_plot(X, model): plt.contourf(xx, yy, Z, alpha=0.4, cmap="tab10", vmax=9) -def plot_full_data( - X, y, title, prediction=False, model=None, size=25, second_color=False -): +def plot_full_data(X, y, title, size=25, second_color=False): if not second_color: plt.scatter(X[:, 0], X[:, 1], s=size, c=y, cmap="tab10", vmax=9, alpha=0.8) else: plt.scatter(X[:, 0], X[:, 1], s=size, c=y, alpha=0.8) plt.xticks([]) plt.yticks([]) - if prediction: - decision_borders_plot(X, model) if title is not None: plt.title(title) @@ -97,12 +93,16 @@ def source_target_comparison( plt.subplot(1, 2, 1) plt.xlim(X[:, 0].min() - 1, X[:, 0].max() + 1) plt.ylim(X[:, 1].min() - 1, X[:, 1].max() + 1) - plot_full_data(Xs, ys, "Source data", prediction, model, size) + plot_full_data(Xs, ys, "Source data", size) + if prediction: + decision_borders_plot(X, model) plt.subplot(1, 2, 2) plt.xlim(X[:, 0].min() - 1, X[:, 0].max() + 1) plt.ylim(X[:, 1].min() - 1, X[:, 1].max() + 1) - plot_full_data(Xt, yt, "Target data", prediction, model) + plot_full_data(Xt, yt, "Target data") + if prediction: + decision_borders_plot(X, model) plt.suptitle(title, fontsize=16) @@ -347,20 +347,20 @@ def source_target_comparison( # the :code:`Adapter` class provided by SKADA. # Define the classifier as a domain adaptation (DA) pipeline from the base classifier -clf = skada.DensityReweight( +adapted_clf = skada.DensityReweight( base_estimator=base_classifier, weight_estimator=KernelDensity(bandwidth=0.5) ) -clf.fit(X, y, sample_domain=sample_domain) +adapted_clf.fit(X, y, sample_domain=sample_domain) # To extract the weights, we take the weight estimator from the pipeline -weight_estimator = clf[0].get_estimator() +weight_estimator = adapted_clf[0].get_estimator() idx = extract_source_indices(sample_domain) # then compute the weights corresponding to the source dataset weights = weight_estimator.compute_weights(X, sample_domain=sample_domain)[idx] # compute the accuracy of the newly obtained model -accuracy = clf.score(Xt, yt) +accuracy = adapted_clf.score(Xt, yt) # sphinx_gallery_start_ignore weights = 15 * weights @@ -371,7 +371,7 @@ def source_target_comparison( sample_domain, "Prediction on reweighted dataset", prediction=True, - model=clf, + model=adapted_clf, size=weights, ) plt.tight_layout() @@ -414,13 +414,14 @@ def source_target_comparison( # using optimal transport methods. This is done automatically # by the :code:`OTMapping` method. -clf = skada.OTMapping(base_classifier) -clf.fit(X, y, sample_domain=sample_domain) +adapted_clf = skada.OTMapping(base_classifier) +adapted_clf.fit(X, y, sample_domain=sample_domain) +accuracy = adapted_clf.fit(Xt, yt) # sphinx_gallery_start_ignore n_tot_source = Xs.shape[0] n_tot_target = Xt.shape[0] -adapter = clf.named_steps["otmappingadapter"].get_estimator() +adapter = adapted_clf.named_steps["otmappingadapter"].get_estimator() T = adapter.ot_transport_.coupling_ T = T / T.max() @@ -439,7 +440,10 @@ def source_target_comparison( ) plt.figure(10, fig_size) -source_target_comparison(X, y, sample_domain, "Predictions after mapping", True, clf) +source_target_comparison( + X, y, sample_domain, "Predictions after mapping", True, adapted_clf +) +print("Accuracy on target:", accuracy) # sphinx_gallery_end_ignore # %% @@ -484,23 +488,27 @@ def source_target_comparison( # %% # Now, we will illustrate what happens when using the Transfer Subspace Learning method -clf = skada.TransferSubspaceLearning(base_classifier, n_components=1) -clf.fit(X, y, sample_domain=sample_domain) -accuracy = clf.score(Xt, yt) +adapted_clf = skada.TransferSubspaceLearning(base_classifier, n_components=1) +adapted_clf.fit(X, y, sample_domain=sample_domain) +accuracy = adapted_clf.score(Xt, yt) # sphinx_gallery_start_ignore plt.figure(12, fig_size) -source_target_comparison(X, y, sample_domain, "Prediction on dataset", True, clf) +source_target_comparison( + X, y, sample_domain, "Prediction on dataset", True, adapted_clf +) plt.tight_layout() -print("Accuracy on target:", accuracy) +print("\nAccuracy on target:", accuracy) # sphinx_gallery_end_ignore # %% # Results summary # --------------- +# +# Here is a summary of the different shifts and the domain adaptation methods used. # sphinx_gallery_start_ignore -plt.figure(13, (15, 7.5)) +plt.figure(13, (17.5, 9)) shift_list = ["covariate_shift", "target_shift", "conditional_shift", "subspace"] clfs = { "covariate_shift": LogisticRegression().set_fit_request(sample_weight=True), @@ -520,34 +528,33 @@ def source_target_comparison( plot_full_data(X, y, shift_name) plt.subplot(4, 5, 7 + indx) + plt.xlim(X[:, 0].min() - 1, X[:, 0].max() + 1) + plt.ylim(X[:, 1].min() - 1, X[:, 1].max() + 1) plot_full_data(Xt, yt, None) base_clf = clfs[shift] base_clf.fit(Xs, ys) shift_acc_before[shift_name] = base_clf.score(Xt, yt) plt.subplot(4, 5, 12 + indx) - plot_full_data(Xt, yt, None, True, base_clf) + plot_full_data(Xt, yt, None) + decision_borders_plot(X, base_clf) - if shift == "covariate_shift": - clf = skada.DensityReweight( + if shift == "covariate_shift" or shift == "target_shift": + adapted_clf = skada.DensityReweight( base_estimator=base_clf, weight_estimator=KernelDensity(bandwidth=0.5) ) - elif shift == "target_shift": - clf = skada.DensityReweight( - base_clf, weight_estimator=KernelDensity(bandwidth=0.5) - ) - elif shift == "conditional_shift": - clf = skada.OTMapping(base_clf) + adapted_clf = skada.OTMapping(base_clf) elif shift == "subspace": - clf = skada.TransferSubspaceLearning(base_clf, n_components=1) + adapted_clf = skada.TransferSubspaceLearning(base_clf, n_components=1) - clf.fit(X, y, sample_domain=sd) - shift_acc_after[shift_name] = clf.score(Xt, yt) + adapted_clf.fit(X, y, sample_domain=sd) + shift_acc_after[shift_name] = adapted_clf.score(Xt, yt) plt.subplot(4, 5, 17 + indx) - plot_full_data(Xt, yt, None, True, clf) + plot_full_data(Xt, yt, None) + decision_borders_plot(X, adapted_clf) X, y, sd = make_shifted_datasets(20, 20, random_state=42) Xs, Xt, ys, yt = skada.source_target_split(X, y, sample_domain=sd) @@ -557,24 +564,30 @@ def source_target_comparison( plt.ylabel("Full dataset", fontsize=15) plt.subplot(4, 5, 6) -plot_full_data(Xs, ys, "Source data") +plot_full_data(Xs, ys, None) plt.ylabel("Observed data", fontsize=15) clf = SVC() clf.fit(Xs, ys) plt.subplot(4, 5, 11) -plot_full_data(Xs, ys, None, True, clf) +plot_full_data(Xs, ys, None) +decision_borders_plot(Xs, clf) plt.ylabel("Before DA", fontsize=15) plt.subplot(4, 5, 16) -plot_full_data(Xs, ys, None, True, clf) +plot_full_data(Xs, ys, None) +decision_borders_plot(Xs, clf) plt.ylabel("After DA", fontsize=15) plt.suptitle("Summary plot", fontsize=20) plt.tight_layout() -print("Accuracy scores before Domain Adaptation:") +print("\nAccuracy scores before Domain Adaptation:") print_scores_as_table(shift_acc_before) print("\nAfter Domain Adaptation:") print_scores_as_table(shift_acc_after) # sphinx_gallery_end_ignore + +# %% +# For information on DA pipelines and the :code:`Adapter` class with SKADA, +# don't hesitate to check out the "How to use SKADA" page and the "Users Guide" page. From 06715efe7a62330a200220e910bd4067990cccc4 Mon Sep 17 00:00:00 2001 From: Aruket Date: Fri, 9 May 2025 16:26:56 +0200 Subject: [PATCH 11/16] fixed error --- examples/plot_beginners_guide.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/plot_beginners_guide.py b/examples/plot_beginners_guide.py index 0891c3b7..c2af07a1 100644 --- a/examples/plot_beginners_guide.py +++ b/examples/plot_beginners_guide.py @@ -416,7 +416,7 @@ def source_target_comparison( adapted_clf = skada.OTMapping(base_classifier) adapted_clf.fit(X, y, sample_domain=sample_domain) -accuracy = adapted_clf.fit(Xt, yt) +accuracy = adapted_clf.score(Xt, yt) # sphinx_gallery_start_ignore n_tot_source = Xs.shape[0] From dff8f158f2815c7eb691f26180847d4c17ffe44c Mon Sep 17 00:00:00 2001 From: Aruket Date: Fri, 9 May 2025 16:57:39 +0200 Subject: [PATCH 12/16] typo fix --- examples/plot_beginners_guide.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/plot_beginners_guide.py b/examples/plot_beginners_guide.py index c2af07a1..e640c147 100644 --- a/examples/plot_beginners_guide.py +++ b/examples/plot_beginners_guide.py @@ -113,11 +113,11 @@ def source_target_comparison( # Creating a shifted dataset # -------------------------- # -# Data shift occurs when there is a change in data distribution. It can come from +# Data shift occurs when there is a change in data distribution. It can come # from a change in the input dataset, the target variable or the latent relations # between the two. # -# This implies that a model trained on an original dataset, (called source) +# This implies that a model trained on an original dataset (called source) # will have a decrease in performance when predicting on the shifted dataset # (called target). # We will see the different methods used to deal with data shift From 3c4edbdbdebcace0a6161d67f78383ad3801c16c Mon Sep 17 00:00:00 2001 From: Aruket Date: Fri, 9 May 2025 18:53:12 +0200 Subject: [PATCH 13/16] updated after remarks --- examples/plot_beginners_guide.py | 185 ++++++++++++++----------------- 1 file changed, 84 insertions(+), 101 deletions(-) diff --git a/examples/plot_beginners_guide.py b/examples/plot_beginners_guide.py index e640c147..11243a24 100644 --- a/examples/plot_beginners_guide.py +++ b/examples/plot_beginners_guide.py @@ -74,15 +74,15 @@ def decision_borders_plot(X, model): plt.contourf(xx, yy, Z, alpha=0.4, cmap="tab10", vmax=9) -def plot_full_data(X, y, title, size=25, second_color=False): - if not second_color: - plt.scatter(X[:, 0], X[:, 1], s=size, c=y, cmap="tab10", vmax=9, alpha=0.8) - else: - plt.scatter(X[:, 0], X[:, 1], s=size, c=y, alpha=0.8) +def plot_full_data(X, y, title=None, size=25, marker="o"): + plt.scatter( + X[:, 0], X[:, 1], s=size, c=y, cmap="tab10", vmax=9, marker=marker, alpha=0.8 + ) plt.xticks([]) plt.yticks([]) if title is not None: - plt.title(title) + plt.title(title, fontsize=16) + plt.gca().set_aspect("equal") def source_target_comparison( @@ -113,14 +113,11 @@ def source_target_comparison( # Creating a shifted dataset # -------------------------- # -# Data shift occurs when there is a change in data distribution. It can come -# from a change in the input dataset, the target variable or the latent relations -# between the two. -# -# This implies that a model trained on an original dataset (called source) -# will have a decrease in performance when predicting on the shifted dataset -# (called target). -# We will see the different methods used to deal with data shift +# Data shift refers to changes in the distribution +# of inputs, targets, or their relationships. +# As a result, a model trained on the source data may perform +# poorly on the shifted target data. +# Methods for handling data shift are discussed # in the :ref:`methods` section. # # DA datasets provided by SKADA are organized as follows: @@ -148,8 +145,7 @@ def source_target_comparison( # # For reproducibility, we will use the seed 42 throughout the guide. # For simplicity, we will use a small (20) number of samples -# in both source and target. Feel free to change these arguments to your liking once -# you have a good understanding of the process. +# in both source and target. # # .. NOTE:: # @@ -229,60 +225,6 @@ def source_target_comparison( plt.tight_layout() # sphinx_gallery_end_ignore -# %% -# The subspace (projected on the positive diagonal) - -# sphinx_gallery_start_ignore -Xs, Xt, ys, yt = skada.source_target_split(X, y, sample_domain=sample_domain) - -clf = skada.TransferJointMatching(SVC(), n_components=1) -clf.fit(X, y, sample_domain=sample_domain) - -subspace_estimator = clf.steps[-2][1].get_estimator() -Xs_sub = subspace_estimator.transform( - Xs, - # mark all samples as sources - sample_domain=np.ones(Xs.shape[0]), - allow_source=True, -) -Xt_sub = subspace_estimator.transform(Xt) -Xs_sub *= 9 -mean = Xs_sub.mean() -Xs_sub = Xs_sub - mean -Xs_sub = -Xs_sub + mean -Xs_sub = np.c_[Xs_sub, Xs_sub] - -plt.figure(5, fig_size) -plt.subplot(1, 2, 1) -plot_full_data(Xs, ys, "Source data (projected)") -plot_full_data(Xs_sub, ys, None) -for i in range(len(Xs)): - plt.plot( - [Xs[i, 0], Xs_sub[i, 0]], - [Xs[i, 1], Xs_sub[i, 0]], - "-g", - alpha=0.2, - zorder=0, - ) - -plt.subplot(1, 2, 2) -Xt_sub *= 9 -mean = Xt_sub.mean() -Xt_sub = Xt_sub - mean -Xt_sub = -Xt_sub + mean -Xt_sub = np.c_[Xt_sub, Xt_sub] -plot_full_data(Xt, yt, "Target data (projected)") -plot_full_data(Xt_sub, yt, None) -for i in range(len(Xt)): - plt.plot( - [Xt[i, 0], Xt_sub[i, 0]], - [Xt[i, 1], Xt_sub[i, 0]], - "-g", - alpha=0.2, - zorder=0, - ) -# sphinx_gallery_end_ignore - # %% # Adaptation methods # ------------------ @@ -426,8 +368,8 @@ def source_target_comparison( T = T / T.max() plt.figure(9) -plot_full_data(Xs, ys, "Mapping source (orange, blue) to target (yellow, purple)") -plot_full_data(Xt, yt, None, second_color=True) +plot_full_data(Xs, ys, "Mapping source (circle) to target (triangle)") +plot_full_data(Xt, yt, marker="v") for i in range(n_tot_source): for j in range(n_tot_target): if T[i, j] > 0: @@ -439,10 +381,13 @@ def source_target_comparison( zorder=0, ) +plt.tight_layout() + plt.figure(10, fig_size) source_target_comparison( X, y, sample_domain, "Predictions after mapping", True, adapted_clf ) +plt.tight_layout() print("Accuracy on target:", accuracy) # sphinx_gallery_end_ignore @@ -493,6 +438,53 @@ def source_target_comparison( accuracy = adapted_clf.score(Xt, yt) # sphinx_gallery_start_ignore +clf = skada.TransferJointMatching(SVC(), n_components=1) +clf.fit(X, y, sample_domain=sample_domain) + +subspace_estimator = clf.steps[-2][1].get_estimator() +Xs_sub = subspace_estimator.transform( + Xs, + # mark all samples as sources + sample_domain=np.ones(Xs.shape[0]), + allow_source=True, +) +Xt_sub = subspace_estimator.transform(Xt) +Xs_sub *= 9 +mean = Xs_sub.mean() +Xs_sub = Xs_sub - mean +Xs_sub = -Xs_sub + mean +Xs_sub = np.c_[Xs_sub, Xs_sub] + +plt.figure(5, fig_size) +plt.subplot(1, 2, 1) +plot_full_data(Xs, ys, "Source data (projected)") +plot_full_data(Xs_sub, ys, None) +for i in range(len(Xs)): + plt.plot( + [Xs[i, 0], Xs_sub[i, 0]], + [Xs[i, 1], Xs_sub[i, 0]], + "-g", + alpha=0.2, + zorder=0, + ) + +plt.subplot(1, 2, 2) +Xt_sub *= 9 +mean = Xt_sub.mean() +Xt_sub = Xt_sub - mean +Xt_sub = -Xt_sub + mean +Xt_sub = np.c_[Xt_sub, Xt_sub] +plot_full_data(Xt, yt, "Target data (projected)") +plot_full_data(Xt_sub, yt, None) +for i in range(len(Xt)): + plt.plot( + [Xt[i, 0], Xt_sub[i, 0]], + [Xt[i, 1], Xt_sub[i, 0]], + "-g", + alpha=0.2, + zorder=0, + ) + plt.figure(12, fig_size) source_target_comparison( X, y, sample_domain, "Prediction on dataset", True, adapted_clf @@ -506,9 +498,8 @@ def source_target_comparison( # --------------- # # Here is a summary of the different shifts and the domain adaptation methods used. - # sphinx_gallery_start_ignore -plt.figure(13, (17.5, 9)) +plt.figure(13, (15, 15)) shift_list = ["covariate_shift", "target_shift", "conditional_shift", "subspace"] clfs = { "covariate_shift": LogisticRegression().set_fit_request(sample_weight=True), @@ -524,19 +515,19 @@ def source_target_comparison( Xs, Xt, ys, yt = skada.source_target_split(X, y, sample_domain=sd) shift_name = shift.capitalize().replace("_", " ") - plt.subplot(4, 5, 2 + indx) - plot_full_data(X, y, shift_name) + plt.subplot(4, 4, 1 + indx) + plot_full_data(Xs, ys, shift_name) - plt.subplot(4, 5, 7 + indx) - plt.xlim(X[:, 0].min() - 1, X[:, 0].max() + 1) - plt.ylim(X[:, 1].min() - 1, X[:, 1].max() + 1) - plot_full_data(Xt, yt, None) + plt.subplot(4, 4, 5 + indx) + plt.xlim(X[:, 0].min() - 2, X[:, 0].max() + 2) + plt.ylim(X[:, 1].min() - 2, X[:, 1].max() + 2) + plot_full_data(Xt, yt) base_clf = clfs[shift] base_clf.fit(Xs, ys) shift_acc_before[shift_name] = base_clf.score(Xt, yt) - plt.subplot(4, 5, 12 + indx) - plot_full_data(Xt, yt, None) + plt.subplot(4, 4, 9 + indx) + plot_full_data(Xt, yt) decision_borders_plot(X, base_clf) if shift == "covariate_shift" or shift == "target_shift": @@ -552,34 +543,26 @@ def source_target_comparison( adapted_clf.fit(X, y, sample_domain=sd) shift_acc_after[shift_name] = adapted_clf.score(Xt, yt) - plt.subplot(4, 5, 17 + indx) - plot_full_data(Xt, yt, None) + plt.subplot(4, 4, 13 + indx) + plot_full_data(Xt, yt) decision_borders_plot(X, adapted_clf) X, y, sd = make_shifted_datasets(20, 20, random_state=42) Xs, Xt, ys, yt = skada.source_target_split(X, y, sample_domain=sd) -plt.subplot(4, 5, 1) -plot_full_data(Xs, ys, "Source data") -plt.ylabel("Full dataset", fontsize=15) +plt.subplot(4, 4, 1) +plt.ylabel("Source data", fontsize=16) -plt.subplot(4, 5, 6) -plot_full_data(Xs, ys, None) -plt.ylabel("Observed data", fontsize=15) +plt.subplot(4, 4, 5) +plt.ylabel("Target data", fontsize=16) -clf = SVC() -clf.fit(Xs, ys) -plt.subplot(4, 5, 11) -plot_full_data(Xs, ys, None) -decision_borders_plot(Xs, clf) -plt.ylabel("Before DA", fontsize=15) +plt.subplot(4, 4, 9) +plt.ylabel("Train before DA", fontsize=16) -plt.subplot(4, 5, 16) -plot_full_data(Xs, ys, None) -decision_borders_plot(Xs, clf) -plt.ylabel("After DA", fontsize=15) +plt.subplot(4, 4, 13) +plt.ylabel("Train after DA", fontsize=16) -plt.suptitle("Summary plot", fontsize=20) +plt.suptitle("Summary plot", fontsize=22) plt.tight_layout() print("\nAccuracy scores before Domain Adaptation:") From c3db304213b5eb265301c7aca50fb5ad7cef4a00 Mon Sep 17 00:00:00 2001 From: Aruket Date: Fri, 9 May 2025 19:01:34 +0200 Subject: [PATCH 14/16] fixed sphinx error --- examples/plot_beginners_guide.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/plot_beginners_guide.py b/examples/plot_beginners_guide.py index 11243a24..f35df7d5 100644 --- a/examples/plot_beginners_guide.py +++ b/examples/plot_beginners_guide.py @@ -498,6 +498,9 @@ def source_target_comparison( # --------------- # # Here is a summary of the different shifts and the domain adaptation methods used. + +# Using everything we have used before + # sphinx_gallery_start_ignore plt.figure(13, (15, 15)) shift_list = ["covariate_shift", "target_shift", "conditional_shift", "subspace"] From e74330e2a588a289fd80d33e8f9957e35e1c0fc7 Mon Sep 17 00:00:00 2001 From: mbarneche Date: Mon, 12 May 2025 17:02:40 +0200 Subject: [PATCH 15/16] updated for better square plots and typo fix --- examples/plot_beginners_guide.py | 122 +++++++++++++++---------------- 1 file changed, 59 insertions(+), 63 deletions(-) diff --git a/examples/plot_beginners_guide.py b/examples/plot_beginners_guide.py index f35df7d5..469edfdf 100644 --- a/examples/plot_beginners_guide.py +++ b/examples/plot_beginners_guide.py @@ -37,9 +37,9 @@ # sphinx_gallery_start_ignore import matplotlib.pyplot as plt import numpy as np -from sklearn.linear_model import LogisticRegression # sphinx_gallery_end_ignore +from sklearn.linear_model import LogisticRegression from sklearn.neighbors import KernelDensity from sklearn.svm import SVC @@ -58,10 +58,10 @@ def print_scores_as_table(scores): print(f"{v*100}{' '*(6-len(str(v*100)))}%") -def decision_borders_plot(X, model): +def decision_borders_plot(model): # Create a meshgrid - x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1 - y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1 + x_min, x_max = -2.5, 4.5 + y_min, y_max = -2.5, 4.5 xx, yy = np.meshgrid( np.linspace(x_min, x_max, num=100), np.linspace(y_min, y_max, num=100) ) @@ -74,7 +74,7 @@ def decision_borders_plot(X, model): plt.contourf(xx, yy, Z, alpha=0.4, cmap="tab10", vmax=9) -def plot_full_data(X, y, title=None, size=25, marker="o"): +def plot_full_data(X, y, title=None, size=25, marker="o", subspace=False): plt.scatter( X[:, 0], X[:, 1], s=size, c=y, cmap="tab10", vmax=9, marker=marker, alpha=0.8 ) @@ -83,28 +83,43 @@ def plot_full_data(X, y, title=None, size=25, marker="o"): if title is not None: plt.title(title, fontsize=16) plt.gca().set_aspect("equal") + maxi = 2.5 if subspace else 4.5 + mini = -2.5 + plt.xlim(mini, maxi) + plt.ylim(mini, maxi) def source_target_comparison( - X, y, sample_domain, title, prediction=False, model=None, size=25 + X, + y, + sample_domain, + title, + prediction=False, + model=None, + size=25, + figsize=(8, 4), + subspace=False, ): Xs, Xt, ys, yt = skada.source_target_split(X, y, sample_domain=sample_domain) - plt.subplot(1, 2, 1) - plt.xlim(X[:, 0].min() - 1, X[:, 0].max() + 1) - plt.ylim(X[:, 1].min() - 1, X[:, 1].max() + 1) - plot_full_data(Xs, ys, "Source data", size) + fig, axes = plt.subplots(1, 2, figsize=figsize) + + plt.sca(axes[0]) + plot_full_data( + Xs, ys, title="Source data", size=size, marker="o", subspace=subspace + ) if prediction: - decision_borders_plot(X, model) + decision_borders_plot(model) - plt.subplot(1, 2, 2) - plt.xlim(X[:, 0].min() - 1, X[:, 0].max() + 1) - plt.ylim(X[:, 1].min() - 1, X[:, 1].max() + 1) - plot_full_data(Xt, yt, "Target data") + plt.sca(axes[1]) + plot_full_data(Xt, yt, title="Target data", marker="v", subspace=subspace) if prediction: - decision_borders_plot(X, model) + decision_borders_plot(model) - plt.suptitle(title, fontsize=16) + fig.suptitle(title, fontsize=16) + fig.tight_layout() + plt.subplots_adjust(top=0.85) + plt.show() # sphinx_gallery_end_ignore @@ -168,9 +183,7 @@ def source_target_comparison( ) # sphinx_gallery_start_ignore -plt.figure(1, fig_size) source_target_comparison(X, y, sample_domain, "Example covariate shift") -plt.tight_layout() # sphinx_gallery_end_ignore # %% @@ -185,9 +198,7 @@ def source_target_comparison( ) # sphinx_gallery_start_ignore -plt.figure(2, fig_size) source_target_comparison(X, y, sample_domain, "Example target shift") -plt.tight_layout() # sphinx_gallery_end_ignore # %% @@ -202,9 +213,7 @@ def source_target_comparison( ) # sphinx_gallery_start_ignore -plt.figure(3, fig_size) source_target_comparison(X, y, sample_domain, "Example conditional shift") -plt.tight_layout() # sphinx_gallery_end_ignore # %% @@ -220,9 +229,7 @@ def source_target_comparison( ) # sphinx_gallery_start_ignore -plt.figure(4, fig_size) -source_target_comparison(X, y, sample_domain, "Example subspace shift") -plt.tight_layout() +source_target_comparison(X, y, sample_domain, "Example subspace shift", subspace=True) # sphinx_gallery_end_ignore # %% @@ -238,8 +245,8 @@ def source_target_comparison( # # For every shift, there is a method to adapt the source data to train the model on. # -# Source dataset reweighting -# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Reweighting methods +# ~~~~~~~~~~~~~~~~~~~ # # A common method for dealing with covariate and target shift is reweighting # the source data. @@ -271,7 +278,6 @@ def source_target_comparison( accuracy = base_classifier.score(Xt, yt) # sphinx_gallery_start_ignore -plt.figure(6, fig_size) source_target_comparison( X, y, @@ -280,7 +286,6 @@ def source_target_comparison( prediction=True, model=base_classifier, ) -plt.tight_layout() print("Accuracy on target:", accuracy) # sphinx_gallery_end_ignore @@ -306,7 +311,6 @@ def source_target_comparison( # sphinx_gallery_start_ignore weights = 15 * weights -plt.figure(7, fig_size) source_target_comparison( X, y, @@ -316,19 +320,18 @@ def source_target_comparison( model=adapted_clf, size=weights, ) -plt.tight_layout() print("Accuracy on target:", accuracy) # sphinx_gallery_end_ignore # %% -# Source to target mapping -# ~~~~~~~~~~~~~~~~~~~~~~~~ +# Mapping methods +# ~~~~~~~~~~~~~~~ # # The traditional way of dealing with conditional and target shift is via # mapping the source data to the target data. # -# First, let's look at what happens wen we try to fit an estimator on the target +# First, let's look at what happens when we try to fit an estimator on the target X, y, sample_domain = make_shifted_datasets( n_samples_source=20, n_samples_target=20, shift="conditional_shift", random_state=42 @@ -343,11 +346,9 @@ def source_target_comparison( accuracy = base_classifier.score(Xt, yt) # sphinx_gallery_start_ignore -plt.figure(8, fig_size) source_target_comparison( X, y, sample_domain, "Prediction without mapping", True, base_classifier ) -plt.tight_layout() print("Accuracy on target:", accuracy) # sphinx_gallery_end_ignore @@ -367,7 +368,7 @@ def source_target_comparison( T = adapter.ot_transport_.coupling_ T = T / T.max() -plt.figure(9) +plt.figure(9, figsize=fig_size) plot_full_data(Xs, ys, "Mapping source (circle) to target (triangle)") plot_full_data(Xt, yt, marker="v") for i in range(n_tot_source): @@ -382,12 +383,11 @@ def source_target_comparison( ) plt.tight_layout() +plt.show() -plt.figure(10, fig_size) source_target_comparison( X, y, sample_domain, "Predictions after mapping", True, adapted_clf ) -plt.tight_layout() print("Accuracy on target:", accuracy) # sphinx_gallery_end_ignore @@ -423,11 +423,9 @@ def source_target_comparison( accuracy = base_classifier.score(Xt, yt) # sphinx_gallery_start_ignore -plt.figure(11, fig_size) source_target_comparison( - X, y, sample_domain, "Prediction on dataset", True, base_classifier + X, y, sample_domain, "Prediction on dataset", True, base_classifier, subspace=True ) -plt.tight_layout() print("Accuracy on target:", accuracy) # sphinx_gallery_end_ignore @@ -455,14 +453,14 @@ def source_target_comparison( Xs_sub = -Xs_sub + mean Xs_sub = np.c_[Xs_sub, Xs_sub] -plt.figure(5, fig_size) +plt.figure(5, figsize=fig_size) plt.subplot(1, 2, 1) -plot_full_data(Xs, ys, "Source data (projected)") -plot_full_data(Xs_sub, ys, None) +plot_full_data(Xs, ys, "Source data (projected)", subspace=True) +plot_full_data(Xs_sub, ys, subspace=True) for i in range(len(Xs)): plt.plot( [Xs[i, 0], Xs_sub[i, 0]], - [Xs[i, 1], Xs_sub[i, 0]], + [Xs[i, 1], Xs_sub[i, 1]], "-g", alpha=0.2, zorder=0, @@ -474,22 +472,21 @@ def source_target_comparison( Xt_sub = Xt_sub - mean Xt_sub = -Xt_sub + mean Xt_sub = np.c_[Xt_sub, Xt_sub] -plot_full_data(Xt, yt, "Target data (projected)") -plot_full_data(Xt_sub, yt, None) +plot_full_data(Xt, yt, "Target data (projected)", marker="v", subspace=True) +plot_full_data(Xt_sub, yt, marker="v", subspace=True) for i in range(len(Xt)): plt.plot( [Xt[i, 0], Xt_sub[i, 0]], - [Xt[i, 1], Xt_sub[i, 0]], + [Xt[i, 1], Xt_sub[i, 1]], "-g", alpha=0.2, zorder=0, ) +plt.show() -plt.figure(12, fig_size) source_target_comparison( - X, y, sample_domain, "Prediction on dataset", True, adapted_clf + X, y, sample_domain, "Prediction on dataset", True, adapted_clf, subspace=True ) -plt.tight_layout() print("\nAccuracy on target:", accuracy) # sphinx_gallery_end_ignore @@ -502,7 +499,7 @@ def source_target_comparison( # Using everything we have used before # sphinx_gallery_start_ignore -plt.figure(13, (15, 15)) +plt.figure(13, (12.5, 12.5)) shift_list = ["covariate_shift", "target_shift", "conditional_shift", "subspace"] clfs = { "covariate_shift": LogisticRegression().set_fit_request(sample_weight=True), @@ -517,21 +514,20 @@ def source_target_comparison( X, y, sd = make_shifted_datasets(20, 20, shift, random_state=42) Xs, Xt, ys, yt = skada.source_target_split(X, y, sample_domain=sd) shift_name = shift.capitalize().replace("_", " ") + subspace = shift == "subspace" plt.subplot(4, 4, 1 + indx) - plot_full_data(Xs, ys, shift_name) + plot_full_data(Xs, ys, shift_name, subspace=subspace) plt.subplot(4, 4, 5 + indx) - plt.xlim(X[:, 0].min() - 2, X[:, 0].max() + 2) - plt.ylim(X[:, 1].min() - 2, X[:, 1].max() + 2) - plot_full_data(Xt, yt) + plot_full_data(Xt, yt, marker="v", subspace=subspace) base_clf = clfs[shift] base_clf.fit(Xs, ys) shift_acc_before[shift_name] = base_clf.score(Xt, yt) plt.subplot(4, 4, 9 + indx) - plot_full_data(Xt, yt) - decision_borders_plot(X, base_clf) + plot_full_data(Xt, yt, marker="v", subspace=subspace) + decision_borders_plot(base_clf) if shift == "covariate_shift" or shift == "target_shift": adapted_clf = skada.DensityReweight( @@ -541,14 +537,14 @@ def source_target_comparison( elif shift == "conditional_shift": adapted_clf = skada.OTMapping(base_clf) - elif shift == "subspace": + elif subspace: adapted_clf = skada.TransferSubspaceLearning(base_clf, n_components=1) adapted_clf.fit(X, y, sample_domain=sd) shift_acc_after[shift_name] = adapted_clf.score(Xt, yt) plt.subplot(4, 4, 13 + indx) - plot_full_data(Xt, yt) - decision_borders_plot(X, adapted_clf) + plot_full_data(Xt, yt, marker="v", subspace=subspace) + decision_borders_plot(adapted_clf) X, y, sd = make_shifted_datasets(20, 20, random_state=42) Xs, Xt, ys, yt = skada.source_target_split(X, y, sample_domain=sd) From 76df9fab7020dce777074b3d38312d73ef91158a Mon Sep 17 00:00:00 2001 From: mbarneche Date: Mon, 12 May 2025 17:06:08 +0200 Subject: [PATCH 16/16] changed reference for sphinx --- examples/plot_beginners_guide.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/plot_beginners_guide.py b/examples/plot_beginners_guide.py index 469edfdf..e68865c3 100644 --- a/examples/plot_beginners_guide.py +++ b/examples/plot_beginners_guide.py @@ -16,8 +16,8 @@ * :ref:`Subspace shift` * :ref:`Methods`: - * :ref:`Reweighting` - * :ref:`Mapping` + * :ref:`Reweighting` + * :ref:`Mapping` * :ref:`Subspace` * :ref:`Summary`