from math import ceil from typing import Optional from scipy.stats import norm SND_QUARTILE: float = 0.674490 def suggest_iqr_to_range_to_suggest_bins_num(n: int) -> float: p = 1 / (n + 1) return (SND_QUARTILE / norm.ppf(1 - p/2)) def suggest_bins_num(n: int, iqr_to_range: Optional[float] = None, scale: float = 1.) -> int: if n <= 0: raise ValueError(f'n should be >= 1, got {n}') if (iqr_to_range is not None) and (iqr_to_range <= 0.): raise ValueError(f'iqr_to_range should be > 0 or None, got {iqr_to_range}') if scale <= 0.: raise ValueError(f'scale should be > 0, got {scale}') if iqr_to_range is None: iqr_to_range = suggest_iqr_to_range_to_suggest_bins_num(n) t = 0.5 * scale * (1. / iqr_to_range) * (n ** (1. / 3)) return int(ceil(t))