Skip to main content

Null density estimation using normalizing flows

Project description

tail integrals for multimodal distributions

This repository is for exploring approximations to difficult-to-sample or -to-model distributions of the sort encountered during Monte Carlo (MC) sampling. The focus is deriving an approximation to the CDF such that more precise tail probabilities can be obtained than through direct MC sampling. A key inferential target is p-values in null hypothesis significance testing. Although built on PyTorch, we do not require GPU access.

Installing and Running

pip install zuko torch torchaudio torchvision scipy numpy pandas nfnull

You can then run in Python as follows:

import torch
import scipy
import numpy as np

from nfnull import NFNull

def gmm_xdf(x, locs, scales, ws, sf=False):
    """ 
    Gaussian mixture model
    """
    pdfs = np.zeros(len(x))
    cdfs = np.zeros(len(x))
    for i in range(len(locs)):
        pdfs += ws[i] * scipy.stats.norm.pdf(x, loc=locs[i], scale=scales[i])
        if sf:
            cdfs += ws[i] * scipy.stats.norm.sf(x, loc=locs[i], scale=scales[i])
        else:
            cdfs += ws[i] * scipy.stats.norm.cdf(x, loc=locs[i], scale=scales[i])        
    return pdfs, cdfs

## generate trimodal distribution
x = np.concatenate((
    scipy.stats.norm.rvs(loc=-1, scale=0.25, size=150),
    scipy.stats.norm.rvs(loc=0, scale=0.25, size=150),
    scipy.stats.norm.rvs(loc=1.5, scale=0.25, size=200)
))
nfn = NFNull(x)
nfn.fit_pdf(verbose=True, tol=1e-4)

print(f"Analytic p-value: {gmm_xdf([4.9], [-1, 0, 1.5], [0.25]*3, [0.3, 0.3, 0.4], sf=True)[1][0]}")
print(f"Empirical mean from samples {np.mean(x > 4.9)}")
print(f"Neural approx: {nfn.p_value(4.9)}")

This should give something close to:

Analytic p-value: 8.008668894725593e-43
Empirical mean from samples 0.0
Neural approx: 9.9999999e-09

Detailed Examples

There are worked examples in nfnull/notebooks.

Calling from R

Assuming you have named your Python environment 'nfnull':

# Load the reticulate library and set up the Python environment
library(reticulate)

# Set the Python environment to 'nfnull'
use_py <- subset(reticulate::conda_list(), name == 'nfnull')$python
Sys.setenv(RETICULATE_PYTHON = use_py)
use_condaenv('nfnull')

# Import necessary Python libraries
np <- import("numpy")
scipy <- import("scipy.stats")
torch <- import("torch")
nfnull <- import("nfnull")

# Define the Gaussian Mixture Model function in R using reticulate
gmm_xdf <- function(x, locs, scales, ws, sf = FALSE) {
  pdfs <- np$zeros(length(x))
  cdfs <- np$zeros(length(x))
  for (i in seq_along(locs)) {
    pdfs <- pdfs + ws[i] * scipy$norm$pdf(x, loc = locs[i], scale = scales[i])
    if (sf) {
      cdfs <- cdfs + ws[i] * scipy$norm$sf(x, loc = locs[i], scale = scales[i])
    } else {
      cdfs <- cdfs + ws[i] * scipy$norm$cdf(x, loc = locs[i], scale = scales[i])
    }
  }
  return(list(pdfs = pdfs, cdfs = cdfs))
}

# Generate the trimodal distribution
x <- np$concatenate(list(
  scipy$norm$rvs(loc = -1, scale = 0.25, size = 150L),
  scipy$norm$rvs(loc = 0, scale = 0.25, size = 150L),
  scipy$norm$rvs(loc = 1.5, scale = 0.25, size = 200L)
))

# Initialize NFNull and fit the model
nfn <- nfnull$NFNull(x)
nfn$fit_pdf(verbose = TRUE, tol = 1e-4)

# Compute and print the p-values
analytic_p_value <- gmm_xdf(c(4.9), c(-1, 0, 1.5), rep(0.25, 3), c(0.3, 0.3, 0.4), sf = TRUE)$cdfs[1]
empirical_mean <- np$mean(x > 4.9)
neural_approx <- nfn$p_value(4.9)

cat("Analytic p-value:", analytic_p_value, "\n")
cat("Empirical mean from samples:", empirical_mean, "\n")
cat("Neural approx:", neural_approx, "\n")

Project details


Download files

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

Source Distribution

nfnull-0.1.0.tar.gz (17.1 kB view details)

Uploaded Source

Built Distribution

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

nfnull-0.1.0-py3-none-any.whl (10.9 kB view details)

Uploaded Python 3

File details

Details for the file nfnull-0.1.0.tar.gz.

File metadata

  • Download URL: nfnull-0.1.0.tar.gz
  • Upload date:
  • Size: 17.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for nfnull-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b3a20c8136b6e98eff8f5518cd5533cfdcdb6cb6df5caf3ec2b35fd17b968e8e
MD5 152df707c143c9aec3cb289a0d2e56e3
BLAKE2b-256 1fde07860d31e8c172afad7dfb14cecb4b758727500458e17de3d5bb067ca7c3

See more details on using hashes here.

File details

Details for the file nfnull-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: nfnull-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 10.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for nfnull-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 63c86b542cfadaf0e0e6259dc72507d70d501e10be1eaa36cf8c43697c262db8
MD5 04f0c8add94b1a1ff4b8b96bcd076eb9
BLAKE2b-256 ef27ba71e92a03d030bfa04d63e791bf3a35b922c91c2a9011db82eb6b6eccba

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page