Repository navigation
v0.14.3
The package counts the distinct values of a group now, and it measures the skewness and the kurtosis. Both come to every backend - numpy, numba and the pure python one. The numba backend counts the distinct values with a hash table instead of sorting them, which comes down from 25.9 ms to 8.3 ms on the benchmark data, and the moments accumulate with Welford's algorithm in a single pass, the way pandas computes them.
Added
- The number of distinct values of every group, in every backend (#159):
func="nunique"and the nan-skippingfunc="nannunique". The values that are equal count once - a zero and a minus zero are one value, an integer and the float of the same number as well - and the nans of a group count once among themselves, like pandas counts them. The numba backend counts them with a hash table of its own instead of sorting the values, which is what a count of distinct values does not need: 8.3 ms against 14.9 ms for the numpy backend and 58.1 ms for pandas. - The skewness and the kurtosis of every group, in every backend (#163):
func="skew",func="kurt"(aliaskurtosis) and the nan-skippingnanskewandnankurt. Both follow pandas - the skewness is the corrected third central moment over the second one to the three-halves power, the kurtosis the excess kurtosis, corrected for the size of the group. A group of fewer than three items has no skewness, a group of fewer than four no kurtosis, and a group without any spread has none either (the answer is then 0). A complex input is refused with aTypeError: the third and the fourth moment of the deviations from the mean have no meaning for a complex value. - The quantile and the percentile of every group, in every backend (#157):
func="quantile",func="percentile"and their nan-skipping counterparts, with the interpolation methods of numpy's own quantile.
Changed
- The numpy backend is a package of modules now instead of one file (#160): the operations, the steps, the reductions and the collecting functions live in their own modules, as they do in the numba backend.
- The shared modules have proper names (#162):
aggregate_common.pyiscommon.pynow,utils.pyisutils_np.py- the latter holds the numpy level, the former the vocabulary of the package, which does not import numpy at all. The rules that were written out twice - the overflow checks of the integer mean and variance, the question whether an input is a scalar - are defined once now. - The gather of the aggregated results back onto the input positions is a jitted loop (#164) and not a plain python loop, as the docstring of
unpack_intopromised since the numba backend was rebuilt.unpack_intocomes down from 224 ms to 0.8 ms for 1.2 million values,uaggregate(..., out=)from 306 ms to 2.3 ms. - The annotations of the public API say what the code does (#155): the result type is honest (
allandanyanswer with booleans,arraywith an object array), the names of the functions are literals, and the casts that were only there to silence the type checker are gone.
Fixed
- The numpy backend refused a bool input for
min,max,argminandargmaxwith aValueErrorout ofnp.finfo(bool), while the numba and the pure python backends answered it (#167). All three answer alike now, like numpy itself. - The documentation of the nan-skipping arg reductions said that they name an index for every group that holds a nan (#166) - a group of nothing but nans has nothing to name and answers the fill value, like the plain forms.
Testing
- The moments have a test module of their own (#163): the skewness and the kurtosis of every backend are compared against the group loop of the reference implementation, with the cases that have no answer - a group of two items, a group without any spread, a group of nans.
- The number of distinct values has a test module of their own (#159), with the values that are equal in the different shapes: a zero and a minus zero, an integer and the float of the same number, the nans of a group.
- A test watches the dispatcher of the gather (#164), so that it cannot fall back to a plain python loop unnoticed - a plain loop is 300 times slower.
Benchmark
The moments and the distinct values are in the tables of the README and of docs/benchmarks.md now. The numba backend is the fastest of them all: the skewness comes down to 2.6 ms (numpy 5.6 ms, polars 3.3 ms, pandas 9.6 ms), the kurtosis to 2.4 ms (numpy 5.6 ms, polars 4.1 ms, pandas 10.7 ms), the distinct values to 8.3 ms (numpy 14.9 ms, polars 11.9 ms, pandas 58.1 ms).