Adaptive Weight System: How Signal Importance Evolves

Not all risk signals matter equally for everyone. Whistl's Adaptive Weight System learns which signals best predict YOUR impulses and adjusts their importance over time. What's a strong predictor for one user may be weak for another—and Whistl discovers the difference.

Why Adaptive Weights Matter

Individual differences in trigger patterns require personalised weighting:

Example: Different Users, Different Triggers

UserStrongest PredictorWeakest Predictor
MarcusVenue proximity (physical triggers)Weather (unaffected by conditions)
SarahSleep quality (biometric triggers)Day of week (consistent across week)
JakeTime of day (late night vulnerability)Calendar stress (not event-driven)

The Problem with Fixed Weights

  • Population averages miss individual patterns: What's true on average may not be true for you
  • Static weights can't adapt: Your patterns may change over time
  • Reduced prediction accuracy: Wrong weights = wrong predictions

How Weight Adaptation Works

The Adaptive Weight System continuously learns from outcomes:

Weight Update Algorithm

# Exponential Moving Average weight update
def update_signal_weight(signal_name, current_weight, signal_value, outcome):
    """
    Adjust signal weight based on prediction accuracy.
    
    Args:
        signal_name: Which signal (e.g., "venue_proximity")
        current_weight: Current importance (0.01 - 0.20)
        signal_value: Signal's current value (0.0 - 1.0)
        outcome: Actual outcome (1 = impulse occurred, 0 = didn't)
    
    Returns:
        Updated weight
    """
    learning_rate = 0.05  # Speed of adaptation
    
    # Calculate prediction contribution
    # If signal was high AND impulse occurred, signal was predictive
    if signal_value > 0.7 and outcome == 1:
        # Signal correctly predicted impulse - increase weight
        adjustment = learning_rate * (1.0 - current_weight)
        new_weight = current_weight + adjustment
    elif signal_value < 0.3 and outcome == 0:
        # Signal correctly predicted no impulse - increase weight
        adjustment = learning_rate * (1.0 - current_weight)
        new_weight = current_weight + adjustment
    elif signal_value > 0.7 and outcome == 0:
        # Signal predicted impulse but none occurred - decrease weight
        adjustment = learning_rate * current_weight
        new_weight = current_weight - adjustment
    elif signal_value < 0.3 and outcome == 1:
        # Signal predicted no impulse but one occurred - decrease weight
        adjustment = learning_rate * current_weight
        new_weight = current_weight - adjustment
    else:
        # Ambiguous case - minor adjustment
        new_weight = current_weight
    
    # Ensure weight stays in valid range
    new_weight = max(0.01, min(0.20, new_weight))
    
    return new_weight

Weight Normalisation

After individual updates, weights are normalised to sum to 1.0:

# Normalise weights to sum to 1.0
def normalise_weights(weights):
    """
    Ensure all signal weights sum to exactly 1.0.
    
    Args:
        weights: Dictionary of {signal_name: weight}
    
    Returns:
        Normalised weights
    """
    total = sum(weights.values())
    
    normalised = {}
    for signal_name, weight in weights.items():
        normalised[signal_name] = weight / total
    
    return normalised

# Example:
# Before: {"venue": 0.08, "sleep": 0.06, "time": 0.04, ...}  # Sum = 0.97
# After:  {"venue": 0.082, "sleep": 0.062, "time": 0.041, ...}  # Sum = 1.0

Weight Adaptation Timeline

Weights evolve through distinct phases:

Phase 1: Default Weights (Days 1-7)

  • Source: Population averages from all users
  • Purpose: Reasonable starting point before personal data
  • Adaptation rate: High (learning quickly)
  • Weight change: Can shift ±20% per week

Phase 2: Personal Calibration (Days 8-30)

  • Source: User's own outcome data
  • Purpose: Discover personal trigger patterns
  • Adaptation rate: Medium (balancing stability and learning)
  • Weight change: Can shift ±10% per week

Phase 3: Stable Personalisation (Days 31+)

  • Source: Accumulated personal data
  • Purpose: Fine-tune established patterns
  • Adaptation rate: Low (stable, minor adjustments)
  • Weight change: Typically ±3% per week

Phase 4: Pattern Shift Detection (Ongoing)

  • Monitors for: Significant changes in impulse patterns
  • Response: Temporarily increase adaptation rate
  • Triggers: Life events, location changes, new habits

Real-World Weight Evolution Examples

Example 1: Marcus's Venue Sensitivity

Initial weight (Day 1): Venue proximity = 5.9% (population average)

Observations:

  • Week 1: 4 impulses, all within 500m of venue
  • Week 2: 3 impulses, all within 500m of venue
  • Week 3: 2 impulses, both within 500m of venue

Weight evolution:

  • Day 7: 7.2% (increased due to predictive accuracy)
  • Day 14: 8.9%
  • Day 30: 10.4%
  • Day 60: 11.2% (stabilised)

Result: Venue proximity weight nearly doubled for Marcus vs. population average

Example 2: Sarah's Sleep Sensitivity

Initial weight (Day 1): Sleep quality = 3.7% (population average)

Observations:

  • Week 1: 3 impulses, all after <6 hours sleep
  • Week 2: 4 impulses, all after <6 hours sleep
  • Week 3: 2 impulses, both after <6 hours sleep
  • Good sleep days: 0 impulses

Weight evolution:

  • Day 7: 5.1%
  • Day 14: 6.8%
  • Day 30: 8.3%
  • Day 60: 8.9% (stabilised)

Result: Sleep weight more than doubled—Sarah is highly sleep-sensitive

Example 3: Jake's Weather Insensitivity

Initial weight (Day 1): Weather conditions = 1.8% (population average)

Observations:

  • Week 1-4: No correlation between weather and impulses
  • Rainy days: Same impulse rate as sunny days
  • Weather signal consistently non-predictive

Weight evolution:

  • Day 7: 1.5%
  • Day 14: 1.2%
  • Day 30: 0.8%
  • Day 60: 0.5% (minimum threshold)

Result: Weather weight reduced to minimum—Jake isn't weather-sensitive

Weight Bounds and Constraints

The system maintains reasonable weight ranges:

Weight Limits

ConstraintValueRationale
Minimum weight0.5%Every signal has some relevance
Maximum weight20%No single signal dominates
Tier 1 minimum8%Primary predictors stay important
Sum constraint100%Weights must sum to 1.0

Rate Limiting

  • Maximum weekly change: ±20% (prevents wild swings)
  • Minimum data for update: 10 observations (prevents overfitting)
  • Cooling period: 24 hours between major adjustments

Effectiveness Data

Adaptive weights vs. fixed weights:

MetricFixed WeightsAdaptive WeightsImprovement
Prediction Accuracy (Day 1-7)72%72%Equal (using defaults)
Prediction Accuracy (Day 30+)72%84%+12%
Prediction Accuracy (Day 90+)72%87%+15%
User Satisfaction4.1/54.6/5+12%

User Testimonials

"Whistl figured out that being near venues is my big trigger. Now it's extra careful when I'm near Crown. That personalisation is powerful." — Marcus, 28

"After a month, Whistl knew my sleep was the key. Now when I sleep badly, it's on high alert. It learned me." — Sarah, 34

"The app gets smarter over time. It's not the same as when I started—it knows my patterns now." — Jake, 31

Conclusion

The Adaptive Weight System transforms Whistl from a generic risk calculator into a deeply personal protection system. By learning which signals matter most for YOU, Whistl becomes more accurate, more relevant, and more effective over time.

Your risk profile is unique. Your weights should be too.

Experience Personalised Risk Assessment

Whistl's adaptive weights learn your unique patterns. Download free and get protection that evolves with you.

Download Whistl Free

Related: Risk Orchestrator | 27 Risk Signals | Machine Learning Money Management