Skip to main content

GOAD🐐 is the GOAT - Goal Oriented Analysis of Data

uv image

GOAD🐐 - When your data analysis is so fire🔥 it's got rizz✨

GOAD🐐

GOAD🐐 is a flexible Python package for analyzing, transforming, and visualizing data with an emphasis on statistical distribution fitting and modular visualization components.

with thanks to my daughters for the genz slang!

📊 Features

  • Composable & extendable plotting system - Build complex visualizations by combining simple components. You can extend the existing components with your own.
  • Statistical distribution fitting - Automatically fit and compare distributions to your data. The distribution registry is extendable with additional distributions.
  • Extendable data transformation pipelines - Chain and reuse data transformations into pipelines. Again, extendable with custom transformation components.

Before GOAD🐐 : mid data After GOAD🐐 : data got infinity aura

📖 Documentation

Full documentation lives in docs/ — ten chapters covering the method, the pipeline and plot systems, the five families of visualisation, distribution fitting, models and residuals, and a visual-critique checklist.

The same chapters are also available as an MCP server, so your coding assistant can coach you through an analysis instead of doing it for you. See MCP_SERVER.md.

🚀 Quick Start

Installation

Using uv:

uv add goad-toolkit

Or, if you prefer your dependencies to be installed 100x slower, with pip:

pip install goad-toolkit

Add the parquet extra if you want to read and write parquet files:

uv add "goad-toolkit[parquet]"

Command line

The install ships a goad command that fits every distribution in the registry to one column of a csv or parquet file and prints the fits, ranked by log-likelihood:

goad data/residuals.csv residual

Use --discrete for count data, --criterion {likelihood,ks,combined} to pick which fits are marked best, and goad --help for the rest.

📋 Demo: Linear Model Analysis

GOAD🐐 includes a comprehensive demo that shows how to use its components together.

Main capabilities

In the demo/linear.py file you can see a showcase of the main capabilities of GOAD🐐:

  • create a data processing pipeline
  • components are extendable, so you can easily add your own steps to a pipeline
  • create visualisations by stacking components. BasePlot will handle boilerplate.
  • the DistributionFitter will try to fit a few common distributions, and add statistical tests for you
  • The results work together with the visualizer.PlotFits class to show the results

The main strenght of this module is not that these elements are there (even thought they are very useful). Its superpower is that everything is extendable: so you can use this as a start, and extend it with your own visualisations and analytics.

POV: Your data just got GOADed🐐 and now it's giving main character energy

📚 Core Components

🔄 Extendable Data Transforms

GOAD🐐 provides a pipeline approach to transform your data:

from goad_toolkit.datatransforms import Pipeline, ShiftValues, ZScaler

# Create a pipeline
pipeline = Pipeline()

# Add transformations
pipeline.add(ShiftValues, name="shift_deaths", column="deaths", period=-14)
pipeline.add(ZScaler, name="scale_tests", column="positivetests", rename=True)

# Apply all transformations
result = pipeline.apply(data)

Available transforms include:

  • ShiftValues - Shift values in a column by a specified period
  • DiffValues - Calculate the difference between consecutive values
  • SelectDataRange - Select rows within a specified date range
  • RollingAvg - Calculate rolling average of a column
  • ZScaler - Standardize values in a column

You can extend the pipeline with your own transformations by subclassing BaseTransform. The Zscaler is implemented as follows:

class ZScaler(TransformBase):
    """Standardize the values in a column."""
    def transform(
        self, data: pd.DataFrame, column: str, rename: bool = False
    ) -> pd.DataFrame:
        """Standardize the values in a column."""
        if rename:
            colname = f"{column}_zscore"
        else:
            colname = column
        data[colname] = (data[column] - data[column].mean()) / data[column].std()
        return data

📊 Visualization System

GOAD🐐 visualization system is built on a composable architecture that allows you to build complex plots by combining simpler components:

from goad_toolkit.visualizer import PlotSettings, ResidualPlot

# Create plot settings
plotsettings = PlotSettings(
        xlabel="date",
        ylabel="normalized values",
        title="Z-Scores of Deaths and Positive Tests",
    )

class LinePlot(BasePlot):
    """Plot a line plot using seaborn."""
    def build(self, data: pd.DataFrame, **kwargs):
        sns.lineplot(data=data, ax=self.ax, **kwargs)
        return self.fig, self.ax


class ComparePlot(BasePlot):
    def build(self, data: pd.DataFrame, x: str, y1: str, y2: str, **kwargs):
        compare = LinePlot(self.settings)
        self.plot_on(compare, data=data, x=x, y=y1, label=y1, **kwargs)
        self.plot_on(compare, data=data, x=x, y=y2, label=y2, **kwargs)
        self.ax.tick_params(axis="x", rotation=45)

        return self.fig, self.ax

compareplot = ComparePlot(plotsettings)
compareplot.plot(
        data=data, x="date", y1="deaths_shifted_zscore", y2="positivetests_zscore"
    )

zscore This extendable strategy lets BasePlot handle the boilerplate, while you can focus on creating the visualizations you need. It is also easier to reuse components in different contexts.

📈 Distribution Fitting

GOAD🐐 includes tools for fitting statistical distributions to your data:

from goad_toolkit.analytics import DistributionFitter
from goad_toolkit.visualizer import PlotSettings, FitPlotSettings, PlotFits

fitter = DistributionFitter()
fits = fitter.fit(data["residual"], discrete=False) # we have to decide if the data is discrete or not
best = fitter.best(fits)
settings = PlotSettings(
    figsize=(12, 6), title="Residuals", xlabel="error", ylabel="probability"
)
fitplotsettings = FitPlotSettings(bins=30, max_fits=3)
fitplotter = PlotFits(settings)
fig = fitplotter.plot(
    data=data["residual"], fit_results=fits, fitplotsettings=fitplotsettings
)

For the kstest, the null hypothesis is that the two distributions are identical. In this example, the p-values are below 0.05, so we can reject the null hypothesis and conclude that the data does not follow any of these.

The plots are sorted by log-likelihood, which means there is no good fit with a distribution in this case. residuals

🎲 Is it real? The shuffle test

Shuffle the labels, measure again, and see where the real number lands. No test, no assumptions, no table of critical values — just a picture of what your measurement does when the label means nothing:

from goad_toolkit.analytics import NullDistribution
from goad_toolkit.visualizer import NullPlot, PlotSettings

def gap(frame):
    means = frame.groupby("is_bot")["length"].mean()
    return means[True] - means[False]

result = NullDistribution(gap, n_iter=2000, seed=1).run(data, label="is_bot")
settings = PlotSettings(
    title="Mean message length: bots minus humans",
    xlabel="difference in mean length (characters)",
    ylabel="density under shuffled labels",
)
NullPlot(settings).plot(result=result)

null distribution

The grey cloud is the statistic under shuffled labels; the line is what the real data did. Writing the statistic is your job — that is the claim. See Models and residuals §6.7 for what the p-value can and cannot carry.

🧩 Extending with Custom Distributions

You can easily register new distributions:

from goad_toolkit.distributions import DistributionRegistry
from scipy import stats

# Create registry
registry = DistributionRegistry()

# Register a new distribution
registry.register_distribution(
    name="negative_binomial",
    dist=stats.nbinom,
    is_discrete=True,
    num_params=2
)

# Hand the registry to the fitter to use your families
from goad_toolkit.analytics import DistributionFitter
fitter = DistributionFitter(registry)
print(fitter.registry) # shows all registered distributions

Registrations belong to the registry you made them on, so a fitter built without one (DistributionFitter()) uses a fresh registry with only the shipped families.

🔧 Advanced Usage: Composing Plots

GOAD🐐 has a powerful plotting system that allows you to combine plot elements:

from goad_toolkit.visualizer import BasePlot, LinePlot, BarWithDates, VerticalDate

# Use a base plot to create a composite
class MyCompositePlot(BasePlot):
    def build(self, data: pd.DataFrame, x: str, y1: str, y2: str, special_date: str):
        # Plot the first component - a line plot
        line_plot = LinePlot(self.settings)
        self.plot_on(line_plot, data=data, x=x, y=y1, label=y1)

        # Plot the second component - a bar chart
        bar_plot = BarWithDates(self.settings)
        self.plot_on(bar_plot, data=data, x=x, y=y2)

        # Add a vertical line
        vline = VerticalDate(self.settings)
        self.plot_on(vline, date=special_date, label="Important Event")
        return self.fig, self.ax

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.


GOAD🐐 - When your data analysis is so fire🔥 it's got rizz✨

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

goad_toolkit-0.2.15.tar.gz (6.4 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

goad_toolkit-0.2.15-py3-none-any.whl (39.0 kB view details)

Uploaded Python 3

File details

Details for the file goad_toolkit-0.2.15.tar.gz.

File metadata

  • Download URL: goad_toolkit-0.2.15.tar.gz
  • Upload date:
  • Size: 6.4 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for goad_toolkit-0.2.15.tar.gz
Algorithm Hash digest
SHA256 2967ae4490f24629d87f5640c7b828a186d5d0f4704ffd238dfa2f41a9505f8c
MD5 f4cef28b8328833575ca3b2920a9fb94
BLAKE2b-256 3c2f6a915878072233aeff2b838c3e6229a021f1b135036c65fc35a3625679be

See more details on using hashes here.

File details

Details for the file goad_toolkit-0.2.15-py3-none-any.whl.

File metadata

  • Download URL: goad_toolkit-0.2.15-py3-none-any.whl
  • Upload date:
  • Size: 39.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for goad_toolkit-0.2.15-py3-none-any.whl
Algorithm Hash digest
SHA256 3c9c7fef081f43dd2d698a1ed1bf49599ab915cee3be11218365e89cfd22fb1d
MD5 6b3faef3d5d929ecb253d04b2ffd9325
BLAKE2b-256 0f9c11524e2eae787a163062dd49ed0116e708211c0ff1785a49744b57d53706

See more details on using hashes here.

Release history Release notifications | RSS feed

0.2.16.1

2 files

This release

0.2.15 This release

2 files

0.2.14

2 files

0.2.13

2 files

0.2.11

2 files

0.2.10

2 files

0.2.9

2 files

0.2.8

2 files

0.2.7

2 files

0.2.5

2 files

0.2.4

2 files

0.2.3

2 files

0.2.2

2 files

0.2.0

2 files

0.1.4

1 file

0.1.3

1 file

0.1.2

1 file

0.1.1

1 file

0.1.0

1 file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page