Пример #1
0
 def denormalize(self, scale: Scale):
     denormalized_min = (scale.denormalize_point(self.min)
                         if self.min is not None else None)
     denormalized_max = (scale.denormalize_point(self.max)
                         if self.max is not None else None)
     return self.__class__(self.p, denormalized_min, denormalized_max,
                           self.weight)
Пример #2
0
def test_log_pdf(xscale: Scale):
    normed_test_loc = 0.5
    normed_test_s = 0.1
    test_loc = xscale.denormalize_point(normed_test_loc)
    test_s = normed_test_s * xscale.width

    ergoLogisticMixture = LogisticMixture(
        components=[
            Logistic(
                loc=xscale.denormalize_point(0.2),
                s=0.5 * xscale.width,
                scale=xscale,
            ),
            Logistic(loc=test_loc, s=test_s, scale=xscale),
        ],
        probs=[1.8629593e-29, 1.0],
    )
    ergoLogistic = Logistic(loc=test_loc, s=test_s, scale=xscale)

    ## Test PDF
    normed_scipydist = scipy.stats.logistic(normed_test_loc, normed_test_s)
    for x in np.linspace(0, 1, 10):
        denormalized_x = xscale.denormalize_point(x)
        assert (normed_scipydist.pdf(x) / xscale.width == pytest.approx(
            float(ergoLogistic.pdf(denormalized_x)), rel=1e-3) ==
                pytest.approx(float(ergoLogisticMixture.pdf(denormalized_x)),
                              rel=1e-3))
Пример #3
0
def test_cdf(xscale: Scale):
    scipydist_normed = scipy.stats.logistic(0.5, 0.05)
    true_loc = xscale.denormalize_point(0.5)
    true_s = 0.05 * xscale.width

    ergodist = Logistic(loc=true_loc, s=true_s, scale=xscale)

    for x in np.linspace(0, 1, 10):
        assert scipydist_normed.cdf(x) == pytest.approx(float(
            ergodist.cdf(xscale.denormalize_point(x))),
                                                        rel=1e-3)

    # TODO: consider a better approach for log scale
    if isinstance(xscale, LogScale):
        for x in np.linspace(xscale.low, xscale.high, 10):
            assert scipydist_normed.cdf(
                xscale.normalize_point(x)) == pytest.approx(float(
                    ergodist.cdf(x)),
                                                            rel=1e-3)
    else:
        scipydist_true = scipy.stats.logistic(true_loc, true_s)
        for x in np.linspace(xscale.low, xscale.high, 10):
            assert scipydist_true.cdf(x) == pytest.approx(float(
                ergodist.cdf(x)),
                                                          rel=1e-3)
Пример #4
0
 def denormalize(self, scale: Scale):
     denormed_base_dist = self.base_dist.denormalize(scale)
     denormed_floor = scale.denormalize_point(self.floor)
     denormed_ceiling = scale.denormalize_point(self.ceiling)
     return self.__class__(
         base_dist=denormed_base_dist,
         floor=denormed_floor,
         ceiling=denormed_ceiling,
     )
Пример #5
0
 def denormalize(self, scale: Scale):
     denormalized_xs = np.array(
         [scale.denormalize_point(x) for x in self.xs])
     denormalized_densities = np.array(
         [density / scale.width for density in self.densities])
     return self.__class__(denormalized_xs, denormalized_densities,
                           self.weight)
Пример #6
0
def test_interval_plus_entropy(scale: Scale):
    conditions = [
        IntervalCondition(p=0.5, max=scale.denormalize_point(0.3)),
        MaxEntropyCondition(weight=0.01),
    ]

    fitted_dist = PointDensity.from_conditions(
        conditions,
        scale=scale,
    )

    # We expect at most 3 different densities: one for inside the interval, one for outside,
    # and one between.
    assert np.unique(fitted_dist.normed_densities).size <= 3
Пример #7
0
def test_pdf(xscale: Scale):
    normed_test_loc = 0.5
    normed_test_s = 0.1
    test_loc = xscale.denormalize_point(normed_test_loc)
    test_s = normed_test_s * xscale.width

    ergoLogisticMixture = LogisticMixture(
        components=[
            Logistic(
                loc=xscale.denormalize_point(0.2),
                s=0.5 * xscale.width,
                scale=xscale,
            ),
            Logistic(loc=test_loc, s=test_s, scale=xscale),
        ],
        probs=[1.8629593e-29, 1.0],
    )
    ergoLogistic = Logistic(loc=test_loc, s=test_s, scale=xscale)

    ## Make sure it integrates to 1
    _xs = xscale.denormalize_points(np.linspace(0, 1, 100))
    densities_logistic = np.array([float(ergoLogistic.pdf(x)) for x in _xs])
    densities_mixture = np.array(
        [float(ergoLogisticMixture.pdf(x)) for x in _xs])
    auc_logistic = float(trapz(densities_logistic, x=_xs))
    auc_mixture = float(trapz(densities_mixture, x=_xs))
    assert (1 == pytest.approx(auc_logistic, abs=0.03) == pytest.approx(
        auc_mixture, abs=0.03))

    if not isinstance(xscale, LogScale):
        scipydist = scipy.stats.logistic(test_loc, test_s)

        for x in np.linspace(xscale.denormalize_point(0),
                             xscale.denormalize_point(1), 10):
            assert (scipydist.pdf(x) == pytest.approx(
                float(ergoLogistic.pdf(x)), rel=1e-3) == pytest.approx(
                    float(ergoLogisticMixture.pdf(x)), rel=1e-3))
Пример #8
0
def test_density_cdf(scale: Scale):
    uniform_dist = PointDensity.from_conditions([MaxEntropyCondition()],
                                                scale=scale)

    # Off of scale
    assert uniform_dist.cdf(scale.denormalize_point(-0.5)) == 0
    assert uniform_dist.cdf(scale.denormalize_point(1.5)) == 1

    # Edges of scale
    assert uniform_dist.cdf(scale.denormalize_point(0.005)) < uniform_dist.cdf(
        scale.denormalize_point(0.015))
    assert uniform_dist.cdf(scale.denormalize_point(0.985)) < uniform_dist.cdf(
        scale.denormalize_point(0.995))

    # Denormalized onto a different scale
    denormalized_dist = uniform_dist.denormalize(Scale(0, 2))
    assert denormalized_dist.cdf(1) == pytest.approx(0.5, abs=0.01)
    assert denormalized_dist.cdf(1.5) != 0
    assert denormalized_dist.cdf(2.5) == 1
Пример #9
0
 def denormalize(self, scale: Scale):
     denormalized_mean = scale.denormalize_point(self.mean)
     return self.__class__(denormalized_mean, self.weight)
Пример #10
0
def test_truncated_ppf(xscale: Scale):
    normed_test_loc = 0.5
    normed_test_s = 0.1
    test_loc = xscale.denormalize_point(normed_test_loc)
    test_s = normed_test_s * xscale.width

    normed_baseline_dist = scipy.stats.logistic(normed_test_loc, normed_test_s)

    def ppf_through_cdf(dist, q):
        return scipy.optimize.bisect(lambda x: dist.cdf(x) - q,
                                     dist.ppf(0.0001),
                                     dist.ppf(0.9999),
                                     maxiter=1000)

    # No bounds
    dist_w_no_bounds = Truncate(Logistic(loc=test_loc, s=test_s, scale=xscale))

    for x in np.linspace(0.01, 0.99, 8):
        assert dist_w_no_bounds.ppf(x) == pytest.approx(float(
            xscale.denormalize_point(normed_baseline_dist.ppf(x))),
                                                        rel=0.001)

    # Floor
    dist_w_floor = Truncate(
        Logistic(loc=test_loc, s=test_s, scale=xscale),
        floor=xscale.denormalize_point(0.5),
    )

    mix_w_floor = LogisticMixture(
        components=[
            Truncate(  # type: ignore
                Logistic(test_loc, s=test_s, scale=xscale),
                floor=xscale.denormalize_point(0.5),
            )
        ],
        probs=[1.0],
    )

    for x in np.linspace(0.01, 0.99, 8):
        assert dist_w_floor.ppf(x) == pytest.approx(float(mix_w_floor.ppf(x)),
                                                    rel=0.001)
        assert dist_w_floor.ppf(x) == pytest.approx(float(
            ppf_through_cdf(dist_w_floor, x)),
                                                    rel=0.001)

    # Ceiling
    dist_w_ceiling = Truncate(
        Logistic(loc=test_loc, s=test_s, scale=xscale),
        ceiling=xscale.denormalize_point(0.8),
    )

    mix_w_ceiling = LogisticMixture(
        components=[
            Truncate(  # type: ignore
                Logistic(test_loc, s=test_s, scale=xscale),
                ceiling=xscale.denormalize_point(0.8),
            )
        ],
        probs=[1.0],
    )

    for x in np.linspace(0.01, 0.99, 8):
        assert dist_w_ceiling.ppf(x) == pytest.approx(float(
            mix_w_ceiling.ppf(x)),
                                                      rel=0.001)
        assert dist_w_ceiling.ppf(x) == pytest.approx(float(
            ppf_through_cdf(dist_w_ceiling, x)),
                                                      rel=0.001)

    # Floor and Ceiling

    dist_w_floor_and_ceiling = Truncate(
        Logistic(loc=test_loc, s=test_s, scale=xscale),
        floor=xscale.denormalize_point(0.2),
        ceiling=xscale.denormalize_point(0.8),
    )

    mix_w_floor_and_ceiling = LogisticMixture(
        components=[
            Truncate(  # type: ignore
                Logistic(test_loc, s=test_s, scale=xscale),
                floor=xscale.denormalize_point(0.2),
                ceiling=xscale.denormalize_point(0.8),
            )
        ],
        probs=[1.0],
    )

    for x in np.linspace(0.01, 0.99, 8):
        assert dist_w_floor_and_ceiling.ppf(x) == pytest.approx(float(
            mix_w_floor_and_ceiling.ppf(x)),
                                                                rel=0.001)
        assert dist_w_floor_and_ceiling.ppf(x) == pytest.approx(float(
            ppf_through_cdf(dist_w_floor_and_ceiling, x)),
                                                                rel=0.001)
Пример #11
0
 def denormalize(self, scale: Scale):
     denormalized_outcome = scale.denormalize_point(self.outcome)
     return self.__class__(denormalized_outcome, self.weight)
Пример #12
0
 def denormalize(self, scale: Scale):
     denormalized_variance = scale.denormalize_point(self.variance)
     return self.__class__(denormalized_variance, self.weight)
Пример #13
0
def test_density_pdf(scale: Scale):
    uniform_dist = PointDensity.from_conditions([MaxEntropyCondition()],
                                                scale=scale)

    assert uniform_dist.pdf(scale.denormalize_point(0.5)) != 0
    assert uniform_dist.pdf(scale.denormalize_point(1.5)) == 0
Пример #14
0
def test_hist_pdf(scale: Scale):
    uniform_dist = HistogramDist.from_conditions([MaxEntropyCondition()], scale=scale)

    assert uniform_dist.pdf(scale.denormalize_point(0.5)) != 0
    assert uniform_dist.pdf(scale.denormalize_point(1.5)) == 0
Пример #15
0
class Logistic(Distribution):
    loc: float  # normalized
    s: float  # normalized
    scale: Scale
    metadata: Any = None

    def __init__(
        self,
        loc: float,
        s: float,
        scale: Optional[Scale] = None,
        metadata=None,
        normalized=False,
    ):
        # TODO (#303): Raise ValueError on scale < 0
        if normalized:
            self.loc = loc
            self.s = np.max([s, 0.0000001])
            self.metadata = metadata
            if scale is not None:
                self.scale = scale
            else:
                self.scale = Scale(0, 1)
            self.true_s = self.s * self.scale.width
            self.true_loc = self.scale.denormalize_point(loc)
        elif scale is None:
            raise ValueError("Either a Scale or normalized parameters are required")
        else:
            self.loc = scale.normalize_point(loc)
            self.s = np.max([s, 0.0000001]) / scale.width
            self.scale = scale
            self.metadata = metadata
            self.true_s = s  # convenience field only used in repr currently
            self.true_loc = loc  # convenience field only used in repr currently

    def __repr__(self):
        return (
            f"Logistic(scale={self.scale}, true_loc={self.true_loc}, "
            f"true_s={self.true_s}, normed_loc={self.loc}, normed_s={self.s},"
            f" metadata={self.metadata})"
        )

    # Distribution

    def pdf(self, x):
        y = (self.scale.normalize_point(x) - self.loc) / self.s
        p = np.exp(scipy.stats.logistic.logpdf(y) - np.log(self.s))
        return p / self.scale.width

    def logpdf(self, x):
        y = (self.scale.normalize_point(x) - self.loc) / self.s
        logp = scipy.stats.logistic.logpdf(y) - np.log(self.s)
        return logp - np.log(self.scale.width)

    def cdf(self, x):
        y = (self.scale.normalize_point(x) - self.loc) / self.s
        return scipy.stats.logistic.cdf(y)

    def ppf(self, q):
        return self.scale.denormalize_point(
            oscipy.stats.logistic(loc=self.loc, scale=self.s).ppf(q)
        )

    def sample(self):
        return self.scale.denormalize_point(
            oscipy.stats.logistic.rvs(loc=self.loc, scale=self.s)
        )

    # Scaled

    def normalize(self):
        """
        Return the normalized condition.

        :param scale: the true scale
        :return: the condition normalized to [0,1]
        """
        return self.__class__(
            self.loc, self.s, Scale(0, 1), self.metadata, normalized=True
        )

    def denormalize(self, scale: Scale):
        """
        Assume that the distribution has been normalized to be over [0,1].
        Return the distribution on the true scale

        :param scale: the true scale
        """

        return self.__class__(self.loc, self.s, scale, self.metadata, normalized=True)

    # Structured

    @classmethod
    def structure(self, params):
        class_params, numeric_params = params
        self_class, scale_classes = class_params
        self_numeric, scale_numeric = numeric_params
        scale = scale_classes[0].structure((scale_classes, scale_numeric))
        return self_class(
            loc=self_numeric[0], s=self_numeric[1], scale=scale, normalized=True
        )

    def destructure(self):
        scale_classes, scale_numeric = self.scale.destructure()
        class_params = (self.__class__, scale_classes)
        self_numeric = (self.loc, self.s)
        numeric_params = (self_numeric, scale_numeric)
        return (class_params, numeric_params)