Why Migrate?

Farseer offers significant advantages over Prophet while maintaining API compatibility:

  • 5-10x faster - Rust-powered performance with automatic multithreading
  • Weighted observations - Native support for data quality and recency weighting
  • Polars support - Modern DataFrame library for even better performance
  • Simpler deployment - Fewer dependencies, single binary distribution
  • Same API - Nearly identical interface, minimal learning curve

Quick Migration Guide

❌ Before (Prophet)

from prophet import Prophet
import pandas as pd

df = pd.DataFrame({
    'ds': pd.date_range('2020-01-01', periods=100),
    'y': range(100)
})

m = Prophet()
m.fit(df)
future = m.make_future_dataframe(periods=30)
forecast = m.predict(future)

✅ After (Farseer)

from farseer import Farseer
import pandas as pd

df = pd.DataFrame({
    'ds': pd.date_range('2020-01-01', periods=100),
    'y': range(100)
})

m = Farseer()  # Just change the class name!
m.fit(df)
future = m.make_future_dataframe(periods=30)
forecast = m.predict(future)

That's it! In most cases, you only need to change Prophet to Farseer.

API Compatibility

Farseer maintains compatibility with Prophet's core API:

✅ Fully Compatible

  • fit(df) - Train the model
  • predict(df) - Make predictions
  • make_future_dataframe(periods) - Generate future dates
  • add_regressor(name, ...) - Add custom regressors
  • add_seasonality(name, period, fourier_order) - Add custom seasonality
  • add_country_holidays(country) - Add holiday effects
  • Growth modes: linear, logistic, flat
  • Seasonality modes: additive, multiplicative
  • Changepoint detection and configuration

⚡ Enhanced Features

  • Weighted observations - Add weight column to your DataFrame
  • Polars DataFrames - Use Polars for 5-10x better performance
  • Automatic multithreading - No configuration needed

Common Migration Scenarios

Scenario 1: Basic Time Series

Prophet

from prophet import Prophet

m = Prophet(
    yearly_seasonality=True,
    weekly_seasonality=False,
    daily_seasonality=False
)
m.fit(df)
forecast = m.predict(future)

Farseer

from farseer import Farseer

m = Farseer(
    yearly_seasonality=True,
    weekly_seasonality=False,
    daily_seasonality=False
)
m.fit(df)
forecast = m.predict(future)

Scenario 2: With Regressors

Prophet

from prophet import Prophet

m = Prophet()
m.add_regressor('temperature')
m.add_regressor('is_weekend')
m.fit(train_df)
forecast = m.predict(test_df)

Farseer

from farseer import Farseer

m = Farseer()
m.add_regressor('temperature')
m.add_regressor('is_weekend')
m.fit(train_df)
forecast = m.predict(test_df)

Scenario 3: With Holidays

Prophet

from prophet import Prophet

m = Prophet()
m.add_country_holidays(country_name='US')
m.fit(df)
forecast = m.predict(future)

Farseer

from farseer import Farseer

m = Farseer()
m.add_country_holidays(country_name='US')
m.fit(df)
forecast = m.predict(future)

Scenario 4: Logistic Growth

Prophet

from prophet import Prophet

df['cap'] = 200  # Carrying capacity
m = Prophet(growth='logistic')
m.fit(df)

future = m.make_future_dataframe(periods=30)
future['cap'] = 200
forecast = m.predict(future)

Farseer

from farseer import Farseer

df['cap'] = 200  # Carrying capacity
m = Farseer(growth='logistic')
m.fit(df)

future = m.make_future_dataframe(periods=30)
future['cap'] = 200
forecast = m.predict(future)

Performance Boost with Polars

For even better performance, migrate to Polars DataFrames:

With Pandas

import pandas as pd
from farseer import Farseer

df = pd.DataFrame({
    'ds': pd.date_range('2020-01-01', periods=1000),
    'y': range(1000)
})

m = Farseer()
m.fit(df)  # Works but slower

With Polars (5-10x faster!)

import polars as pl
from farseer import Farseer
from datetime import datetime

df = pl.DataFrame({
    'ds': pl.date_range(datetime(2020, 1, 1),
                        periods=1000, interval='1d', eager=True),
    'y': range(1000)
})

m = Farseer()
m.fit(df)  # Much faster! ⚡

New Features in Farseer

Weighted Observations

This feature is unique to Farseer and not available in Prophet:

import polars as pl
from farseer import Farseer

# Add weights to emphasize recent data
df = pl.DataFrame({
    'ds': dates,
    'y': values,
    'weight': [2.0 if i < 50 else 1.0 for i in range(100)]
})

# Weights are automatically detected!
m = Farseer()
m.fit(df)

Automatic Multithreading

No configuration needed - Farseer automatically uses all available CPU cores:

# Prophet: single-threaded by default
from prophet import Prophet
m = Prophet()
m.fit(large_df)  # Slower

# Farseer: automatic multithreading
from farseer import Farseer
m = Farseer()
m.fit(large_df)  # Much faster with no extra code!

Conditional Seasonality

Both Prophet and Farseer support conditional seasonality:

Prophet

from prophet import Prophet

m = Prophet()
m.add_seasonality(
    name='weekly_weekday',
    period=7,
    fourier_order=3,
    condition_name='is_weekday'
)
df['is_weekday'] = (df['ds'].dt.weekday < 5)
m.fit(df)

Farseer (identical!)

from farseer import Farseer

m = Farseer()
m.add_seasonality(
    name='weekly_weekday',
    period=7,
    fourier_order=3,
    condition_name='is_weekday'
)
df['is_weekday'] = (df['ds'].dt.weekday < 5)
m.fit(df)

Floor Parameter (Logistic Growth)

Both support floor parameter for saturating minimum:

Prophet

from prophet import Prophet

df['floor'] = 1.5
df['cap'] = 10.0
m = Prophet(growth='logistic')
m.fit(df)

future['floor'] = 1.5
future['cap'] = 10.0
forecast = m.predict(future)

Farseer (identical!)

from farseer import Farseer

df['floor'] = 1.5
df['cap'] = 10.0
m = Farseer(growth='logistic')
m.fit(df)

future['floor'] = 1.5
future['cap'] = 10.0
forecast = m.predict(future)

Smart Regressor Standardization

Farseer auto-detects binary vs continuous regressors:

Prophet

from prophet import Prophet

m = Prophet()

# Manual standardization control
m.add_regressor('is_weekend', standardize=False)
m.add_regressor('temperature', standardize=True)

m.fit(df)

Farseer (smarter!)

from farseer import Farseer

m = Farseer()

# Auto mode detects binary (0/1) vs continuous
m.add_regressor('is_weekend', standardize='auto')
m.add_regressor('temperature', standardize='auto')
# Binary won't be standardized, continuous will be!

m.fit(df)

Independent Holiday Priors

Both support per-holiday prior scales:

Prophet

from prophet import Prophet

m = Prophet()

m.add_country_holidays(
    'US',
    prior_scale=10.0
)
# Can customize per holiday with holidays DataFrame

m.fit(df)

Farseer

from farseer import Farseer

m = Farseer()

# Independent prior scales per holiday
m.add_holidays(
    'christmas',
    dates=[...],
    prior_scale=20.0  # Strong effect
)
m.add_holidays(
    'minor_event',
    dates=[...],
    prior_scale=5.0   # Weak effect
)

m.fit(df)

Feature Comparison Table

Feature Prophet Farseer
Basic Forecasting ✅ Supported ✅ Supported
Linear/Logistic/Flat Growth ✅ Supported ✅ Supported
Custom Seasonality ✅ Supported ✅ Supported
Conditional Seasonality ✅ Supported ✅ Supported
Floor Parameter ✅ Supported ✅ Supported
Regressors ✅ Supported ✅ Supported
Auto Regressor Standardization ❌ Manual only ✅ 'auto' mode
Weighted Observations ❌ Not supported ✅ Native support
Holidays ✅ Supported ✅ Supported
Independent Holiday Priors ✅ Supported ✅ Supported
Multithreading ❌ Single-threaded ✅ Automatic
Polars DataFrames ❌ Pandas only ✅ Polars + Pandas
Model Serialization ✅ JSON/Pickle ✅ JSON
Uncertainty Intervals ✅ Full posterior (MCMC) ✅ Approximation (MAP)
Performance ⚠️ Slower ✅ 5-10x faster

Troubleshooting

Import Errors

# If you get import errors, ensure Farseer is installed
pip install farseer

# For development version
git clone https://github.com/ryanbieber/seer
cd seer
export PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1  # Python 3.13+
maturin develop --release

Minor Differences

While Farseer aims for full Prophet compatibility, there may be minor numerical differences due to:

  • Different optimization algorithms (both use L-BFGS but with different implementations)
  • Floating point precision differences between Rust and Python
  • Random number generation in uncertainty intervals

These differences are typically negligible and don't affect forecast quality.

Need Help?

If you encounter issues migrating from Prophet to Farseer: