FITRON: adaptive fuzzy-tree MCDM decision engine for generic tabular binary problems
Project description
FITRON
FITRON is a Python package for hybrid decision intelligence under uncertainty.
Current release: 1.0.0
The package combines:
- fuzzy feature transformation,
- decision tree learning,
- TOPSIS multi-criteria ranking,
- memory-guided adaptive weight updates,
- interpretable ranking outputs.
Package name on PyPI: fitron
Import path: fitron
What FITRON Supports
FITRON is designed for generic tabular decision problems where the target is binary and the feature space contains a mix of numeric and categorical variables.
It is a good fit when:
- the target can be encoded as 0/1, yes/no, true/false, approved/rejected, or another binary pair,
- the data contains structured rows with feature columns that can be normalized, encoded, and ranked,
- the goal is not only prediction, but also interpretable candidate ranking.
It is not a fit for:
- multi-class targets without adaptation,
- unstructured text or image-only problems,
- tasks where row-level ranking is not meaningful.
Why FITRON
Most pipelines stop at classification. FITRON extends that flow into adaptive decision ranking.
- Learns a predictive backbone with a decision tree.
- Ranks valid candidates with TOPSIS and learned criteria weights.
- Adapts weights over iterations using memory and exploration.
- Produces feature-level explanations for selected options.
Core Workflow
- Preprocess tabular data and encode features.
- Fuzzify numeric features into low/mid/high memberships.
- Train decision tree model and estimate feature importances.
- Filter valid candidates using model predictions.
- Rank candidates with TOPSIS.
- Update weights using adaptive exploration and memory feedback.
- Return best option, score, and explanation.
Installation
End users
pip install fitron
From source
pip install .
Editable install (development)
pip install -e .[dev]
Environment Setup
Use a standard CPython virtual environment.
Windows:
python -m venv .venv-win
.\.venv-win\Scripts\python.exe -m pip install -U pip setuptools wheel
.\.venv-win\Scripts\python.exe -m pip install -e .[dev]
If PowerShell blocks script activation, use:
.venv-win\Scripts\activate.bat
Linux or macOS:
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -U pip setuptools wheel
python -m pip install -e .[dev]
More detailed setup for Linux/macOS:
- Confirm Python 3.10+ is available:
python3 --version
- If
venvis missing on Linux, install it first (example for Debian/Ubuntu):
sudo apt update
sudo apt install -y python3-venv
- Create and activate the virtual environment:
python3 -m venv .venv
source .venv/bin/activate
- Upgrade packaging tools and install FITRON in editable mode:
python -m pip install -U pip setuptools wheel
python -m pip install -e .[dev]
- Verify installation:
python -c "from fitron import FITRONModel; print('ok')"
pytest -q
Notes:
- On some macOS setups,
python3may be installed via Homebrew and located under/opt/homebrew/bin/python3(Apple Silicon) or/usr/local/bin/python3(Intel). - Use
deactivatewhen you are done working in the virtual environment.
Quick Start
Here's a complete working example with sufficient data to train the model effectively:
import pandas as pd
from fitron import FITRONModel
# Create sample data with sufficient rows for training
sample = pd.DataFrame(
{
"income": [50000, 20000, 75000, 43000, 60000, 47000, 71000, 25000, 55000, 38000, 65000, 30000],
"risk": [0.2, 0.8, 0.3, 0.5, 0.4, 0.6, 0.25, 0.9, 0.35, 0.7, 0.2, 0.75],
"credit_score": [710, 520, 760, 640, 700, 650, 750, 500, 720, 580, 740, 550],
"employment_years": [5, 1, 10, 3, 7, 4, 9, 1, 6, 2, 8, 2],
"target": [1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0],
}
)
# Initialize and fit the model
model = FITRONModel(iterations=5, random_state=42)
result = model.fit(sample, target="target")
# Access results
print("Best candidate index:", result.best_index)
print("Best score:", result.best_score)
print("Test accuracy:", result.test_accuracy)
print("\nExplanation for best candidate:")
for explanation in result.explanation:
print(" -", explanation)
Output:
Best candidate index: 4
Best score: 0.87
Test accuracy: 0.83
Explanation for best candidate:
- credit_score: 0.7341 (importance: 0.3872)
- income: 0.6523 (importance: 0.2914)
- employment_years: 0.5890 (importance: 0.1632)
- risk: 0.4241 (importance: 0.1582)
Using String Targets
FITRON automatically handles string labels through explicit mapping:
data = pd.DataFrame(
{
"feature_a": [10, 20, 30, 40, 50, 60, 70, 80],
"feature_b": [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8],
"decision": ["reject", "approve", "approve", "reject", "approve", "approve", "reject", "approve"],
}
)
from fitron import fit
result = fit(
data,
target="decision",
target_map={"reject": 0, "approve": 1},
iterations=10,
)
print("Best index:", result.best_index)
print("Explanation:", result.explanation)
API Reference
Core Classes
FITRONModel
Main class for building and iterating over decision-ranking workflows. Maintains memory and weights across multiple iterations.
Constructor Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
iterations |
int |
20 | Number of iterations to run during fit(). Each iteration refines weights and finds better candidates. |
random_state |
int |
42 | Random seed for reproducibility. Affects train/test splits, fuzzy profile fitting, and decision tree training. |
decision_threshold |
float |
0.5 | Probability threshold for binary classification. Candidates above this are preferred. |
objective_classification_weight |
float |
0.65 | Weight balancing classification quality (0.65) vs ranking quality (0.35) in the objective score. Range: [0, 1]. |
confidence_floor |
float |
0.55 | Minimum confidence score for a candidate to be selected. If no candidate meets this, falls back to highest probability. |
Methods:
fit(df, target, ...)
Train the model on data and perform multi-iteration optimization.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
df |
pd.DataFrame |
Required | Input data containing features and target column. Must have at least 5 rows for reliable results. |
target |
str |
Required | Name of the binary target column. Values can be numeric (0/1) or strings (mapped via target_map). |
iterations |
int |
20 | Override the constructor's iteration count (optional). |
drop_columns |
list[str] | None |
None | Feature columns to exclude from processing. Useful for removing IDs, timestamps, etc. |
criterion_types |
list[str] | None |
None | MCDM criterion type for each feature: "benefit" (higher is better) or "cost" (lower is better). If None, all treated as benefits. |
expected_feature_columns |
list[str] | None |
None | Explicit list of feature columns to use. If None, all columns except target are used. |
target_map |
dict[str, int] | None |
None | Mapping for non-numeric target values. Example: {"reject": 0, "approve": 1}. |
metrics_output_path |
str | None |
None | Path to save iteration metrics as CSV. If provided, creates iteration_metrics.csv with scores and accuracies. |
Returns: IterationResult object containing predictions, rankings, best candidate, and explanations.
Example:
result = model.fit(
df=loan_data,
target="approved",
iterations=20,
target_map={"denied": 0, "approved": 1},
metrics_output_path="./metrics.csv",
)
rank(df, target, ...)
Rank candidates using previously fitted weights and memory without retraining from scratch.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
df |
pd.DataFrame |
Required | Input data to rank. Must have same features as training data. |
target |
str |
Required | Name of the binary target column. |
drop_columns |
list[str] | None |
None | Columns to exclude. |
criterion_types |
list[str] | None |
None | MCDM criterion types for each feature. |
expected_feature_columns |
list[str] | None |
None | Explicit feature columns to use. |
target_map |
dict[str, int] | None |
None | Mapping for non-numeric target values. |
tune_hyperparameters |
bool |
False | If True, retunes decision tree hyperparameters (slower, more accurate). |
Returns: IterationResult object.
Example:
# After fit(), use same model to rank new data
new_candidates = pd.DataFrame({...})
rank_result = model.rank(
df=new_candidates,
target="approved",
target_map={"denied": 0, "approved": 1},
)
print("Ranked order:", rank_result.candidate_indices)
print("Best choice index:", rank_result.best_index)
API Functions
fit(df, target, ...)
Convenience function wrapper around FITRONModel.fit(). Creates a model internally.
Parameters: Same as FITRONModel.fit() plus:
| Parameter | Type | Default | Description |
|---|---|---|---|
random_state |
int |
42 | Random seed. |
decision_threshold |
float |
0.5 | Classification threshold. |
objective_classification_weight |
float |
0.65 | Classification weight in objective. |
confidence_floor |
float |
0.55 | Minimum confidence for selection. |
Returns: IterationResult
Example:
from fitron import fit
result = fit(
df=data,
target="approved",
iterations=10,
target_map={"no": 0, "yes": 1},
)
rank(df, target, weights=None, memory=None, ...)
Convenience function to rank candidates without creating a model instance.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
df |
pd.DataFrame |
Required | Candidates to rank. |
target |
str |
Required | Binary target column name. |
weights |
np.ndarray | None |
None | Feature weights from a previous fit. If None, weights are initialized from feature importances. |
memory |
Memory | None |
None | Memory object from a previous fit to blend learned patterns. |
drop_columns |
list[str] | None |
None | Columns to exclude. |
criterion_types |
list[str] | None |
None | MCDM criterion types. |
expected_feature_columns |
list[str] | None |
None | Explicit features to use. |
tune_hyperparameters |
bool |
False | Retune decision tree hyperparameters. |
target_map |
dict[str, int] | None |
None | Target value mapping. |
Returns: IterationResult
Example:
from fitron import rank
result = rank(
df=candidates,
target="approved",
weights=previous_weights,
memory=previous_memory,
target_map={"rejected": 0, "approved": 1},
)
explain(result)
Extract explanation strings from an IterationResult.
Parameters:
| Parameter | Type | Description |
|---|---|---|
result |
IterationResult |
Result object from fit() or rank(). |
Returns: list[str] - Feature explanations in importance order.
Example:
from fitron import explain
explanations = explain(result)
print("Top features explaining the selection:")
for exp in explanations:
print(f" • {exp}")
update_memory(memory, weights, score, best_idx)
Manually update a memory object with new weights and scores.
Parameters:
| Parameter | Type | Description |
|---|---|---|
memory |
Memory |
Memory object to update. |
weights |
np.ndarray |
Feature weights to store. |
score |
float |
Objective score achieved. |
best_idx |
int |
Index of the best candidate selected. |
Returns: None (modifies memory in place)
Example:
from fitron import update_memory, Memory
import numpy as np
memory = Memory()
weights = np.array([0.2, 0.3, 0.25, 0.25])
update_memory(memory, weights, score=0.85, best_idx=5)
Data Classes
IterationResult
Dataclass containing all outputs from a single fit() or rank() call.
| Attribute | Type | Description |
|---|---|---|
predictions |
np.ndarray |
Binary predictions (0 or 1) for each row in test set. |
scores |
np.ndarray |
Final ranking scores for candidate rows. Higher = better. |
candidate_indices |
list[int] |
Indices of rows selected as valid candidates. |
best_index |
int |
Index of the highest-scoring candidate (best choice). |
best_score |
float |
Final ranking score of the best candidate. |
objective_score |
float |
Composite objective score across all iterations. |
weights |
np.ndarray |
Final optimized feature weights used for ranking. |
train_accuracy |
float |
Accuracy of decision tree on training set. |
test_accuracy |
float |
Accuracy of decision tree on test set. |
classification_quality |
float |
Quality metric for classification (0 to 1). |
ranking_quality |
float |
Quality metric for ranking (0 to 1). |
threshold_balanced_accuracy |
float |
Balanced accuracy at decision threshold. |
threshold_f1 |
float |
F1 score at decision threshold. |
fallback_triggered |
bool |
True if fallback to highest probability was used (confidence below floor). |
model |
object |
Underlying decision tree model (sklearn DecisionTreeClassifier). |
explanation |
list[str] |
Top-N feature explanations for best candidate. |
Example:
result = model.fit(data, target="approved")
print(f"Best candidate: {result.best_index}")
print(f"Score: {result.best_score:.4f}")
print(f"Test accuracy: {result.test_accuracy:.4f}")
print(f"Fallback used: {result.fallback_triggered}")
print(f"Ranking scores: {result.scores}")
Memory
Dataclass for tracking optimization history and best weights across iterations.
| Attribute | Type | Description |
|---|---|---|
history |
list[dict] |
Log of all updates. Each entry contains: weights, score, improvement, ema_improvement, best_idx. |
best_weights |
np.ndarray | None |
Feature weights that achieved the best score. |
best_score |
float |
The highest objective score achieved. |
max_history |
int |
Maximum entries to keep in history (default: 200). Older entries are removed. |
ema_improvement |
float |
Exponential moving average of score improvements. |
Methods:
update(weights, score, best_idx)
Record new weights and score in memory.
Parameters:
| Parameter | Type | Description |
|---|---|---|
weights |
np.ndarray |
Feature weights to store. |
score |
float |
Objective score. |
best_idx |
int |
Index of selected candidate. |
Example:
from fitron import Memory
memory = Memory()
memory.update(weights=np.array([0.25, 0.35, 0.2, 0.2]), score=0.82, best_idx=3)
# Later, retrieve best weights
best_w = memory.get_best()
print(f"Best weights: {best_w}")
print(f"Best score: {memory.best_score}")
get_best()
Retrieve the feature weights that achieved the best score.
Returns: np.ndarray | None - Best weights or None if memory is empty.
Common Workflows
Workflow 1: Single-Pass Ranking
Train once and get the best candidate:
from fitron import FITRONModel
model = FITRONModel(iterations=10, random_state=42)
result = model.fit(data, target="decision")
print(f"Best candidate index: {result.best_index}")
print(f"Score: {result.best_score}")
Workflow 2: Multi-Pass Refinement with Memory
Reuse weights and memory across multiple ranking calls:
from fitron import FITRONModel
model = FITRONModel(iterations=5, random_state=42)
# First fit on training data
result1 = model.fit(train_data, target="decision")
# Access learned memory and weights
memory = model.memory
weights = result1.weights
# Apply to new candidates using same learned patterns
result2 = model.rank(new_candidates, target="decision")
print(f"Iteration 1 best: {result1.best_index}")
print(f"Iteration 2 best: {result2.best_index}")
print(f"Memory history entries: {len(memory.history)}")
Workflow 3: Using Explicit Weights with Criteria
Define which features are benefits vs. costs:
from fitron import fit
result = fit(
df=data,
target="approved",
iterations=15,
target_map={"rejected": 0, "approved": 1},
criterion_types=["benefit", "cost", "benefit", "benefit"], # cost = lower is better
drop_columns=["applicant_id", "timestamp"],
)
print(f"Best index: {result.best_index}")
print(f"Scores: {result.scores}")
Workflow 4: Saving Iteration Metrics
Track model performance across all iterations:
from fitron import FITRONModel
model = FITRONModel(iterations=20)
result = model.fit(
df=data,
target="decision",
metrics_output_path="./iteration_metrics.csv",
)
# CSV will contain: iteration, objective_score, top_candidate_score,
# best_option_index, train_accuracy, test_accuracy,
# threshold_balanced_accuracy, threshold_f1
Read and analyze metrics:
import pandas as pd
metrics = pd.read_csv("./iteration_metrics.csv")
print(metrics[["iteration", "objective_score", "test_accuracy"]])
# Plot convergence
import matplotlib.pyplot as plt
plt.plot(metrics["iteration"], metrics["objective_score"])
plt.xlabel("Iteration")
plt.ylabel("Objective Score")
plt.show()
Parameter Tuning Guide
iterations
- Low (5-10): Fast experimentation, suitable for small datasets or demos.
- Medium (20-30): Balanced; good for most production use cases.
- High (50+): Slower but may find better solutions; risk of overfitting to noisy data.
objective_classification_weight
- 0.5: Equal weight to classification and ranking quality.
- 0.65 (default): Emphasizes classification accuracy; prefer high-quality predictions.
- 0.8+: Strong emphasis on correct classification; ranking quality is secondary.
decision_threshold
- 0.3-0.4: Lenient; accepts more candidates, may include borderline cases.
- 0.5 (default): Standard probability threshold for binary classification.
- 0.7-0.9: Strict; only high-confidence candidates are considered.
confidence_floor
- 0.4-0.5: Lenient fallback; will select candidates even with low ranking scores.
- 0.55-0.7: Moderate; requires decent confidence; may trigger fallback on ambiguous data.
- 0.8+: Strict; high standards; fallback will be used frequently.
Troubleshooting
Issue: Poor test accuracy or high fallback rate
Causes: Insufficient data, target leakage, poor feature quality.
Solutions:
- Increase dataset size to at least 20-30 rows.
- Review features for relevance to target.
- Lower
confidence_floorto reduce fallback triggers. - Increase
iterationsto refine weights.
Issue: Inconsistent results across runs
Cause: Non-deterministic behavior due to random sampling.
Solution: Set random_state consistently:
model = FITRONModel(iterations=10, random_state=42)
Issue: Memory or weights not improving
Cause: Model is converging or data is too noisy.
Solutions:
- Check
memory.ema_improvementto see if learning has stalled. - Review
criterion_typesto ensure they match business logic. - Inspect data quality for outliers or mislabeling.
Run Tests
pytest -q
Release notes and version history are tracked in CHANGELOG.md.
Authors
- zibransheikh
- hazlived
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fitron-1.0.1.tar.gz.
File metadata
- Download URL: fitron-1.0.1.tar.gz
- Upload date:
- Size: 25.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0faeee14b32678504562bc0e965c283ea3fab00c90483551f29de4443cbb4d10
|
|
| MD5 |
a5761b917918ce3fcb7c58dbd2259daa
|
|
| BLAKE2b-256 |
9cc5e13a059c0bb2fd30643fef30547c5b6ee02e9a00531cf44cfce3b38eb20a
|
Provenance
The following attestation bundles were made for fitron-1.0.1.tar.gz:
Publisher:
publish.yml on hazlived/fitron
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fitron-1.0.1.tar.gz -
Subject digest:
0faeee14b32678504562bc0e965c283ea3fab00c90483551f29de4443cbb4d10 - Sigstore transparency entry: 1340702785
- Sigstore integration time:
-
Permalink:
hazlived/fitron@7171ec94b9cbf55d708f3f3485d30a5b2112cb92 -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/hazlived
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7171ec94b9cbf55d708f3f3485d30a5b2112cb92 -
Trigger Event:
release
-
Statement type:
File details
Details for the file fitron-1.0.1-py3-none-any.whl.
File metadata
- Download URL: fitron-1.0.1-py3-none-any.whl
- Upload date:
- Size: 21.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e92afcad7c54a27680cd99184b290f0c79e243d29d0148a33a0c7726ed168c3e
|
|
| MD5 |
ddc536816547d1e0760b7c0da33ee456
|
|
| BLAKE2b-256 |
cd4703c6195d600cc3ceb7dd2a98d7101ccc03cc731055ef4774e0b9925bc055
|
Provenance
The following attestation bundles were made for fitron-1.0.1-py3-none-any.whl:
Publisher:
publish.yml on hazlived/fitron
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fitron-1.0.1-py3-none-any.whl -
Subject digest:
e92afcad7c54a27680cd99184b290f0c79e243d29d0148a33a0c7726ed168c3e - Sigstore transparency entry: 1340702789
- Sigstore integration time:
-
Permalink:
hazlived/fitron@7171ec94b9cbf55d708f3f3485d30a5b2112cb92 -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/hazlived
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7171ec94b9cbf55d708f3f3485d30a5b2112cb92 -
Trigger Event:
release
-
Statement type: