Introduction
Real-world data rarely matches the shape of a Normal or Lognormal distribution — project costs skew right, response times have fat tails, some outcomes are bimodal — and forcing a mismatched distribution onto a Monte Carlo model quietly corrupts every result downstream. CreateMetalogDistribution sidesteps that by fitting a Metalog distribution, an "any-shape" family that can represent virtually any continuous data — bounded, semi-bounded, or unbounded — directly from your empirical data, then returns as many random samples as you need for a simulation.
Metalog distributions are essential for:
- Epidemiology: Modeling disease incubation periods with heavy tails or irregular shapes.
- Healthcare: Simulating patient hospital length of stay or recovery times.
- Intelligence Analysis: Modeling uncertainty in target location, response times, or signal strength.
- Finance: Estimating Value at Risk for non-normal asset returns or market volatility.
- Engineering: Reliability analysis for components with complex or non-standard failure distributions.
- Environmental Science: Assessing risks of extreme weather events like flood levels or peak winds.
- Project Management: Estimating task durations in complex R&D or software development.
- Supply Chain: Quantifying lead time variability and demand spikes in global logistics.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
dataframerequired | pd.DataFrame | — | The pandas DataFrame containing the variable of interest. |
variablerequired | str | — | The name of the column in the DataFrame to be used for fitting the distribution. |
lower_bound | float | None | The lower logical bound of the distribution (e.g., 0 for length of stay). If provided along with upper_bound, a bounded metalog is created. Defaults to None. |
upper_bound | float | None | The upper logical bound of the distribution. If provided along with lower_bound, a bounded metalog is created. Defaults to None. |
learning_rate | float | 0.01 | The step length for the metalog fit algorithm. Decreasing this may improve fit accuracy for complex data. Defaults to 0.01. |
term_maximum | int | 9 | The maximum number of terms allowed in the metalog expansion (up to 9). Higher terms provide more shape flexibility but may lead to overfitting. Defaults to 9. |
term_minimum | int | 2 | The minimum number of terms allowed. Defaults to 2. |
term_for_random_sample | int | None | The specific number of terms to use when generating random samples. If None, the term_limit from the fitted metalog is used. Defaults to None. |
number_of_samples | int | 10000 | The number of stochastic samples to generate from the fitted distribution. Defaults to 10000. |
show_summary | bool | True | Whether to print a text summary of the fitted metalog coefficients and validation. Defaults to True. |
return_format | str | 'dataframe' | The format of the returned samples: 'dataframe' (as a pd.DataFrame) or 'array' (as a np.ndarray). Defaults to 'dataframe'. |
plot_metalog_distribution | bool | True | Whether to display a histogram of the generated samples with optional mean/median indicators. Defaults to True. |
fill_color | str | '#999999' | The hex color code for the histogram bars. Defaults to '#999999'. |
fill_transparency | float | 0.6 | The transparency level (0-1) for the histogram plot. Defaults to 0.6. |
figure_size | tuple | (8, 6) | The size of the plot figure in inches (width, height). Defaults to (8, 6). |
show_mean | bool | True | Whether to display the mean value as a vertical dashed line on the plot. Defaults to True. |
show_median | bool | True | Whether to display the median value as a vertical dotted line on the plot. Defaults to True. |
title_for_plot | str | 'Metalog Distribution' | The main title for the distribution plot. Defaults to 'Metalog Distribution'. |
subtitle_for_plot | str | 'Showing the metalog distribution of the variable' | The descriptive subtitle for the plot. |
caption_for_plot | str | None | Optional caption text displayed at the bottom of the plot. Defaults to None. |
data_source_for_plot | str | None | Optional data source identification text. Defaults to None. |
show_y_axis | bool | False | Whether to display the y-axis (frequency/density scale) on the plot. Defaults to False. |
title_y_indent | float | 1.1 | Vertical position for the title text. Defaults to 1.1. |
subtitle_y_indent | float | 1.05 | Vertical position for the subtitle text. Defaults to 1.05. |
caption_y_indent | float | -0.15 | Vertical position for the caption text. Defaults to -0.15. |
Returns
The generated samples from the Metalog distribution, in the format specified by return_format — a pandas DataFrame or a NumPy array.
Example
from analysistoolbox.simulations import CreateMetalogDistribution
import pandas as pd
# Historical project cost data (in $K)
cost_history = pd.DataFrame({
'cost': [82, 95, 110, 125, 140, 155, 170, 195, 230, 280]
})
samples = CreateMetalogDistribution(
dataframe=cost_history,
variable='cost',
lower_bound=0, # costs can't be negative
number_of_samples=10_000,
)
# Use samples in a Monte Carlo model
p10 = samples['cost'].quantile(0.10)
p50 = samples['cost'].quantile(0.50)
p90 = samples['cost'].quantile(0.90)
print(f"P10: ${p10:.0f}K P50: ${p50:.0f}K P90: ${p90:.0f}K")