Skip to content

Instantly share code, notes, and snippets.

@MyKo101
Created July 7, 2023 12:09
Show Gist options
  • Select an option

  • Save MyKo101/d94ec9ceb2394d26423db1c0081760ad to your computer and use it in GitHub Desktop.

Select an option

Save MyKo101/d94ec9ceb2394d26423db1c0081760ad to your computer and use it in GitHub Desktop.
Multi-Modality Testing
import itertools
from dataclasses import dataclass
from typing import Tuple
import numpy as np
from diptest import diptest
MEAN = 18.75
STDDEV = 5.647
@dataclass
class Pair:
"""
Data shown represent one of two values. Since we cannot tell
which of the two values the frequency is associated with,
we need to be able to check all combinations of both values.
"""
start: int
freq: int
def __iter__(self):
"""
Begin an iteration
"""
self.count = 0
return self
def __next__(self):
"""
Returns a list of length `freq`, returning
all combinations of the two possible values.
For example, Pair(1,2) would return [1,1], then [1,2] and then [2,2]
"""
n = self.count
m = self.freq - self.count
if m < 0:
raise StopIteration
self.count += 1
a = [self.start]
b = [self.start+1]
return a*m + b*n
@dataclass
class Data:
"""
A way to represent the data (just a tuple of ints)
"""
ls: Tuple[int]
def mean(self, sf: int):
"""
Returns the mean to the appropriate number of significant figures
"""
return float(round(np.mean(self.ls), sf))
def std(self, sf: int):
"""
Returns the standard deviation to the appropriate number of significant figures
"""
return float(round(np.std(self.ls), sf))
def matches(self, mean=MEAN, std=STDDEV):
"""
Test if the data matches the mean & std given
"""
return self.mean(2) == mean and self.std(3) == std
def test(self):
"""
Test if the data is multi-modal or not
"""
dp = diptest(np.array(self.ls))
return {"stat": dp[0], "p": dp[1]}
@dataclass
class PairList:
ls: Tuple[Pair]
def __init__(self, *args):
self.ls = tuple(args)
def __iter__(self):
self.iters = itertools.product(*self.ls)
return self
def __next__(self) -> Data:
return Data(tuple(y for x in next(self.iters) for y in x))
# Data taken from the plot
datapairs = PairList(
Pair(1, 1),
Pair(3, 2),
Pair(5, 1),
Pair(15, 3),
Pair(17, 5),
Pair(19, 12),
Pair(21, 9),
Pair(23, 5),
Pair(25, 2)
)
sig = 0
nsig = 0
for gen_data in datapairs:
if gen_data.matches():
dp = gen_data.test()
if dp["p"] < 0.05:
sig += 1
else:
nsig += 1
print(f"{sig = } <=> {nsig=}. Prop: {sig/(sig+nsig)}")
@MyKo101
Copy link
Author

MyKo101 commented Jul 7, 2023

Figure_1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment