Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/usage/accumulators.rst
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ Mean

This accumulator is contained in the Mean storage, and supports Views. It
provides three values; ``.count``, ``.value``, and ``.variance``. Internally,
the variance is stored as ``sum_of_deltas_squared``, which is used to compute
the variance is stored as ``_sum_of_deltas_squared``, which is used to compute
``variance``.

For example, you could compute the mean of the following values::
Expand Down
26 changes: 14 additions & 12 deletions include/bh_python/accumulators/mean.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,29 +33,29 @@ struct mean {
const value_type& variance) noexcept
: count(n)
, value(mean)
, sum_of_deltas_squared(variance * (n - 1)) {}
, _sum_of_deltas_squared(variance * (n - 1)) {}

mean(const value_type& sum,
const value_type& mean,
const value_type& sum_of_deltas_squared,
const value_type& _sum_of_deltas_squared,
bool /* Tag to trigger python internal constructor */)
: count(sum)
, value(mean)
, sum_of_deltas_squared(sum_of_deltas_squared) {}
, _sum_of_deltas_squared(_sum_of_deltas_squared) {}

void operator()(const value_type& x) noexcept {
count += static_cast<value_type>(1);
const auto delta = x - value;
value += delta / count;
sum_of_deltas_squared += delta * (x - value);
_sum_of_deltas_squared += delta * (x - value);
}

void operator()(const boost::histogram::weight_type<value_type>& w,
const value_type& x) noexcept {
count += w.value;
const auto delta = x - value;
value += w.value * delta / count;
sum_of_deltas_squared += w.value * delta * (x - value);
_sum_of_deltas_squared += w.value * delta * (x - value);
}

mean& operator+=(const mean& rhs) noexcept {
Expand All @@ -69,38 +69,40 @@ struct mean {

count += rhs.count;
value = (n1 * mu1 + n2 * mu2) / count;
sum_of_deltas_squared += rhs.sum_of_deltas_squared;
sum_of_deltas_squared
_sum_of_deltas_squared += rhs._sum_of_deltas_squared;
_sum_of_deltas_squared
+= n1 * (value - mu1) * (value - mu1) + n2 * (value - mu2) * (value - mu2);

return *this;
}

mean& operator*=(const value_type& s) noexcept {
value *= s;
sum_of_deltas_squared *= s * s;
_sum_of_deltas_squared *= s * s;
return *this;
}

bool operator==(const mean& rhs) const noexcept {
return count == rhs.count && value == rhs.value
&& sum_of_deltas_squared == rhs.sum_of_deltas_squared;
&& _sum_of_deltas_squared == rhs._sum_of_deltas_squared;
}

bool operator!=(const mean& rhs) const noexcept { return !operator==(rhs); }

value_type variance() const noexcept { return sum_of_deltas_squared / (count - 1); }
value_type variance() const noexcept {
return _sum_of_deltas_squared / (count - 1);
}

template <class Archive>
void serialize(Archive& ar, unsigned) {
ar& boost::make_nvp("count", count);
ar& boost::make_nvp("value", value);
ar& boost::make_nvp("sum_of_deltas_squared", sum_of_deltas_squared);
ar& boost::make_nvp("_sum_of_deltas_squared", _sum_of_deltas_squared);
}

value_type count{};
value_type value{};
value_type sum_of_deltas_squared{};
value_type _sum_of_deltas_squared{};
};

} // namespace accumulators
2 changes: 1 addition & 1 deletion notebooks/BoostHistogramHandsOn.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -884,7 +884,7 @@
" [(3., 0.4, 0.02), (0., 0. , 0. ), (0., 0. , 0. ), (0., 0. , 0. ),\n",
" (0., 0. , 0. ), (0., 0. , 0. ), (0., 0. , 0. ), (0., 0. , 0. ),\n",
" (0., 0. , 0. ), (0., 0. , 0. )],\n",
" dtype=[('count', '<f8'), ('value', '<f8'), ('sum_of_deltas_squared', '<f8')])"
" dtype=[('count', '<f8'), ('value', '<f8'), ('_sum_of_deltas_squared', '<f8')])"
]
},
"execution_count": 36,
Expand Down
2 changes: 1 addition & 1 deletion src/boost_histogram/_core/accumulators.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class Mean(_BaseAccumulator):
@property
def value(self) -> float: ...
@property
def sum_of_deltas_squared(self) -> float: ...
def _sum_of_deltas_squared(self) -> float: ...
@property
def variance(self) -> float: ...
def __call__(
Expand Down
6 changes: 3 additions & 3 deletions src/boost_histogram/_internal/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,20 +219,20 @@ def variance(self) -> np.ndarray:
)


@fields("count", "value", "sum_of_deltas_squared")
@fields("count", "value", "_sum_of_deltas_squared")
class MeanView(View):
__slots__ = ()
_PARENT = Mean

count: np.ndarray
value: np.ndarray
sum_of_deltas_squared: np.ndarray
_sum_of_deltas_squared: np.ndarray

# Variance is a computation
@property
def variance(self) -> np.ndarray:
with np.errstate(divide="ignore", invalid="ignore"):
return self["sum_of_deltas_squared"] / (self["count"] - 1) # type: ignore
return self["_sum_of_deltas_squared"] / (self["count"] - 1) # type: ignore


def _to_view(
Expand Down
18 changes: 9 additions & 9 deletions src/register_accumulators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ void register_accumulators(py::module& accumulators) {
;

using mean = accumulators::mean<double>;
PYBIND11_NUMPY_DTYPE(mean, count, value, sum_of_deltas_squared);
PYBIND11_NUMPY_DTYPE(mean, count, value, _sum_of_deltas_squared);

register_accumulator<mean>(accumulators, "Mean", py::buffer_protocol())
.def_buffer(make_buffer<mean>())
Expand All @@ -275,7 +275,7 @@ void register_accumulators(py::module& accumulators) {

.def_readonly("count", &mean::count)
.def_readonly("value", &mean::value)
.def_readonly("sum_of_deltas_squared", &mean::sum_of_deltas_squared)
.def_readonly("_sum_of_deltas_squared", &mean::_sum_of_deltas_squared)

.def_property_readonly("variance", &mean::variance)

Expand Down Expand Up @@ -311,11 +311,11 @@ void register_accumulators(py::module& accumulators) {
return self.count;
else if(key.equal(py::str("value")))
return self.value;
else if(key.equal(py::str("sum_of_deltas_squared")))
return self.sum_of_deltas_squared;
else if(key.equal(py::str("_sum_of_deltas_squared")))
return self._sum_of_deltas_squared;
else
throw py::key_error(
py::str("{0} not one of count, value, sum_of_deltas_squared")
py::str("{0} not one of count, value, _sum_of_deltas_squared")
.format(key));
})
.def("__setitem__",
Expand All @@ -324,17 +324,17 @@ void register_accumulators(py::module& accumulators) {
self.count = value;
else if(key.equal(py::str("value")))
self.value = value;
else if(key.equal(py::str("sum_of_deltas_squared")))
self.sum_of_deltas_squared = value;
else if(key.equal(py::str("_sum_of_deltas_squared")))
self._sum_of_deltas_squared = value;
else
throw py::key_error(
py::str("{0} not one of count, value, sum_of_deltas_squared")
py::str("{0} not one of count, value, _sum_of_deltas_squared")
.format(key));
})

.def("_ipython_key_completions_",
[](py::object /* self */) {
return py::make_tuple("count", "value", "sum_of_deltas_squared");
return py::make_tuple("count", "value", "_sum_of_deltas_squared");
})

;
Expand Down
10 changes: 5 additions & 5 deletions tests/test_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def test_setting_profile():

assert b["value"][0] == h[0].value
assert b["count"][0] == h[0].count
assert b["sum_of_deltas_squared"][0] == h[0].sum_of_deltas_squared
assert b["_sum_of_deltas_squared"][0] == h[0]._sum_of_deltas_squared

h[0] = bh.accumulators.Mean(count=6, value=3, variance=2)
assert h[0].count == 6
Expand All @@ -109,20 +109,20 @@ def test_setting_profile():

assert b["value"][0] == h[0].value
assert b["count"][0] == h[0].count
assert b["sum_of_deltas_squared"][0] == h[0].sum_of_deltas_squared
assert b["_sum_of_deltas_squared"][0] == h[0]._sum_of_deltas_squared

assert b[0]["value"] == a[0]["value"]
assert b[0]["count"] == a[0]["count"]
assert b[0]["sum_of_deltas_squared"] == a[0]["sum_of_deltas_squared"]
assert b[0]["_sum_of_deltas_squared"] == a[0]["_sum_of_deltas_squared"]

assert b[0]["value"] == a["value"][0]
assert b[0]["count"] == a["count"][0]
assert b[0]["sum_of_deltas_squared"] == a["sum_of_deltas_squared"][0]
assert b[0]["_sum_of_deltas_squared"] == a["_sum_of_deltas_squared"][0]

assert_array_equal(a.view().value, b.view()["value"])
assert_array_equal(a.view().count, b.view()["count"])
assert_array_equal(
a.view().sum_of_deltas_squared, b.view()["sum_of_deltas_squared"]
a.view()._sum_of_deltas_squared, b.view()["_sum_of_deltas_squared"]
)


Expand Down