|
Table of Contents
|
What fuzzy logic is actually good for
Fuzzy logic is most useful when a system must act on vague, linguistic, or uncertain conditions rather than on a single sharp threshold. Instead of forcing reality into crude binary rules such as “fast/slow” or “safe/unsafe,” fuzzy logic allows graded reasoning such as “speed is moderately high” or “uncertainty is low but rising.” In Python, scikit-fuzzy provides a control-system API with constructs such as antecedents, consequents, rules, control systems, and simulations for building such rule-based decision layers.
══════════════════════════
That makes fuzzy logic especially valuable in:
supervisory control,
rule-based decision support,
interpretable model selection,
safety and fallback logic,
systems where expert knowledge matters.
Fuzzy logic is not a universal substitute for machine learning. It is strongest when the problem has a small or medium number of meaningful variables and when human-readable rules are desirable.
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
Python is enough; fuzzy logic does not need MATLAB
In Python, fuzzy inference can be implemented directly with scikit-fuzzy, while machine-learning models can be trained with general frameworks such as TensorFlow and PyTorch. TensorFlow is positioned as an end-to-end platform for creating ML models across desktop, mobile, web, and cloud, while PyTorch provides production-ready distributed training and a broad ecosystem for research and deployment. That means Python can host both the learned models and the fuzzy supervisory layer in one stack.
The correct way to think about this is simple:
TensorFlow / PyTorch train the data-driven models.
Fuzzy logic decides how to use them under changing conditions.
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
Where fuzzy logic fits in modern AI systems
A good modern use of fuzzy logic is not “replace deep learning with fuzzy rules.” A better use is to place fuzzy logic above trained models as a supervisory layer.
For example, suppose you train several models for the same domain:
one optimized for speed,
one for accuracy,
one for noisy inputs,
one for low-power or edge deployment.
A fuzzy controller can then choose among them using inputs such as:
latency requirement,
confidence score,
input quality,
compute budget,
risk tolerance,
environmental instability.
This gives a practical and interpretable adaptive system. But it must be designed carefully. Dynamic model switching has real costs: switching overhead, calibration mismatch, unstable oscillation between models, and maintenance burden from keeping many models healthy.
So fuzzy logic is useful here, but only when the control variables are clear and the switching policy is worth the complexity.
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
Forecasting: fuzzy logic can help, but it is not magic
Fuzzy logic has real forecasting use cases, especially in evolving fuzzy systems and neuro-fuzzy systems. A 2024 systematic review found a substantial literature on evolving fuzzy inference systems for forecasting in non-stationary and dynamic settings, including many different structures and application fields. A 2025 open-access study on Baltic Dry Index forecasting used ANFIS and reported better RMSE than a feed-forward neural network and traditional AR/ARMA baselines in that study.
But the correct conclusion is not “fuzzy always beats ML.” The real conclusion is narrower:
fuzzy methods can be useful when the data are non-stationary,
when expert priors matter,
when interpretability matters,
or when a hybrid neuro-fuzzy design captures useful structure.
For many high-dimensional forecasting tasks, plain deep learning, transformers, state-space models, or probabilistic methods may still be better. Fuzzy logic is a tool, not a universal winner.
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
Brain-inspired methods: where fuzzy logic can and cannot fit
Spiking neural networks (SNNs) are one of the most practical brain-inspired methods now being studied for robotics and temporal data. A robotics survey highlights SNN-based control applications and emphasizes speed, energy efficiency, and computation capability as motivations. A 2024 time-series paper reports SNN forecasting results that are comparable to or better than classic ANN baselines on its benchmarks with lower energy use.
So yes, brain-inspired methods usable today can be combined with fuzzy logic.
Good combinations
Fuzzy logic can sit on top of a brain-inspired model as:
a task selector,
a safety governor,
a resource-aware policy switcher,
an interpretable arbitration layer,
or a high-level context manager.
Example:
an SNN handles perception and temporal dynamics,
a fuzzy layer decides whether the robot should prioritize speed, precision, stability, or caution.
That is a sensible hybrid.
Bad combinations
Fuzzy logic should not be forced to act as the entire brain-like substrate for:
rich perception,
large-scale memory formation,
end-to-end sequence learning,
or high-dimensional continuous control by itself.
In those cases, the fuzzy layer becomes brittle or explodes in rule count.
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
Neuro-fuzzy systems are legitimate, but they have limits
Hybrid systems that combine neural networks and fuzzy inference are real and still active. Recent work such as DCNFIS explicitly combines deep learning with fuzzy inference and argues that such architectures can improve transparency while maintaining competitive accuracy. That makes neuro-fuzzy systems a valid design option when explainability matters.
But they are not automatically superior to standard deep learning. Their value is greatest when:
the problem has interpretable intermediate concepts,
rule transparency is useful,
and the dimensionality is still manageable.
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
What to build in practice
A solid Python architecture looks like this:
Layer 1: specialized models
Train several models for distinct operating regimes.
Layer 2: monitoring signals
Continuously compute:
latency,
confidence,
drift,
sensor quality,
uncertainty,
resource load.
Layer 3: fuzzy supervisor
Use fuzzy rules to choose:
which model to run,
whether to fall back,
whether to slow down,
whether to request more evidence.
Layer 4: feedback
Track outcomes and update either:
fuzzy membership functions,
fuzzy rules,
or the underlying models.
This is a realistic adaptive system. It is not a brain emulator. It is an engineering architecture.
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
Final conclusion
Fuzzy logic remains useful in Python, especially as an interpretable supervisory layer for adaptive systems. It is relevant to control, forecasting, and hybrid AI. It can also be combined with brain-inspired methods such as SNNs and modular cognitive systems. But it should be used where it is strong: handling vagueness, expert rules, safety logic, and transparent decision layers. It should not be inflated into a universal theory of intelligence or sold as a direct path to real-time whole-brain emulation.
Practical synthesis of WBE and Fuzzy Logic
brain-inspired core for perception, memory, temporal dynamics;
fuzzy supervisory layer for interpretable context-dependent control.
That combination is reasonable.
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
Practical method: MLP regression + fuzzy supervisor for model selection
For a house-price style MLP, the target is a scalar regression output. For your case, replace “house price” with gold-price value, gold-price change, or gold signal score. In Python, Keras provides the standard training workflow, including fit(), callbacks such as EarlyStopping and ModelCheckpoint, and model saving in the recommended .keras format. For the fuzzy layer, scikit-fuzzy provides the standard control-system objects: Antecedent, Consequent, Rule, ControlSystem, and ControlSystemSimulation. For a forecasting problem, you should use time-ordered validation, not random splitting; scikit-learn’s TimeSeriesSplit exists specifically because ordinary shuffled splits leak future information into the past.
Right Architecture for this use case
Do not begin with “one big fuzzy system that directly predicts gold price.” That is usually the wrong design.
Use a two-layer design:
Model bank
Train several regression MLPs with:
different feature subsets,
different hidden-layer sizes,
different dropout/L2 settings,
different random initializations.
Fuzzy supervisor
At prediction time, fuzzy logic decides either:
which model to trust most, or
what weight to give each model.
For astrological forecasting program, the second option is usually better: fuzzy-weighted ensemble is better than hard winner-take-all selection, because financial and astrological regimes drift and a single “best” model often changes abruptly. The fuzzy layer is then a supervisory decision system, exactly the kind of problem the skfuzzy.control API is meant for.
Simple Practical Explanation
Simple way to improve forecasting:
Instead of trusting one neural net, train many MLP models with different architectures, feature groups, and starting random weights. Then use fuzzy logic to judge which model is more reliable under current conditions. Fuzzy logic can look at recent error, direction accuracy, and stability, then give each model a weight. Final forecast is a weighted combination of all models. This is more realistic than trusting one model forever, especially in changing markets like gold.
Do not trust only one neural network.
Train several small MLP models on the same forecasting problem:
same target,
but different architectures,
different starting random weights,
and sometimes different parameter groups.
Then do not choose one model forever.
Instead, for each new forecast, use a fuzzy logic supervisor that asks simple questions such as:
Which model has been more accurate recently?
Which model is more stable?
Which model is getting the direction right more often?
Which model is suitable for the current market condition?
Then fuzzy logic gives more weight to better models and less weight to weaker models.
So the final forecast is not:
“Use model 3 only”
but rather:
“Use 50% of model 3, 30% of model 1, and 20% of model 5”
This is useful for gold forecasting because market behavior changes. A single model may work well in one period and badly in another. TensorFlow/Keras is enough for training the models, and scikit-fuzzy is enough for the fuzzy decision layer. For forecasting, the validation must be time-ordered; TimeSeriesSplit exists for exactly that reason.
The practical programming method
Train many MLPs → measure recent quality of each model → use fuzzy logic to assign weights → combine them into one final forecast.
Step 1: decide the target
For gold forecasting, use one of these:
next gold price
next gold change
next gold return
next gold signal score
For your first program, keep it simple:
input row at date t
target = gold value at t+1
Step 2: arrange features in groups
For your astrological program, do not mix everything blindly at first.
Make blocks such as:
astro_core = main astrological parameters
transit = transit-related parameters
cycle = tithi/nakshatra/monthly cycle type parameters
market = previous gold values, momentum, volatility, etc.
Then different models can use different combinations.
Example:
Model A uses astro_core
Model B uses astro_core + transit
Model C uses astro_core + cycle
Model D uses astro_core + transit + market
This is better than one giant messy model.
Step 3: train several MLPs
Use different:
hidden-layer sizes
dropout values
seeds / initial random weights
This is standard Keras work with Sequential, fit(), EarlyStopping, and model saving. A plain stack of layers is exactly what Sequential is for.
Example set:
small = [64, 32]
medium = [128, 64, 32]
deep = [256, 128, 64, 32]
And for each architecture, train with seeds:
11
22
33
That already gives many different models.
Step 4: validate correctly
For house-price toy demos, people often use random train/test split.
For forecasting, that is wrong.
Use time-ordered splits only. TimeSeriesSplit is meant for time-ordered data because ordinary cross-validation can train on future data and evaluate on past data.
So:
train on old data
validate on later data
repeat over several folds
Step 5: measure each model
For every model, store:
rmse = average magnitude error
dir_acc = how often direction was correct
stability = how much performance changes across folds
These three are enough for your first fuzzy system.
Step 6: fuzzy logic gives model weight
The fuzzy system will read:
error = low / medium / high
direction accuracy = weak / fair / strong
stability = unstable / moderate / stable
Output:
model weight = very low / low / medium / high / very high
Example rules:
If error is low and direction is strong and stability is stable → weight very high
If error is high → weight very low
If direction is weak even when error is medium → weight low
If error is medium but direction is strong and stability is stable → weight medium to high
This is exactly the kind of rule-based decision system that scikit-fuzzy supports with Antecedent, Consequent, Rule, ControlSystem, and ControlSystemSimulation.
Step 7: final forecast
Let each trained model predict the next value.
Then fuzzy logic gives a weight to each model.
final forecast = [ ∑(weighti × predictioni) ] / ∑(weighti)
So the final answer is a weighted combination, not blind trust in one model.
Actual starter code
At the end of this page is a usable starter program CODE-1.
It is not your final production system, but it is the correct starting structure.
It assumes a CSV file like this:
Date
gold_next ← target column
many feature columns such as:
astro_1, astro_2, …
transit_1, transit_2, …
cycle_1, cycle_2, …
market_1, market_2, …
How you adapt CODE-1 to your astrological forecasting program
This is the only part you really need to change first.
A. Replace feature names
Instead of:
"astro_1", "astro_2", …
use your real columns, for example:
FEATURE_GROUPS = {
"astro_core": [
"d1_strength",
"d9_strength",
"d60_strength",
"yoga_score",
"bhava_strength"
],
"transit": [
"gochara_score",
"dasha_score"
],
"cycle": [
"tithi_score",
"nakshatra_score",
"paksha_score"
],
"market": [
"gold_prev_1",
"gold_prev_5",
"volatility_10",
"momentum_10"
]
}
B. Decide target carefully
If your target is too noisy, create one of these instead:
next gold value
next gold difference
next gold percent change
next gold direction only
For first testing, simplest is:
gold_next
C. Add your own fuzzy rules
If you care more about direction than exact magnitude, then make fuzzy rules stricter on direction.
Example:
low error + weak direction = only medium weight
medium error + strong direction + stable = high weight
That will suit financial or astrological signal systems better.
The simplest possible mental picture
Think of this like 5 astrologers:
each astrologer uses a slightly different method
each astrologer also has good and bad periods
fuzzy logic is the chairman who says:
“Today astrologer 2 is more reliable, astrologer 5 is also useful, astrologer 1 should be given less importance.”
That is all.
What not to do
Do not do these mistakes:
do not use only one model
do not use random data shuffle for time forecasting
do not feed 50 fuzzy inputs into one fuzzy system
do not make fuzzy logic predict gold directly at first
do not use hard winner-take-all model selection first
Use fuzzy weights, not hard switching, in the first version.
TimeSeriesSplit is specifically meant for time-ordered data, and Keras already gives the standard training/evaluation/saving workflow you need for this style of experiment.
import os
import json
import math
import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow import keras
from sklearn.model_selection import TimeSeriesSplit
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error
import skfuzzy as fuzz
from skfuzzy import control as ctrl
- -----—
- 1. USER SETTINGS
- -----—
CSV_FILE = "gold_data.csv"
DATE_COL = "Date"
TARGET_COL = "gold_next"
N_SPLITS = 5
EPOCHS = 100
BATCH_SIZE = 32
MODEL_DIR = "saved_models"
os.makedirs(MODEL_DIR, exist_ok=True)
- Feature groups for your astrology/gold system
FEATURE_GROUPS = {
"astro_core": ["astro_1", "astro_2", "astro_3", "astro_4"],
"transit": ["transit_1", "transit_2"],
"cycle": ["cycle_1", "cycle_2"],
"market": ["market_1", "market_2", "market_3"]
}
- Each model uses some feature groups + architecture + random seed
MODEL_SPECS = [
{"name": "M1", "groups": ["astro_core"], "layers": [64, 32], "dropout": 0.10, "seed": 11},
{"name": "M2", "groups": ["astro_core", "transit"], "layers": [64, 32], "dropout": 0.10, "seed": 22},
{"name": "M3", "groups": ["astro_core", "cycle"], "layers": [128, 64, 32], "dropout": 0.10, "seed": 33},
{"name": "M4", "groups": ["astro_core", "market"], "layers": [128, 64, 32], "dropout": 0.15, "seed": 44},
{"name": "M5", "groups": ["astro_core", "transit", "market"], "layers": [128, 64, 32], "dropout": 0.15, "seed": 55},
{"name": "M6", "groups": ["astro_core", "transit", "cycle", "market"], "layers": [256, 128, 64, 32], "dropout": 0.20, "seed": 66},
]
- -----—
- 2. FUZZY SYSTEM
- -----—
def build_fuzzy_system():
# error: 0 best, 1 worst
error = ctrl.Antecedent(np.arange(0, 1.01, 0.01), 'error')
direction = ctrl.Antecedent(np.arange(0, 1.01, 0.01), 'direction')
stability = ctrl.Antecedent(np.arange(0, 1.01, 0.01), 'stability')
weight = ctrl.Consequent(np.arange(0, 101, 1), 'weight')
error['low'] = fuzz.trimf(error.universe, [0.0, 0.0, 0.4])
error['medium'] = fuzz.trimf(error.universe, [0.2, 0.5, 0.8])
error['high'] = fuzz.trimf(error.universe, [0.6, 1.0, 1.0])
direction['weak'] = fuzz.trimf(direction.universe, [0.0, 0.0, 0.5])
direction['fair'] = fuzz.trimf(direction.universe, [0.3, 0.5, 0.7])
direction['strong'] = fuzz.trimf(direction.universe, [0.5, 1.0, 1.0])
stability['unstable'] = fuzz.trimf(stability.universe, [0.0, 0.0, 0.5])
stability['moderate'] = fuzz.trimf(stability.universe, [0.3, 0.5, 0.7])
stability['stable'] = fuzz.trimf(stability.universe, [0.5, 1.0, 1.0])
weight['very_low'] = fuzz.trimf(weight.universe, [0, 0, 20])
weight['low'] = fuzz.trimf(weight.universe, [10, 25, 40])
weight['medium'] = fuzz.trimf(weight.universe, [35, 50, 65])
weight['high'] = fuzz.trimf(weight.universe, [60, 75, 90])
weight['very_high'] = fuzz.trimf(weight.universe, [80, 100, 100])
rules = [
ctrl.Rule(error['low'] & direction['strong'] & stability['stable'], weight['very_high']),
ctrl.Rule(error['low'] & direction['fair'] & stability['stable'], weight['high']),
ctrl.Rule(error['medium'] & direction['strong'] & stability['stable'], weight['high']),
ctrl.Rule(error['medium'] & direction['strong'] & stability['moderate'], weight['medium']),
ctrl.Rule(error['medium'] & direction['fair'] & stability['stable'], weight['medium']),
ctrl.Rule(error['high'], weight['very_low']),
ctrl.Rule(direction['weak'], weight['low']),
ctrl.Rule(stability['unstable'] & error['medium'], weight['low']),
ctrl.Rule(stability['unstable'] & direction['weak'], weight['very_low']),
]
system = ctrl.ControlSystem(rules)
return system
FUZZY_SYSTEM = build_fuzzy_system()
def fuzzy_weight(err_norm, dir_acc, stability_score):
sim = ctrl.ControlSystemSimulation(FUZZY_SYSTEM)
sim.input['error'] = float(err_norm)
sim.input['direction'] = float(dir_acc)
sim.input['stability'] = float(stability_score)
sim.compute()
return float(sim.output['weight'])
- -----—
- 3. DATA HELPERS
- -----—
def load_data():
df = pd.read_csv(CSV_FILE)
df = df.sort_values(DATE_COL).reset_index(drop=True)
return df
def get_feature_list(groups):
cols = []
for g in groups:
cols.extend(FEATURE_GROUPS[g])
return cols
def direction_accuracy(y_true, y_pred):
# Here direction means whether predicted change sign matches true sign
# If target is absolute next value instead of change, convert outside this function.
y_true_sign = np.sign(y_true)
y_pred_sign = np.sign(y_pred)
return np.mean(y_true_sign == y_pred_sign)
- -----—
- 4. MODEL BUILDING
- -----—
def build_mlp(input_dim, layers, dropout, seed):
tf.keras.utils.set_random_seed(seed)
model = keras.Sequential()
model.add(keras.layers.Input(shape=(input_dim,)))
for units in layers:
model.add(keras.layers.Dense(units, activation='relu'))
if dropout > 0:
model.add(keras.layers.Dropout(dropout))
model.add(keras.layers.Dense(1, activation='linear'))
model.compile(
optimizer=keras.optimizers.Adam(learning_rate=0.001),
loss='mse',
metrics=[keras.metrics.RootMeanSquaredError(name='rmse')]
)
return model
- -----—
- 5. CROSS-VALIDATION EVALUATION
- -----—
def evaluate_model_spec(df, spec):
features = get_feature_list(spec["groups"])
X = df[features].values.astype(np.float32)
y = df[TARGET_COL].values.astype(np.float32)
tscv = TimeSeriesSplit(n_splits=N_SPLITS)
fold_rmses = []
fold_diraccs = []
for fold_no, (train_idx, test_idx) in enumerate(tscv.split(X), start=1):
X_train, X_test = X[train_idx], X[test_idx]
y_train, y_test = y[train_idx], y[test_idx]
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
model = build_mlp(
input_dim=X_train.shape[1],
layers=spec["layers"],
dropout=spec["dropout"],
seed=spec["seed"]
)
callbacks = [
keras.callbacks.EarlyStopping(
monitor='val_loss',
patience=10,
restore_best_weights=True
)
]
model.fit(
X_train, y_train,
validation_data=(X_test, y_test),
epochs=EPOCHS,
batch_size=BATCH_SIZE,
verbose=0,
callbacks=callbacks
)
pred = model.predict(X_test, verbose=0).reshape(-1)
rmse = math.sqrt(mean_squared_error(y_test, pred))
diracc = direction_accuracy(y_test, pred)
fold_rmses.append(rmse)
fold_diraccs.append(diracc)
avg_rmse = float(np.mean(fold_rmses))
avg_diracc = float(np.mean(fold_diraccs))
# Higher stability means less variation across folds
rmse_std = float(np.std(fold_rmses))
stability_score = 1.0 / (1.0 + rmse_std) # simple stable score in (0,1]
return {
"name": spec["name"],
"groups": spec["groups"],
"layers": spec["layers"],
"dropout": spec["dropout"],
"seed": spec["seed"],
"avg_rmse": avg_rmse,
"avg_diracc": avg_diracc,
"rmse_std": rmse_std,
"stability_score_raw": stability_score
}
- -----—
- 6. NORMALIZE METRICS FOR FUZZY INPUT
- -----—
def normalize_summaries(summaries):
rmses = np.array([s["avg_rmse"] for s in summaries], dtype=np.float32)
stabs = np.array([s["stability_score_raw"] for s in summaries], dtype=np.float32)
rmse_min, rmse_max = float(rmses.min()), float(rmses.max())
stab_min, stab_max = float(stabs.min()), float(stabs.max())
for s in summaries:
if rmse_max > rmse_min:
err_norm = (s["avg_rmse"] - rmse_min) / (rmse_max - rmse_min)
else:
err_norm = 0.0
if stab_max > stab_min:
stability_norm = (s["stability_score_raw"] - stab_min) / (stab_max - stab_min)
else:
stability_norm = 1.0
s["err_norm"] = float(err_norm)
s["stability_norm"] = float(stability_norm)
return summaries
- -----—
- 7. TRAIN FINAL MODELS ON ALL DATA
- -----—
def train_final_model(df, spec):
features = get_feature_list(spec["groups"])
X = df[features].values.astype(np.float32)
y = df[TARGET_COL].values.astype(np.float32)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
model = build_mlp(
input_dim=X_scaled.shape[1],
layers=spec["layers"],
dropout=spec["dropout"],
seed=spec["seed"]
)
callbacks = [
keras.callbacks.EarlyStopping(
monitor='loss',
patience=10,
restore_best_weights=True
)
]
model.fit(
X_scaled, y,
epochs=EPOCHS,
batch_size=BATCH_SIZE,
verbose=0,
callbacks=callbacks
)
model_path = os.path.join(MODEL_DIR, f"{spec['name']}.keras")
model.save(model_path)
return model, scaler, model_path
- -----—
- 8. MAIN TRAINING PIPELINE
- -----—
def train_all():
df = load_data()
summaries = []
for spec in MODEL_SPECS:
print(f"Evaluating {spec['name']} …")
summary = evaluate_model_spec(df, spec)
summaries.append(summary)
summaries = normalize_summaries(summaries)
# Compute fuzzy weights from historical summary metrics
for s in summaries:
s["fuzzy_weight"] = fuzzy_weight(
err_norm=s["err_norm"],
dir_acc=s["avg_diracc"],
stability_score=s["stability_norm"]
)
print("\nModel summaries:")
for s in summaries:
print(json.dumps(s, indent=2))
trained = {}
for spec in MODEL_SPECS:
print(f"Training final model {spec['name']} on all past data …")
model, scaler, model_path = train_final_model(df, spec)
trained[spec["name"]] = {
"model": model,
"scaler": scaler,
"path": model_path
}
with open("model_summaries.json", "w", encoding="utf-8") as f:
json.dump(summaries, f, indent=2)
return summaries, trained
- -----—
- 9. FINAL ENSEMBLE PREDICTION
- -----—
def predict_one(df_current_row, summaries, trained):
preds = []
weights = []
for s in summaries:
name = s["name"]
spec = next(x for x in MODEL_SPECS if x["name"] == name)
features = get_feature_list(spec["groups"])
x = df_current_row[features].values.astype(np.float32).reshape(1, -1)
scaler = trained[name]["scaler"]
model = trained[name]["model"]
x_scaled = scaler.transform(x)
pred = float(model.predict(x_scaled, verbose=0)[0, 0])
preds.append(pred)
weights.append(max(s["fuzzy_weight"], 0.0001))
preds = np.array(preds, dtype=np.float32)
weights = np.array(weights, dtype=np.float32)
final_pred = float(np.sum(preds * weights) / np.sum(weights))
return final_pred, preds, weights
- -----—
- 10. RUN
- -----—
if name == "main":
df = load_data()
summaries, trained = train_all()
# Example: use the latest available row to forecast next target
current_row = df.iloc[-1]
final_pred, preds, weights = predict_one(current_row, summaries, trained)
print("\nIndividual predictions:")
for i, s in enumerate(summaries):
print(f"{s['name']}: pred={preds[i]:.6f}, fuzzy_weight={weights[i]:.3f}")
print(f"\nFinal weighted prediction = {final_pred:.6f}")
Minimum Real Code : tiny house-price demo
This demo shows only one idea:
train 3 MLP models
compare them
use fuzzy logic to give each model a weight
final answer = weighted average of all 3 predictions
After you understand this, the same method can be used in your gold / astrological program.
Simple idea
Suppose 3 different models are predicting house price:
Model A = small model
Model B = medium model
Model C = deep model
After training, some models are:
more accurate
more stable
more trustworthy
So instead of blindly using only one model, we use fuzzy logic:
if model error is low and stability is high → give high weight
if model error is high → give low weight
Then final price:
Final Price= (wApA+wBpB+wCpC) / (wA+wB+wC)
Install packages
pip install tensorflow pandas numpy scikit-learn scikit-fuzzy
CSV file format
reate a file named house_prices.csv. Example (You can add many more rows later.):
size_sqft,bedrooms,age_years,price
1200,2,10,210000
1500,3,8,260000
1800,3,5,310000
2200,4,12,340000
900,2,20,150000
1400,3,15,230000
1700,3,7,295000
2500,4,6,420000
1100,2,18,175000
2000,4,9,360000
1300,3,14,220000
1600,3,10,275000
1900,4,8,325000
2100,4,4,390000
1000,2,25,140000
1550,3,11,250000
1750,3,9,300000
2300,4,7,410000
1250,2,16,205000
1450,3,13,240000
Full tiny Python program
import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow import keras
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error
import skfuzzy as fuzz
from skfuzzy import control as ctrl
- ---------—
- 1. LOAD DATA
- ---------—
df = pd.read_csv("house_prices.csv")
X = df[["size_sqft", "bedrooms", "age_years"]].values.astype(np.float32)
y = df["price"].values.astype(np.float32)
- Simple train/test split for house-price demo
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25, random_state=42
)
- Scale input features
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
- ---------—
- 2. BUILD MLP MODELS
- ---------—
def build_model(input_dim, layers, seed):
tf.keras.utils.set_random_seed(seed)
model = keras.Sequential()
model.add(keras.layers.Input(shape=(input_dim,)))
for units in layers:
model.add(keras.layers.Dense(units, activation="relu"))
model.add(keras.layers.Dense(1, activation="linear"))
model.compile(
optimizer=keras.optimizers.Adam(learning_rate=0.01),
loss="mse"
)
return model
model_specs = [
{"name": "A", "layers": [16], "seed": 11},
{"name": "B", "layers": [32, 16], "seed": 22},
{"name": "C", "layers": [64, 32, 16], "seed": 33},
]
- ---------—
- 3. TRAIN MODELS AND MEASURE ERROR
- ---------—
results = []
for spec in model_specs:
model = build_model(X_train.shape[1], spec["layers"], spec["seed"])
early_stop = keras.callbacks.EarlyStopping(
monitor="val_loss",
patience=20,
restore_best_weights=True
)
history = model.fit(
X_train, y_train,
validation_split=0.2,
epochs=300,
batch_size=4,
verbose=0,
callbacks=[early_stop]
)
pred = model.predict(X_test, verbose=0).reshape(-1)
rmse = np.sqrt(mean_squared_error(y_test, pred))
# stability = how much validation loss moved around near the end
val_losses = history.history["val_loss"]
if len(val_losses) >= 10:
stability_raw = np.std(val_losses[-10:])
else:
stability_raw = np.std(val_losses)
results.append({
"name": spec["name"],
"model": model,
"rmse": float(rmse),
"stability_raw": float(stability_raw)
})
- ---------—
- 4. NORMALIZE METRICS
- error_norm: 0 = best, 1 = worst
- stability_norm: 0 = bad, 1 = good
- ---------—
rmses = np.array([r["rmse"] for r in results], dtype=np.float32)
stabs = np.array([r["stability_raw"] for r in results], dtype=np.float32)
rmse_min, rmse_max = rmses.min(), rmses.max()
stab_min, stab_max = stabs.min(), stabs.max()
for r in results:
if rmse_max > rmse_min:
r["error_norm"] = float((r["rmse"] - rmse_min) / (rmse_max - rmse_min))
else:
r["error_norm"] = 0.0
# lower raw stability std means better stability
if stab_max > stab_min:
badness = (r["stability_raw"] - stab_min) / (stab_max - stab_min)
r["stability_norm"] = float(1.0 - badness)
else:
r["stability_norm"] = 1.0
- ---------—
- 5. FUZZY LOGIC SYSTEM
- Inputs:
- error_norm : 0 best, 1 worst
- stability_norm : 0 bad, 1 good
- Output:
- weight : 0 to 100
- ---------—
error = ctrl.Antecedent(np.arange(0, 1.01, 0.01), "error")
stability = ctrl.Antecedent(np.arange(0, 1.01, 0.01), "stability")
weight = ctrl.Consequent(np.arange(0, 101, 1), "weight")
error["low"] = fuzz.trimf(error.universe, [0.0, 0.0, 0.4])
error["medium"] = fuzz.trimf(error.universe, [0.2, 0.5, 0.8])
error["high"] = fuzz.trimf(error.universe, [0.6, 1.0, 1.0])
stability["low"] = fuzz.trimf(stability.universe, [0.0, 0.0, 0.4])
stability["medium"] = fuzz.trimf(stability.universe, [0.2, 0.5, 0.8])
stability["high"] = fuzz.trimf(stability.universe, [0.6, 1.0, 1.0])
weight["very_low"] = fuzz.trimf(weight.universe, [0, 0, 20])
weight["low"] = fuzz.trimf(weight.universe, [10, 25, 40])
weight["medium"] = fuzz.trimf(weight.universe, [35, 50, 65])
weight["high"] = fuzz.trimf(weight.universe, [60, 75, 90])
weight["very_high"] = fuzz.trimf(weight.universe, [80, 100, 100])
rules = [
ctrl.Rule(error["low"] & stability["high"], weight["very_high"]),
ctrl.Rule(error["low"] & stability["medium"], weight["high"]),
ctrl.Rule(error["medium"] & stability["high"], weight["high"]),
ctrl.Rule(error["medium"] & stability["medium"], weight["medium"]),
ctrl.Rule(error["medium"] & stability["low"], weight["low"]),
ctrl.Rule(error["high"], weight["very_low"]),
]
fuzzy_system = ctrl.ControlSystem(rules)
def get_fuzzy_weight(error_value, stability_value):
sim = ctrl.ControlSystemSimulation(fuzzy_system)
sim.input["error"] = error_value
sim.input["stability"] = stability_value
sim.compute()
return float(sim.output["weight"])
for r in results:
r["fuzzy_weight"] = get_fuzzy_weight(r["error_norm"], r["stability_norm"])
- ---------—
- 6. TEST ON ONE NEW HOUSE
- ---------—
new_house = pd.DataFrame([{
"size_sqft": 1850,
"bedrooms": 3,
"age_years": 8
}])
new_X = scaler.transform(new_house.values.astype(np.float32))
predictions = []
weights = []
for r in results:
pred = float(r["model"].predict(new_X, verbose=0)[0, 0])
w = max(r["fuzzy_weight"], 0.0001)
predictions.append(pred)
weights.append(w)
final_price = np.sum(np.array(predictions) * np.array(weights)) / np.sum(weights)
- ---------—
- 7. PRINT RESULTS
- ---------—
print("\nModel Results")
print("-" * 60)
for r, pred in zip(results, predictions):
print(
f"Model {r['name']} | "
f"RMSE={r['rmse']:.2f} | "
f"ErrorNorm={r['error_norm']:.3f} | "
f"StabilityNorm={r['stability_norm']:.3f} | "
f"FuzzyWeight={r['fuzzy_weight']:.2f} | "
f"Prediction={pred:.2f}"
)
print("-" * 60)
print(f"Final Weighted House Price = {final_price:.2f}")
What this program does
It trains 3 MLPs
A = small
B = medium
C = deeper
It measures 2 things
RMSE = how wrong the model is
stability = whether validation loss is jumping around too much
It uses fuzzy logic
If a model has:
low error
high stability
then fuzzy logic gives it high weight.
If a model has:
high error
then fuzzy logic gives it very low weight.
Then it predicts one new house
Each model predicts price.
Then final answer is weighted average.
How to run it
In terminal:
python fuzzy_house_price_demo.py
You will see output like:
Model A | RMSE=18000.22 | ErrorNorm=0.10 | StabilityNorm=0.75 | FuzzyWeight=82.50 | Prediction=302000.00
Model B | RMSE=21000.44 | ErrorNorm=0.40 | StabilityNorm=0.60 | FuzzyWeight=55.30 | Prediction=308500.00
Model C | RMSE=26000.89 | ErrorNorm=1.00 | StabilityNorm=0.30 | FuzzyWeight=12.10 | Prediction=315000.00
Final Weighted House Price = 305100.25
How to understand it in plain language
This program says:
Model A is good, so trust it more
Model B is acceptable, so trust it somewhat
Model C is weak, so trust it very little
Then combine all 3.
That is the whole idea.
How to convert this into astrological gold system
After you understand this demo, only 4 things change:
Replace input columns
Instead of:
size_sqft
bedrooms
age_years
you will use things like:
d1_strength
d9_strength
d60_strength
gochara_score
dasha_score
nakshatra_score
tithi_score
gold_prev_1
gold_prev_5
Replace target
Instead of house price, use:
gold_next
or
gold_change_next
Replace random split
For gold forecasting, later use time-based split, not random split.
Add more fuzzy inputs later
For gold, later you may also add:
direction accuracy
regime match
recent success in bull phase / bear phase
But not now. First understand this 2-input fuzzy demo.