Skip to content

Commit c25d3f0

Browse files
m-richardsFBruzzesipre-commit-ci[bot]
authored
feat: Add support for {Expr,Series}.{ceil,floor} (#3198)
--------- Co-authored-by: Francesco Bruzzesi <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent f05011c commit c25d3f0

File tree

15 files changed

+301
-1
lines changed

15 files changed

+301
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ dist/
1313
coverage.xml
1414
.hypothesis/
1515
.pytest_cache/
16+
.mypy_cache
1617

1718
# Documentation
1819
site/

docs/api-reference/expr.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
- all
1010
- any
1111
- cast
12+
- ceil
1213
- clip
1314
- count
1415
- cum_count
@@ -24,6 +25,7 @@
2425
- fill_null
2526
- filter
2627
- first
28+
- floor
2729
- is_between
2830
- is_close
2931
- is_duplicated

docs/api-reference/series.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- arg_min
1616
- arg_true
1717
- cast
18+
- ceil
1819
- clip
1920
- count
2021
- cum_count
@@ -31,6 +32,7 @@
3132
- fill_null
3233
- filter
3334
- first
35+
- floor
3436
- from_iterable
3537
- from_numpy
3638
- gather_every

narwhals/_arrow/series.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,12 @@ def round(self, decimals: int) -> Self:
516516
pc.round(self.native, decimals, round_mode="half_towards_infinity")
517517
)
518518

519+
def floor(self) -> Self:
520+
return self._with_native(pc.floor(self.native))
521+
522+
def ceil(self) -> Self:
523+
return self._with_native(pc.ceil(self.native))
524+
519525
def diff(self) -> Self:
520526
return self._with_native(pc.pairwise_diff(self.native.combine_chunks()))
521527

narwhals/_compliant/column.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,8 @@ def rolling_var(
198198
self, window_size: int, *, min_samples: int, center: bool, ddof: int
199199
) -> Self: ...
200200
def round(self, decimals: int) -> Self: ...
201+
def floor(self) -> Self: ...
202+
def ceil(self) -> Self: ...
201203
def shift(self, n: int) -> Self: ...
202204
def unique(self) -> Self: ...
203205

narwhals/_compliant/expr.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,12 @@ def tail(self, n: int) -> Self:
709709
def round(self, decimals: int) -> Self:
710710
return self._reuse_series("round", decimals=decimals)
711711

712+
def floor(self) -> Self:
713+
return self._reuse_series("floor")
714+
715+
def ceil(self) -> Self:
716+
return self._reuse_series("ceil")
717+
712718
def len(self) -> Self:
713719
return self._reuse_series("len", returns_scalar=True)
714720

narwhals/_dask/expr.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,16 @@ def count(self) -> Self:
445445
def round(self, decimals: int) -> Self:
446446
return self._with_callable(lambda expr: expr.round(decimals), "round")
447447

448+
def floor(self) -> Self:
449+
import dask.array as da
450+
451+
return self._with_callable(da.floor, "floor")
452+
453+
def ceil(self) -> Self:
454+
import dask.array as da
455+
456+
return self._with_callable(da.ceil, "ceil")
457+
448458
def unique(self) -> Self:
449459
return self._with_callable(lambda expr: expr.unique(), "unique")
450460

narwhals/_pandas_like/series.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,62 @@ def tail(self, n: int) -> Self:
788788
def round(self, decimals: int) -> Self:
789789
return self._with_native(self.native.round(decimals=decimals))
790790

791+
def floor(self) -> Self:
792+
native = self.native
793+
native_cls = type(native)
794+
implementation = self._implementation
795+
if get_dtype_backend(native.dtype, implementation=implementation) == "pyarrow":
796+
import pyarrow.compute as pc
797+
798+
from narwhals._arrow.utils import native_to_narwhals_dtype
799+
800+
ca = native.array._pa_array
801+
result_arr = cast("ChunkedArrayAny", pc.floor(ca))
802+
nw_dtype = native_to_narwhals_dtype(result_arr.type, self._version)
803+
out_dtype = narwhals_to_native_dtype(
804+
nw_dtype, "pyarrow", self._implementation, self._version
805+
)
806+
result_native = native_cls(
807+
result_arr, dtype=out_dtype, index=native.index, name=native.name
808+
)
809+
else:
810+
array_funcs = self._array_funcs
811+
result_arr = array_funcs.floor(self.native)
812+
result_native = (
813+
native_cls(result_arr, index=native.index, name=native.name)
814+
if implementation.is_cudf()
815+
else result_arr
816+
)
817+
return self._with_native(result_native)
818+
819+
def ceil(self) -> Self:
820+
native = self.native
821+
native_cls = type(native)
822+
implementation = self._implementation
823+
if get_dtype_backend(native.dtype, implementation=implementation) == "pyarrow":
824+
import pyarrow.compute as pc
825+
826+
from narwhals._arrow.utils import native_to_narwhals_dtype
827+
828+
ca = native.array._pa_array
829+
result_arr = cast("ChunkedArrayAny", pc.ceil(ca))
830+
nw_dtype = native_to_narwhals_dtype(result_arr.type, self._version)
831+
out_dtype = narwhals_to_native_dtype(
832+
nw_dtype, "pyarrow", self._implementation, self._version
833+
)
834+
result_native = native_cls(
835+
result_arr, dtype=out_dtype, index=native.index, name=native.name
836+
)
837+
else:
838+
array_funcs = self._array_funcs
839+
result_arr = array_funcs.ceil(self.native)
840+
result_native = (
841+
native_cls(result_arr, index=native.index, name=native.name)
842+
if implementation.is_cudf()
843+
else result_arr
844+
)
845+
return self._with_native(result_native)
846+
791847
def to_dummies(self, *, separator: str, drop_first: bool) -> PandasLikeDataFrame:
792848
from narwhals._pandas_like.dataframe import PandasLikeDataFrame
793849

narwhals/_polars/expr.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ def struct(self) -> PolarsExprStructNamespace:
340340
arg_max: Method[Self]
341341
arg_min: Method[Self]
342342
arg_true: Method[Self]
343+
ceil: Method[Self]
343344
clip: Method[Self]
344345
count: Method[Self]
345346
cum_max: Method[Self]
@@ -352,6 +353,7 @@ def struct(self) -> PolarsExprStructNamespace:
352353
fill_null: Method[Self]
353354
fill_nan: Method[Self]
354355
first: Method[Self]
356+
floor: Method[Self]
355357
last: Method[Self]
356358
gather_every: Method[Self]
357359
head: Method[Self]

narwhals/_polars/series.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
"arg_max",
8282
"arg_min",
8383
"arg_true",
84+
"ceil",
8485
"clip",
8586
"count",
8687
"cum_max",
@@ -93,6 +94,7 @@
9394
"fill_null",
9495
"fill_nan",
9596
"filter",
97+
"floor",
9698
"gather_every",
9799
"head",
98100
"is_between",
@@ -699,6 +701,7 @@ def struct(self) -> PolarsSeriesStructNamespace:
699701
arg_max: Method[int]
700702
arg_min: Method[int]
701703
arg_true: Method[Self]
704+
ceil: Method[Self]
702705
clip: Method[Self]
703706
count: Method[int]
704707
cum_max: Method[Self]
@@ -711,6 +714,7 @@ def struct(self) -> PolarsSeriesStructNamespace:
711714
fill_null: Method[Self]
712715
fill_nan: Method[Self]
713716
filter: Method[Self]
717+
floor: Method[Self]
714718
gather_every: Method[Self]
715719
head: Method[Self]
716720
is_between: Method[Self]

0 commit comments

Comments
 (0)