Python library for causal time series modeling
Project description
🧠 Causal Time Series (CTS)
Causal Time Series (CTS) is a Python library for modeling, simulating, and intervening in dynamic business systems using Dynamic DAGs and ODE-style causal updates.
It bridges causal inference, forecasting, and simulation, letting you answer “what if” questions such as:
“What if we increase marketing spend, lower price, or improve support response times — how does that affect revenue?”
🚀 Features
- 🕸️ Dynamic DAGs — define causal dependencies across time.
- ⚙️ Mechanism-based modeling — learn how each variable evolves.
- 💡 Interventions (
Dooperator) — simulate counterfactuals. - 🔁 Forecasting & simulation — Euler-style integration through time.
- 🧮 Derived variables — define deterministic metrics (e.g., revenue = price × paying users).
- 📊 Pandas-first API — DataFrame in, DataFrame out.
- 🔍 Scikit-learn style — familiar
fit(),forecast(),simulate(),plot()interface.
📦 Installation
pip install causal_time_series
🧩 Example: Business Metrics Simulation
This demo models a subscription-based business with feedback between growth, churn, and monetization.
📊 Variables
| Variable | Type | Description |
|---|---|---|
marketing_spend |
Lever | Daily advertising investment |
new_users |
Flow | New users acquired |
churned_users |
Flow | Users leaving the platform |
active_users |
Stock | Current engaged user base |
support_tickets |
State | Customer support volume |
price |
Lever | Subscription price |
paying_users |
State | Users converting to paid plans |
revenue |
Derived | price × paying_users |
arpu |
Derived | revenue / active_users |
🧭 Quickstart
import pandas as pd
from cts import CausalDAG, CTSModel, Do
from cts.utils import business_dataset
# 1️⃣ Load synthetic data
df = business_dataset()
# 2️⃣ Define the causal DAG (no explicit revenue node)
dag = CausalDAG(
nodes=['M','P','N','C','S','A','Pay'],
edges=[
('M','M'), ('P','P'), # persistence for levers
('M','N'), # marketing -> new users
('A','S'), ('S','C'), # active -> tickets -> churn
('N','A'), ('C','A'), # new adds, churn removes
('P','Pay'), ('A','Pay'), # price & active -> paying users
('Pay','Pay'), ('S','S') # persistence
],
lag=1,
rename={
"M":"marketing_spend","P":"price","N":"new_users",
"C":"churned_users","S":"support_tickets",
"A":"active_users","Pay":"paying_users"
}
)
# 3️⃣ Derived variables
derived = {
"revenue": lambda s: s["price"] * s["paying_users"],
"arpu": lambda s: s["revenue"] / (s["active_users"] + 1e-6)
}
# 4️⃣ Fit causal model
cts = CTSModel(dag, backend="ridge", derived=derived).fit(df)
cts.constraints = {
"price": "nonnegative",
"marketing_spend": "nonnegative",
"paying_users": "nonnegative",
"active_users": "nonnegative",
"churned_users": "nonnegative"
}
# 5️⃣ Forecast baseline
forecast = cts.forecast(h=30)
# 6️⃣ Counterfactual: increase marketing
cf = cts.simulate(
h=60,
intervention=Do(shift={"marketing_spend": +50}, from_time=df.index[-1])
)
# 7️⃣ Visualize
cts.plot(df, forecast, cf, cols=["marketing_spend","price","paying_users","churned_users","revenue"])
🧠 Core Concepts
🕸️ Dynamic DAGs
Each edge expresses a temporal causal relationship:
X_{t−1} → Y_t
Variables evolve in time through their causal parents.
⚙️ Differential formulation
CTS learns: [ ΔX_t = f(\text{Parents}_{t−1}) + ε_t ] for each node, using Ridge regression by default (can be extended to Neural ODEs).
🧮 Derived Variables
Derived columns are deterministic functions of other state variables:
derived = {
"revenue": lambda s: s["price"] * s["paying_users"],
"arpu": lambda s: s["revenue"] / (s["active_users"] + 1e-6)
}
They are recomputed automatically after each forecast or simulation step.
🧩 Interventions
Simulate causal “what-if” changes:
# Increase marketing spend
Do(shift={'marketing_spend': +100}, from_time='2023-06-01')
# Fix a variable to constant value
Do(set={'price': 8.0}, from_time='2023-07-01')
📁 Repository Structure
cts/
__init__.py
dag.py
core.py
intervene.py
models/
__init__.py
ridge_delta.py
utils/
__init__.py
datasets.py
examples/
demo_business.ipynb
main.py
README.md
👩💻 License
MIT License © 2025 Nick Gavriil
“Don’t just forecast the future — understand how your actions create it.”
Project details
Release history Release notifications | RSS feed
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 causal_time_series-0.0.2.tar.gz.
File metadata
- Download URL: causal_time_series-0.0.2.tar.gz
- Upload date:
- Size: 9.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7e5ceb66f5b15240e094e8a73310d428dae9de2ded78e308fe9fff5c18e9216f
|
|
| MD5 |
781bb64241bdc29627b9ab93e7b6725f
|
|
| BLAKE2b-256 |
d1a0e30fba378e9613bb4434a8fa82b0eeb407a07efe69b521d049988137e77f
|
File details
Details for the file causal_time_series-0.0.2-py3-none-any.whl.
File metadata
- Download URL: causal_time_series-0.0.2-py3-none-any.whl
- Upload date:
- Size: 11.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e15349f40f66ed0485081c7a751a4f0e8d9ff167543594db19517ae7aca43f60
|
|
| MD5 |
1cf97521f91e0d46ed8d2388457860ba
|
|
| BLAKE2b-256 |
5f64a13cff690ca2d2b88501df814aa764052782af2867f80b28d64858517cb0
|