Skip to content
Merged

0.9.6 #745

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
48b6df4
fix: replace en dashes with hyphens in benchmark docs
Irozuku Jun 24, 2026
f919d54
fix: update translation handling for language changes in ModelCompari…
Creylay Jun 25, 2026
784aaf9
docs: add --force-reinstall --no-cache-dir to README pip install comm…
Irozuku Jun 25, 2026
c37ec8a
fix: remove original text columns replaced by emb_* counterparts in E…
Creylay Jun 25, 2026
7a7659c
fix: remove original text columns replaced by tok_* counterparts in T…
Creylay Jun 25, 2026
ac64c23
fix: update Spanish display names for Additive and Skewed Chi² Samplers
Creylay Jun 25, 2026
a787d2d
refactor: extract shared categorical encoder mixin
Irozuku Jun 25, 2026
7beda1d
fix: encode categorical features in MLP regression
Irozuku Jun 25, 2026
4a68536
fix: add MAXIMIZE = True to explained variance metric
Irozuku Jun 25, 2026
1eadfb8
feat: Solve problem with temp_dir in translation
Felipedino Jun 26, 2026
594a87b
fix: clarify Normalizer is row wise in display name and description
Irozuku Jun 26, 2026
95f5694
fix: cap select all to column cardinality limit
Irozuku Jun 26, 2026
4801d55
refactor: replace per-type dtype restrictions with global dtype black…
Irozuku Jun 26, 2026
601e423
feat: show excluded data types in column selector
Irozuku Jun 26, 2026
6866edf
feat: add excluded data types translations
Irozuku Jun 26, 2026
5f96b6f
fix: ship diffusers source and avoid AutoPipeline so frozen exe can r…
Irozuku Jun 26, 2026
21953a1
fix: preserve source resolution in SD1.5 depth ControlNet
Irozuku Jun 26, 2026
af95e20
fix: make optuna CmaEsSampler work and drop incompatible GridSampler
Irozuku Jun 26, 2026
51bc812
fix: match GGUF filename case so llama.cpp models load on Linux
Irozuku Jun 26, 2026
c13a778
fix: allow empty output in VarianceThreshold by handling ValueError d…
Creylay Jun 26, 2026
bb9568b
fix: render AppImage icon from SVG isotype at high resolution
Irozuku Jun 26, 2026
8a782b4
style: center chat title and adjust session info layout
Irozuku Jun 26, 2026
9e43267
fix: add validation for n_components in dimensionality reduction conv…
Creylay Jun 26, 2026
4ebe18b
fix: update n_components warning message to use consistent variable n…
Creylay Jun 26, 2026
c40808c
feat: enhance MissingIndicator converter with missing value normaliza…
Creylay Jun 26, 2026
995ef58
feat: Change colors and style of the modal target column
Felipedino Jun 28, 2026
da23123
fix type in converters
Felipedino Jun 29, 2026
38f61f9
Merge pull request #722 from DashAISoftware/fix/benchmark-dash-punctu…
cristian-tamblay Jun 29, 2026
57bf38b
Merge pull request #723 from DashAISoftware/fix/metric-descriptions-l…
cristian-tamblay Jun 29, 2026
8a93e1b
Merge pull request #725 from DashAISoftware/docs/readme-pip-force-rei…
cristian-tamblay Jun 29, 2026
2b145d4
Merge pull request #726 from DashAISoftware/fix/embedding-tokenizer-c…
cristian-tamblay Jun 29, 2026
594b535
Merge pull request #728 from DashAISoftware/fix/mlp-regression-catego…
cristian-tamblay Jun 29, 2026
690f019
Merge pull request #729 from DashAISoftware/fix/chi2-sampler-spanish-…
cristian-tamblay Jun 29, 2026
e5a3972
Merge pull request #730 from DashAISoftware/fix/explained-variance-ma…
cristian-tamblay Jun 29, 2026
ca0bff1
Merge pull request #731 from DashAISoftware/fix/temp_dir
cristian-tamblay Jun 29, 2026
e6fee4f
Merge pull request #732 from DashAISoftware/fix/normalizer-row-wise-c…
cristian-tamblay Jun 29, 2026
7507498
Merge pull request #734 from DashAISoftware/refactor/non-allowed-dtypes
cristian-tamblay Jun 29, 2026
529d28c
Merge pull request #735 from DashAISoftware/fix/exe-torchscript-source
cristian-tamblay Jun 29, 2026
ff1faae
Merge pull request #736 from DashAISoftware/fix/optuna-samplers
cristian-tamblay Jun 29, 2026
41fa0d6
Merge pull request #737 from DashAISoftware/fix/gguf-filename-case-linux
cristian-tamblay Jun 29, 2026
cabc62c
Merge pull request #738 from DashAISoftware/fix/variance-threshold-al…
cristian-tamblay Jun 29, 2026
6239aef
Merge pull request #739 from DashAISoftware/style/center-chat-title
cristian-tamblay Jun 29, 2026
2963d56
Merge pull request #740 from DashAISoftware/fix/appimage-icon-svg
cristian-tamblay Jun 29, 2026
98cba92
Merge pull request #741 from DashAISoftware/fix/pca-n-components-vali…
cristian-tamblay Jun 29, 2026
0d3fa0f
Merge pull request #742 from DashAISoftware/fix/missing-indicator-con…
cristian-tamblay Jun 29, 2026
af4af9b
Merge pull request #743 from DashAISoftware/fix/modal-target
cristian-tamblay Jun 29, 2026
43fa7bf
Bump to 0.9.6
cristian-tamblay Jun 29, 2026
97eded9
Merge branch 'develop' into feat/fix-type-featureselect
Felipedino Jun 29, 2026
9965e96
Merge pull request #744 from DashAISoftware/feat/fix-type-featureselect
cristian-tamblay Jun 29, 2026
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
9 changes: 6 additions & 3 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ jobs:
python -m pip install --upgrade pip
pip install build python-appimage
sudo apt-get update
sudo apt-get install -y libfuse2 imagemagick
sudo apt-get install -y libfuse2 imagemagick librsvg2-bin
- name: Build wheel (frontend bundled)
run: python -m build --wheel
- name: Verify frontend is included in wheel
Expand All @@ -262,8 +262,11 @@ jobs:
fi
- name: Prepare AppImage recipe
run: |
# Icon referenced by dashai.desktop (Icon=dashai); take the first frame of the .ico
convert installer/dashAI.ico[0] appimage/dashai.png
# Icon referenced by dashai.desktop (Icon=dashai). Rasterize the
# scalable SVG isotype to a large square PNG so desktops have a
# high-resolution icon (the .ico only carried small frames).
rsvg-convert -h 512 DashAI/front/public/dashai-isotype.svg -o /tmp/dashai-isotype.png
convert /tmp/dashai-isotype.png -background none -gravity center -extent 512x512 appimage/dashai.png
# Append the freshly built wheel (with bundled frontend) to the recipe requirements
WHEEL=$(ls "$PWD"/dist/*.whl | head -n1)
echo "$WHEEL" >> appimage/requirements.txt
Expand Down
3 changes: 3 additions & 0 deletions DashAI/back/converters/base_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ def get_metadata(cls) -> Dict[str, Any]:
meta["color"] = cls.COLOR if cls.COLOR else "rgb(255, 255, 255)"
meta["supervised"] = cls.SUPERVISED
meta["changes_row_count"] = cls.CHANGES_ROW_COUNT
meta["n_components_features_bounded"] = getattr(
cls, "N_COMPONENTS_FEATURES_BOUNDED", False
)

# Serialize allowed_types class references → class name strings for the frontend
raw_types = meta.get("allowed_types", [])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ class DimensionalityReductionConverter(BaseConverter):
)
ICON: Final[str] = Icon.Layers.value
COLOR: Final[str] = "rgb(255, 99, 132)"
N_COMPONENTS_FEATURES_BOUNDED: bool = True
64 changes: 63 additions & 1 deletion DashAI/back/converters/category/feature_selection.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
from typing import Final
from typing import TYPE_CHECKING, Final, Union

from DashAI.back.converters.base_converter import BaseConverter
from DashAI.back.core.utils import MultilingualString
from DashAI.back.static.icons import Icon
from DashAI.back.types.dashai_data_type import DashAIDataType

if TYPE_CHECKING:
from DashAI.back.dataloaders.classes.dashai_dataset import DashAIDataset


class FeatureSelectionConverter(BaseConverter):
Expand All @@ -15,6 +19,10 @@ class FeatureSelectionConverter(BaseConverter):

Use these converters to reduce overfitting, speed up training, and improve
model interpretability by retaining only the most informative features.

These converters only drop columns; the retained columns keep their
original values untouched, so their data types must be preserved instead of
being coerced to float.
"""

CATEGORY = MultilingualString(
Expand All @@ -26,3 +34,57 @@ class FeatureSelectionConverter(BaseConverter):
)
ICON: Final[str] = Icon.FilterList.value
COLOR: Final[str] = "rgb(255, 206, 86)"

def fit(
self, x: "DashAIDataset", y: Union["DashAIDataset", None] = None
) -> "FeatureSelectionConverter":
"""Fit the selector while remembering the input column types.

Feature selection only keeps a subset of the input columns without
modifying their values, so the original types are captured here to be
returned later by ``get_output_type``. Types are recorded during ``fit``
(rather than ``transform``) because scikit-learn auto-wraps ``transform``
on subclasses and would coerce its output back to a pandas DataFrame.

Parameters
----------
x : DashAIDataset
The input dataset to fit the selector on.
y : DashAIDataset, optional
Target values for the supervised selectors. Defaults to None.

Returns
-------
FeatureSelectionConverter
The fitted selector instance (self).
"""
if hasattr(x, "types") and x.types is not None:
self._input_types = dict(x.types)
return super().fit(x, y)

def get_output_type(self, column_name: str = None) -> DashAIDataType:
"""Return the original DashAI data type of a retained column.

Since feature selection leaves the retained columns' values unchanged,
the output type matches the input type of that column.

Parameters
----------
column_name : str, optional
The name of the retained column. Defaults to None.

Returns
-------
DashAIDataType
The original type of the column. Falls back to ``float64`` when the
input type is unknown (feature selectors only operate on numbers).
"""
input_types = getattr(self, "_input_types", None)
if input_types is not None and column_name in input_types:
return input_types[column_name]

import pyarrow as pa

from DashAI.back.types.value_types import Float

return Float(arrow_type=pa.float64())
5 changes: 5 additions & 0 deletions DashAI/back/converters/hugging_face/embedding.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,4 +247,9 @@ def _process_batch(self, batch: "DashAIDataset") -> "DashAIDataset":
pa.array(embeddings_np[:, i].tolist(), type=pa.float32()),
)

# Remove original text columns — they are replaced by their emb_* counterparts
for column in batch.column_names:
col_idx = result_table.column_names.index(column)
result_table = result_table.remove_column(col_idx)

return DashAIDataset(result_table)
5 changes: 5 additions & 0 deletions DashAI/back/converters/hugging_face/tokenizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,11 @@ def _process_batch(self, batch: "DashAIDataset") -> "DashAIDataset":
pa.array(input_ids[:, i].tolist(), type=pa.int64()),
)

# Remove original text columns — they are replaced by their tok_* counterparts
for column in batch.column_names:
col_idx = result_table.column_names.index(column)
result_table = result_table.remove_column(col_idx)

return DashAIDataset(result_table)

def get_output_type(self, column_name: Optional[str] = None) -> DashAIDataType:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class AdditiveChi2Sampler(
)
DISPLAY_NAME = MultilingualString(
en="Additive Chi² Sampler",
es="Muestreador Chi²",
es="Muestreador Chi² Aditivo",
pt="Amostrador Qui-2 Aditivo",
de="Additiver Chi²-Stichprobennehmer",
zh="加性卡方采样器",
Expand Down
1 change: 1 addition & 0 deletions DashAI/back/converters/scikit_learn/fast_ica.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ class FastICA(DimensionalityReductionConverter, SklearnWrapper, FastICAOperation
"""

SCHEMA = FastICASchema
N_COMPONENTS_FEATURES_BOUNDED: bool = False
DESCRIPTION = MultilingualString(
en="FastICA: a fast algorithm for Independent Component Analysis.",
es=(
Expand Down
19 changes: 0 additions & 19 deletions DashAI/back/converters/scikit_learn/generic_univariate_select.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
)
from DashAI.back.core.schema_fields.base_schema import BaseSchema
from DashAI.back.core.utils import MultilingualString
from DashAI.back.types.dashai_data_type import DashAIDataType
from DashAI.back.types.value_types import Float, Integer


Expand Down Expand Up @@ -83,21 +82,3 @@ class GenericUnivariateSelect(
)
IMAGE_PREVIEW = "generic_univariate_select.png"
metadata = {"allowed_types": [Float, Integer], "allowed_dtypes": []}

def get_output_type(self, column_name: str = None) -> DashAIDataType:
"""Return the DashAI data type produced by this converter for a column.

Parameters
----------
column_name : str, optional
Not used; all output columns share the
same type. Defaults to None.

Returns
-------
DashAIDataType
A Float type backed by ``pyarrow.float64()``.
"""
import pyarrow as pa

return Float(arrow_type=pa.float64())
122 changes: 122 additions & 0 deletions DashAI/back/converters/scikit_learn/missing_indicator.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import TYPE_CHECKING, Union

from sklearn.impute import MissingIndicator as MissingIndicatorOperation

from DashAI.back.converters.category.basic_preprocessing import (
Expand All @@ -9,6 +11,11 @@
from DashAI.back.types.dashai_data_type import DashAIDataType
from DashAI.back.types.value_types import Integer

if TYPE_CHECKING:
import pandas as pd

from DashAI.back.dataloaders.classes.dashai_dataset import DashAIDataset


class MissingIndicatorSchema(BaseSchema):
"""Schema for configuring the MissingIndicator converter.
Expand Down Expand Up @@ -75,7 +82,122 @@ def __init__(self, **kwargs):
Configuration keyword arguments matching the converter's
schema fields. Forwarded to the underlying scikit-learn class.
"""
# Force indicators for all selected features so the user always sees the
# new column, even when a feature has no missing values (all-False indicator).
kwargs.setdefault("features", "all")
super().__init__(**kwargs)
# SklearnWrapper.__init__ sets set_output(transform="pandas"), which causes
# sklearn's __init_subclass__ wrapper to intercept our custom transform and
# attempt to rename its output using get_feature_names_out() (which returns
# only the indicator column count, not the combined output count).
# Reset to "default" so the wrapper returns our DashAIDataset as-is.
if hasattr(self, "set_output"):
self.set_output(transform="default")

@staticmethod
def _normalize_missing(frame: "pd.DataFrame") -> "pd.DataFrame":
"""Return a copy of *frame* where object-column missing values are float NaN.

HuggingFace/PyArrow stores missing strings as ``None`` (Python), but
sklearn's ``_get_mask`` uses ``x != x`` which is ``False`` for ``None``
(only ``float('nan') != float('nan')`` is ``True``). We also treat
empty strings as missing to match the dataset-filter behaviour.
"""
import numpy as np

frame = frame.copy()
for col in frame.select_dtypes(include="object").columns:
frame[col] = frame[col].replace("", np.nan)
frame[col] = frame[col].where(frame[col].notna(), np.nan)
return frame

def fit(
self, x: "DashAIDataset", y: Union["DashAIDataset", None] = None
) -> "MissingIndicator":
"""Fit after normalising missing values so sklearn detects them."""
from DashAI.back.dataloaders.classes.dashai_dataset import to_dashai_dataset

x_pandas = x.to_pandas() if hasattr(x, "to_pandas") else x
x_clean_ds = to_dashai_dataset(self._normalize_missing(x_pandas))
if hasattr(x, "types"):
x_clean_ds.types = x.types.copy()
return super().fit(x_clean_ds, y)

def transform(
self, x: "DashAIDataset", y: Union["DashAIDataset", None] = None
) -> "DashAIDataset":
"""Transform x by appending missing-value indicator columns.

Keeps the original columns intact and appends one boolean indicator
column per feature that had missing values during fit. Indicator
columns are named ``missingindicator_<original_col_name>`` so that
``_rebuild_dataset_with_transformed_columns`` treats them as *new*
columns rather than replacements, preserving the original data.
"""
import numpy as np
import pandas as pd

from DashAI.back.dataloaders.classes.dashai_dataset import to_dashai_dataset

x_pandas = x.to_pandas() if hasattr(x, "to_pandas") else x

# Normalise missing values before sklearn sees the data (None and ""
# are both treated as missing, matching dataset-filter behaviour).
x_for_sklearn = self._normalize_missing(x_pandas)

sklearn_cls = next(
(
cls
for cls in type(self).__mro__
if "sklearn" in cls.__module__
and "DashAI" not in cls.__module__
and "transform" in cls.__dict__
),
None,
)
if sklearn_cls is None:
raise RuntimeError(
"No sklearn class with a 'transform' method found in the MRO."
)

indicators = sklearn_cls.__dict__["transform"](self, x_for_sklearn)

# features_ contains the column indices for which indicators are produced.
# With features='all' (default), this always equals all input column indices.
if hasattr(self, "features_") and len(self.features_) > 0:
indicator_col_names = [
f"missingindicator_{x_pandas.columns[i]}" for i in self.features_
]
else:
indicator_col_names = [
f"missingindicator_{col}" for col in x_pandas.columns
]

if isinstance(indicators, np.ndarray):
indicators_df = pd.DataFrame(
indicators,
columns=indicator_col_names,
index=x_pandas.index,
)
else:
indicators_df = indicators.copy()
indicators_df.columns = indicator_col_names

combined_df = pd.concat([x_pandas, indicators_df], axis=1)
converted_dataset = to_dashai_dataset(combined_df)

output_type = self.get_output_type()
for col in indicator_col_names:
if col in converted_dataset.column_names:
converted_dataset.types[col] = output_type

# Preserve original column types from the input dataset
if hasattr(x, "types"):
for col in x_pandas.columns:
if col in x.types and col in converted_dataset.column_names:
converted_dataset.types[col] = x.types[col]

return converted_dataset

def get_output_type(self, column_name: str = None) -> DashAIDataType:
"""Return the DashAI data type produced by this converter for a column.
Expand Down
38 changes: 28 additions & 10 deletions DashAI/back/converters/scikit_learn/normalizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,36 @@ class Normalizer(ScalingAndNormalizationConverter, SklearnWrapper, NormalizerOpe

SCHEMA = NormalizerSchema
DESCRIPTION = MultilingualString(
en="Normalize samples individually to unit norm.",
es="Normaliza muestras individualmente a norma unitaria.",
pt="Normaliza amostras individualmente para norma unitária.",
de="Stichproben individuell auf Einheitsnorm normalisieren.",
zh="将每个样本单独归一化为单位范数。",
en=(
"Normalize each row (sample) to unit norm across the selected columns. "
"Select two or more columns; a single column collapses to plus or minus 1."
),
es=(
"Normaliza cada fila (muestra) a norma unitaria a lo largo de las columnas "
"seleccionadas. Selecciona dos o más columnas; una sola columna colapsa a "
"más o menos 1."
),
pt=(
"Normaliza cada linha (amostra) para norma unitária ao longo das colunas "
"selecionadas. Selecione duas ou mais colunas; uma única coluna colapsa "
"para mais ou menos 1."
),
de=(
"Normalisiert jede Zeile (Stichprobe) über die ausgewählten Spalten auf "
"Einheitsnorm. Mindestens zwei Spalten auswählen; eine einzelne Spalte "
"kollabiert zu plus oder minus 1."
),
zh=(
"在所选列上将每一行(样本)归一化为单位范数。"
"请选择两列或以上;单列会收敛为正负 1。"
),
)
DISPLAY_NAME = MultilingualString(
en="Normalizer",
es="Normalizador",
pt="Normalizador",
de="Normalisierer",
zh="归一化器",
en="Row Wise Normalizer",
es="Normalizador por filas",
pt="Normalizador por linhas",
de="Zeilenweiser Normalisierer",
zh="按行归一化器",
)
IMAGE_PREVIEW = "normalizer.png"

Expand Down
1 change: 1 addition & 0 deletions DashAI/back/converters/scikit_learn/nystroem.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ class Nystroem(DimensionalityReductionConverter, SklearnWrapper, NystroemOperati
"""

SCHEMA = NystroemSchema
N_COMPONENTS_FEATURES_BOUNDED: bool = False
DESCRIPTION = MultilingualString(
en=(
"Approximate a kernel map using a subset of the training data. "
Expand Down
Loading
Loading