Skip to content

Commit

Permalink
python fix floor divide of float Series
Browse files Browse the repository at this point in the history
  • Loading branch information
ritchie46 committed Oct 22, 2021
1 parent 3935c3e commit b56c930
Show file tree
Hide file tree
Showing 9 changed files with 71 additions and 4 deletions.
17 changes: 17 additions & 0 deletions polars/polars-core/src/series/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,23 @@ impl Series {
))
}

#[cfg(feature = "round_series")]
#[cfg_attr(docsrs, doc(cfg(feature = "round_series")))]
/// Floor underlying floating point array to the lowest integers smaller or equal to the float value.
pub fn floor(&self) -> Result<Self> {
if let Ok(ca) = self.f32() {
let s = ca.apply(|val| val.floor()).into_series();
return Ok(s);
}
if let Ok(ca) = self.f64() {
let s = ca.apply(|val| val.floor()).into_series();
return Ok(s);
}
Err(PolarsError::DataTypeMisMatch(
format!("{:?} is not a floating point datatype", self.dtype()).into(),
))
}

#[cfg(feature = "dot_product")]
#[cfg_attr(docsrs, doc(cfg(feature = "dot_product")))]
pub fn dot(&self, other: &Series) -> Option<f64> {
Expand Down
7 changes: 7 additions & 0 deletions polars/polars-lazy/src/dsl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1054,6 +1054,13 @@ impl Expr {
self.map(move |s: Series| s.round(decimals), GetOutput::same_type())
}

/// Floor underlying floating point array to the lowest integers smaller or equal to the float value.
#[cfg(feature = "round_series")]
#[cfg_attr(docsrs, doc(cfg(feature = "round_series")))]
pub fn floor(self) -> Self {
self.map(move |s: Series| s.floor(), GetOutput::same_type())
}

/// Apply window function over a subgroup.
/// This is similar to a groupby + aggregation + self join.
/// Or similar to [window functions in Postgres](https://www.postgresql.org/docs/9.1/tutorial-window.html).
Expand Down
1 change: 1 addition & 0 deletions py-polars/docs/source/reference/expression.rst
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ Manipulation/ selection
Expr.take_every
Expr.repeat_by
Expr.round
Expr.floor
Expr.cast
Expr.sort
Expr.arg_sort
Expand Down
1 change: 1 addition & 0 deletions py-polars/docs/source/reference/series.rst
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ Manipulation/ selection
Series.rechunk
Series.cast
Series.round
Series.floor
Series.set_at_idx
Series.fill_null
Series.zip_with
Expand Down
26 changes: 25 additions & 1 deletion py-polars/polars/eager/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -392,16 +392,32 @@ def __sub__(self, other: Any) -> "Series":

def __truediv__(self, other: Any) -> "Series":
physical_type = date_like_to_physical(self.dtype)
if self.dtype != physical_type or self.is_float():

# this branch is exactly the floordiv function without rounding the floats
if self.is_float():
if isinstance(other, Series):
return Series._from_pyseries(self._s.div(other._s))

other = _maybe_cast(other, self.dtype)
dtype = date_like_to_physical(self.dtype)
f = get_ffi_func("div_<>", dtype, self._s)
return wrap_s(f(other))

if self.dtype != physical_type:
return self.__floordiv__(other)
return self.cast(pl.Float64) / other

def __floordiv__(self, other: Any) -> "Series":
if isinstance(other, Series):
if self.is_float():
return Series._from_pyseries(self._s.div(other._s)).floor()
return Series._from_pyseries(self._s.div(other._s))

other = _maybe_cast(other, self.dtype)
dtype = date_like_to_physical(self.dtype)
f = get_ffi_func("div_<>", dtype, self._s)
if self.is_float():
return wrap_s(f(other)).floor()
return wrap_s(f(other))

def __mul__(self, other: Any) -> "Series":
Expand Down Expand Up @@ -1986,6 +2002,14 @@ def fill_null(self, strategy: Union[str, "pl.Expr"]) -> "Series":
]
return wrap_s(self._s.fill_null(strategy))

def floor(self) -> "Series":
"""
Floor underlying floating point array to the lowest integers smaller or equal to the float value.
Only works on floating point Series
"""
return wrap_s(self._s.floor())

def round(self, decimals: int) -> "Series":
"""
Round underlying floating point data by `decimals` digits.
Expand Down
8 changes: 8 additions & 0 deletions py-polars/polars/lazy/expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,14 @@ def cummax(self, reverse: bool = False) -> "Expr":
"""
return wrap_expr(self._pyexpr.cummax(reverse))

def floor(self) -> "Expr":
"""
Floor underlying floating point array to the lowest integers smaller or equal to the float value.
Only works on floating point Series
"""
return wrap_expr(self._pyexpr.floor())

def round(self, decimals: int) -> "Expr":
"""
Round underlying floating point data by `decimals` digits.
Expand Down
4 changes: 4 additions & 0 deletions py-polars/src/lazy/dsl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,10 @@ impl PyExpr {
self.clone().inner.round(decimals).into()
}

pub fn floor(&self) -> PyExpr {
self.clone().inner.floor().into()
}

pub fn is_duplicated(&self) -> PyExpr {
self.clone().inner.is_duplicated().into()
}
Expand Down
5 changes: 5 additions & 0 deletions py-polars/src/series.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1238,6 +1238,11 @@ impl PySeries {
Ok(s.into())
}

pub fn floor(&self) -> PyResult<Self> {
let s = self.series.floor().map_err(PyPolarsEr::from)?;
Ok(s.into())
}

pub fn shrink_to_fit(&mut self) {
self.series.shrink_to_fit();
}
Expand Down
6 changes: 3 additions & 3 deletions py-polars/tests/test_series.py
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,7 @@ def test_comparisons_int_series_to_float():
assert (srs_int / 2.0).to_list() == [0.5, 1.0, 1.5, 2.0]
assert (srs_int % 2.0).to_list() == [1, 0, 1, 0]
assert (4.0 % srs_int).to_list() == [0, 0, 1, 0]
# floordiv is implemented as div

assert (srs_int // 2.0).to_list() == [0, 1, 1, 2]
assert (srs_int < 3.0).to_list() == [True, True, False, False]
assert (srs_int <= 3.0).to_list() == [True, True, True, False]
Expand All @@ -741,8 +741,8 @@ def test_comparisons_float_series_to_int():
assert (srs_float / 2).to_list() == [0.5, 1.0, 1.5, 2.0]
assert (srs_float % 2).to_list() == [1.0, 0.0, 1.0, 0.0]
assert (4 % srs_float).to_list() == [0.0, 0.0, 1.0, 0.0]
# floordiv is implemented as div
assert (srs_float // 2).to_list() == [0.5, 1.0, 1.5, 2.0]

assert (srs_float // 2).to_list() == [0.0, 1.0, 1.0, 2.0]
assert (srs_float < 3).to_list() == [True, True, False, False]
assert (srs_float <= 3).to_list() == [True, True, True, False]
assert (srs_float > 3).to_list() == [False, False, False, True]
Expand Down

0 comments on commit b56c930

Please sign in to comment.