Skip to content

Commit

Permalink
Expose half_up rounding in cuDF (#8477)
Browse files Browse the repository at this point in the history
Authors:
  - Ashwin Srinath (https://github.com/shwina)

Approvers:
  - GALI PREM SAGAR (https://github.com/galipremsagar)
  - Ram (Ramakrishna Prabhu) (https://github.com/rgsl888prabhu)
  - Michael Wang (https://github.com/isVoid)
  - Marlene  (https://github.com/marlenezw)

URL: #8477
  • Loading branch information
shwina authored Jun 10, 2021
1 parent b895396 commit d46e8c7
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 11 deletions.
11 changes: 8 additions & 3 deletions python/cudf/cudf/_lib/round.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ from cudf._lib.cpp.round cimport (
)


def round(Column input_col, int decimal_places=0):
def round(Column input_col, int decimal_places=0, how="half_even"):
"""
Round column values to the given number of decimal places
Expand All @@ -26,16 +26,21 @@ def round(Column input_col, int decimal_places=0):
-------
A Column with values rounded to the given number of decimal places
"""
if how not in {"half_even", "half_up"}:
raise ValueError("'how' must be either 'half_even' or 'half_up'")

cdef column_view input_col_view = input_col.view()
cdef unique_ptr[column] c_result

cdef cpp_rounding_method c_how = (
cpp_rounding_method.HALF_EVEN if how == "half_even"
else cpp_rounding_method.HALF_UP
)
with nogil:
c_result = move(
cpp_round(
input_col_view,
decimal_places,
cpp_rounding_method.HALF_EVEN,
c_how
)
)

Expand Down
6 changes: 4 additions & 2 deletions python/cudf/cudf/core/column/numerical_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,12 @@ def corr(self, other: ColumnBase) -> float:
return cudf.utils.dtypes._get_nan_for_dtype(self.dtype)
return cov / lhs_std / rhs_std

def round(self, decimals: int = 0) -> NumericalBaseColumn:
def round(
self, decimals: int = 0, how: str = "half_even"
) -> NumericalBaseColumn:
"""Round the values in the Column to the given number of decimals.
"""
return libcudf.round.round(self, decimal_places=decimals)
return libcudf.round.round(self, decimal_places=decimals, how=how)

def _apply_scan_op(self, op: str) -> ColumnBase:
return self._copy_type_metadata(libcudf.reduce.scan(op, self, True))
9 changes: 6 additions & 3 deletions python/cudf/cudf/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -1661,7 +1661,7 @@ def __arrow_array__(self, type=None):
"consider using .to_arrow()"
)

def round(self, decimals=0):
def round(self, decimals=0, how="half_even"):
"""
Round a DataFrame to a variable number of decimal places.
Expand All @@ -1676,6 +1676,9 @@ def round(self, decimals=0):
columns not included in `decimals` will be left as is. Elements
of `decimals` which are not columns of the input will be
ignored.
how : str, optional
Type of rounding. Can be either "half_even" (default)
of "half_up" rounding.
Returns
-------
Expand Down Expand Up @@ -1741,7 +1744,7 @@ def round(self, decimals=0):
raise ValueError("Index of decimals must be unique")

cols = {
name: col.round(decimals[name])
name: col.round(decimals[name], how=how)
if (
name in decimals.keys()
and pd.api.types.is_numeric_dtype(col.dtype)
Expand All @@ -1751,7 +1754,7 @@ def round(self, decimals=0):
}
elif isinstance(decimals, int):
cols = {
name: col.round(decimals)
name: col.round(decimals, how=how)
if pd.api.types.is_numeric_dtype(col.dtype)
else col.copy(deep=True)
for name, col in self._data.items()
Expand Down
8 changes: 5 additions & 3 deletions python/cudf/cudf/core/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -4748,7 +4748,7 @@ def mode(self, dropna=True):

return Series(val_counts.index.sort_values(), name=self.name)

def round(self, decimals=0):
def round(self, decimals=0, how="half_even"):
"""
Round each value in a Series to the given number of decimals.
Expand All @@ -4758,6 +4758,9 @@ def round(self, decimals=0):
Number of decimal places to round to. If decimals is negative,
it specifies the number of positions to the left of the decimal
point.
how : str, optional
Type of rounding. Can be either "half_even" (default)
of "half_up" rounding.
Returns
-------
Expand All @@ -4773,9 +4776,8 @@ def round(self, decimals=0):
2 3.0
dtype: float64
"""

return Series(
self._column.round(decimals=decimals),
self._column.round(decimals=decimals, how=how),
name=self.name,
index=self.index,
dtype=self.dtype,
Expand Down
7 changes: 7 additions & 0 deletions python/cudf/cudf/tests/test_series.py
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,13 @@ def test_series_round(arr, decimals):
np.array_equal(ser.nullmask.to_array(), result.to_array())


def test_series_round_half_up():
s = cudf.Series([0.0, 1.0, 1.2, 1.7, 0.5, 1.5, 2.5, None])
expect = cudf.Series([0.0, 1.0, 1.0, 2.0, 1.0, 2.0, 3.0, None])
got = s.round(how="half_up")
assert_eq(expect, got)


@pytest.mark.parametrize(
"series",
[
Expand Down

0 comments on commit d46e8c7

Please sign in to comment.