| 14 | |
| 15 | |
| 16 | class SeriesQuantile(Expr): |
| 17 | _parameters = ["frame", "q", "method"] |
| 18 | _defaults = {"method": "default"} |
| 19 | |
| 20 | @functools.cached_property |
| 21 | def q(self): |
| 22 | q = np.array(self.operand("q")) |
| 23 | if q.ndim > 0: |
| 24 | assert len(q) > 0, f"must provide non-empty q={q}" |
| 25 | q.sort(kind="mergesort") |
| 26 | return q |
| 27 | return np.asarray([self.operand("q")]) |
| 28 | |
| 29 | @functools.cached_property |
| 30 | def method(self): |
| 31 | if self.operand("method") == "default": |
| 32 | return "dask" |
| 33 | else: |
| 34 | return self.operand("method") |
| 35 | |
| 36 | @functools.cached_property |
| 37 | def _meta(self): |
| 38 | meta = self.frame._meta |
| 39 | if not is_series_like(self.frame._meta): |
| 40 | meta = meta.to_series() |
| 41 | return make_meta(meta_nonempty(meta).quantile(self.operand("q"))) |
| 42 | |
| 43 | def _divisions(self): |
| 44 | if is_series_like(self._meta): |
| 45 | return (np.min(self.q), np.max(self.q)) |
| 46 | return (None, None) |
| 47 | |
| 48 | @functools.cached_property |
| 49 | def _constructor(self): |
| 50 | meta = self.frame._meta |
| 51 | if not is_series_like(self.frame._meta): |
| 52 | meta = meta.to_series() |
| 53 | return meta._constructor |
| 54 | |
| 55 | @functools.cached_property |
| 56 | def _finalizer(self): |
| 57 | if is_series_like(self._meta): |
| 58 | return lambda tsk: ( |
| 59 | self._constructor, |
| 60 | tsk, |
| 61 | self.q, |
| 62 | None, |
| 63 | self.frame._meta.name, |
| 64 | ) |
| 65 | else: |
| 66 | return lambda tsk: (_finalize_scalar_result, self._constructor, tsk, [0]) |
| 67 | |
| 68 | def _lower(self): |
| 69 | frame = DropnaSeries(self.frame) |
| 70 | if self.method == "tdigest": |
| 71 | return SeriesQuantileTdigest( |
| 72 | frame, self.operand("q"), self.operand("method") |
| 73 | ) |