Skip to content

Commit 22f0c7e

Browse files
committed
Merge pull request pandas-dev#11809 from Dr-Irv/rounding
ENH: Using built-in round on a series pandas-dev#11763
2 parents 92cf968 + 45b304e commit 22f0c7e

File tree

9 files changed

+233
-135
lines changed

9 files changed

+233
-135
lines changed

doc/source/whatsnew/v0.18.0.txt

+4
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ Other enhancements
3434
- Handle truncated floats in SAS xport files (:issue:`11713`)
3535
- Added option to hide index in ``Series.to_string`` (:issue:`11729`)
3636
- ``read_excel`` now supports s3 urls of the format ``s3://bucketname/filename`` (:issue:`11447`)
37+
- A simple version of ``Panel.round()`` is now implemented (:issue:`11763`)
38+
- For Python 3.x, ``round(DataFrame)``, ``round(Series)``, ``round(Panel)`` will work (:issue:`11763`)
3739

3840
.. _whatsnew_0180.enhancements.rounding:
3941

@@ -90,6 +92,8 @@ In addition, ``.round()`` will be available thru the ``.dt`` accessor of ``Serie
9092
Backwards incompatible API changes
9193
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9294

95+
- The parameter ``out`` has been removed from the ``Series.round()`` method. (:issue:`11763`)
96+
9397
Bug in QuarterBegin with n=0
9498
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9599

pandas/core/frame.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -4376,13 +4376,17 @@ def round(self, decimals=0, out=None):
43764376
Returns
43774377
-------
43784378
DataFrame object
4379+
4380+
See Also
4381+
--------
4382+
numpy.around
43794383
"""
43804384
from pandas.tools.merge import concat
43814385

43824386
def _dict_round(df, decimals):
43834387
for col, vals in df.iteritems():
43844388
try:
4385-
yield np.round(vals, decimals[col])
4389+
yield vals.round(decimals[col])
43864390
except KeyError:
43874391
yield vals
43884392

@@ -4392,8 +4396,8 @@ def _dict_round(df, decimals):
43924396
raise ValueError("Index of decimals must be unique")
43934397
new_cols = [col for col in _dict_round(self, decimals)]
43944398
elif com.is_integer(decimals):
4395-
# Dispatch to numpy.round
4396-
new_cols = [np.round(v, decimals) for _, v in self.iteritems()]
4399+
# Dispatch to Series.round
4400+
new_cols = [v.round(decimals) for _, v in self.iteritems()]
43974401
else:
43984402
raise TypeError("decimals must be an integer, a dict-like or a Series")
43994403

pandas/core/generic.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -749,7 +749,10 @@ def bool(self):
749749

750750
def __abs__(self):
751751
return self.abs()
752-
752+
753+
def __round__(self,decimals=0):
754+
return self.round(decimals)
755+
753756
#----------------------------------------------------------------------
754757
# Array Interface
755758

pandas/core/panel.py

+27
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,33 @@ def head(self, n=5):
624624

625625
def tail(self, n=5):
626626
raise NotImplementedError
627+
628+
def round(self, decimals=0):
629+
"""
630+
Round each value in Panel to a specified number of decimal places.
631+
632+
.. versionadded:: 0.18.0
633+
634+
Parameters
635+
----------
636+
decimals : int
637+
Number of decimal places to round to (default: 0).
638+
If decimals is negative, it specifies the number of
639+
positions to the left of the decimal point.
640+
641+
Returns
642+
-------
643+
Panel object
644+
645+
See Also
646+
--------
647+
numpy.around
648+
"""
649+
if com.is_integer(decimals):
650+
result = np.apply_along_axis(np.round, 0, self.values)
651+
return self._wrap_result(result, axis=0)
652+
raise TypeError("decimals must be an integer")
653+
627654

628655
def _needs_reindex_multi(self, axes, method, level):
629656
""" don't allow a multi reindex on Panel or above ndim """

pandas/core/series.py

+20-6
Original file line numberDiff line numberDiff line change
@@ -1235,15 +1235,29 @@ def idxmax(self, axis=None, out=None, skipna=True):
12351235
argmin = idxmin
12361236
argmax = idxmax
12371237

1238-
@Appender(np.ndarray.round.__doc__)
1239-
def round(self, decimals=0, out=None):
1238+
def round(self, decimals=0):
12401239
"""
1240+
Round each value in a Series to the given number of decimals.
1241+
1242+
Parameters
1243+
----------
1244+
decimals : int
1245+
Number of decimal places to round to (default: 0).
1246+
If decimals is negative, it specifies the number of
1247+
positions to the left of the decimal point.
1248+
1249+
Returns
1250+
-------
1251+
Series object
1252+
1253+
See Also
1254+
--------
1255+
numpy.around
12411256
12421257
"""
1243-
result = _values_from_object(self).round(decimals, out=out)
1244-
if out is None:
1245-
result = self._constructor(result,
1246-
index=self.index).__finalize__(self)
1258+
result = _values_from_object(self).round(decimals)
1259+
result = self._constructor(result,
1260+
index=self.index).__finalize__(self)
12471261

12481262
return result
12491263

pandas/tests/test_format.py

+1-123
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# -*- coding: utf-8 -*-
1+
# -*- coding: utf-8 -*-
22
from __future__ import print_function
33
from distutils.version import LooseVersion
44
import re
@@ -2969,128 +2969,6 @@ def test_to_csv_engine_kw_deprecation(self):
29692969
df = DataFrame({'col1' : [1], 'col2' : ['a'], 'col3' : [10.1] })
29702970
df.to_csv(engine='python')
29712971

2972-
def test_round_dataframe(self):
2973-
2974-
# GH 2665
2975-
2976-
# Test that rounding an empty DataFrame does nothing
2977-
df = DataFrame()
2978-
tm.assert_frame_equal(df, df.round())
2979-
2980-
# Here's the test frame we'll be working with
2981-
df = DataFrame(
2982-
{'col1': [1.123, 2.123, 3.123], 'col2': [1.234, 2.234, 3.234]})
2983-
2984-
# Default round to integer (i.e. decimals=0)
2985-
expected_rounded = DataFrame(
2986-
{'col1': [1., 2., 3.], 'col2': [1., 2., 3.]})
2987-
tm.assert_frame_equal(df.round(), expected_rounded)
2988-
2989-
# Round with an integer
2990-
decimals = 2
2991-
expected_rounded = DataFrame(
2992-
{'col1': [1.12, 2.12, 3.12], 'col2': [1.23, 2.23, 3.23]})
2993-
tm.assert_frame_equal(df.round(decimals), expected_rounded)
2994-
2995-
# This should also work with np.round (since np.round dispatches to
2996-
# df.round)
2997-
tm.assert_frame_equal(np.round(df, decimals), expected_rounded)
2998-
2999-
# Round with a list
3000-
round_list = [1, 2]
3001-
with self.assertRaises(TypeError):
3002-
df.round(round_list)
3003-
3004-
# Round with a dictionary
3005-
expected_rounded = DataFrame(
3006-
{'col1': [1.1, 2.1, 3.1], 'col2': [1.23, 2.23, 3.23]})
3007-
round_dict = {'col1': 1, 'col2': 2}
3008-
tm.assert_frame_equal(df.round(round_dict), expected_rounded)
3009-
3010-
# Incomplete dict
3011-
expected_partially_rounded = DataFrame(
3012-
{'col1': [1.123, 2.123, 3.123], 'col2': [1.2, 2.2, 3.2]})
3013-
partial_round_dict = {'col2': 1}
3014-
tm.assert_frame_equal(
3015-
df.round(partial_round_dict), expected_partially_rounded)
3016-
3017-
# Dict with unknown elements
3018-
wrong_round_dict = {'col3': 2, 'col2': 1}
3019-
tm.assert_frame_equal(
3020-
df.round(wrong_round_dict), expected_partially_rounded)
3021-
3022-
# float input to `decimals`
3023-
non_int_round_dict = {'col1': 1, 'col2': 0.5}
3024-
if sys.version < LooseVersion('2.7'):
3025-
# np.round([1.123, 2.123], 0.5) is only a warning in Python 2.6
3026-
with self.assert_produces_warning(DeprecationWarning, check_stacklevel=False):
3027-
df.round(non_int_round_dict)
3028-
else:
3029-
with self.assertRaises(TypeError):
3030-
df.round(non_int_round_dict)
3031-
3032-
# String input
3033-
non_int_round_dict = {'col1': 1, 'col2': 'foo'}
3034-
with self.assertRaises(TypeError):
3035-
df.round(non_int_round_dict)
3036-
3037-
non_int_round_Series = Series(non_int_round_dict)
3038-
with self.assertRaises(TypeError):
3039-
df.round(non_int_round_Series)
3040-
3041-
# List input
3042-
non_int_round_dict = {'col1': 1, 'col2': [1, 2]}
3043-
with self.assertRaises(TypeError):
3044-
df.round(non_int_round_dict)
3045-
3046-
non_int_round_Series = Series(non_int_round_dict)
3047-
with self.assertRaises(TypeError):
3048-
df.round(non_int_round_Series)
3049-
3050-
# Non integer Series inputs
3051-
non_int_round_Series = Series(non_int_round_dict)
3052-
with self.assertRaises(TypeError):
3053-
df.round(non_int_round_Series)
3054-
3055-
non_int_round_Series = Series(non_int_round_dict)
3056-
with self.assertRaises(TypeError):
3057-
df.round(non_int_round_Series)
3058-
3059-
# Negative numbers
3060-
negative_round_dict = {'col1': -1, 'col2': -2}
3061-
big_df = df * 100
3062-
expected_neg_rounded = DataFrame(
3063-
{'col1':[110., 210, 310], 'col2':[100., 200, 300]})
3064-
tm.assert_frame_equal(
3065-
big_df.round(negative_round_dict), expected_neg_rounded)
3066-
3067-
# nan in Series round
3068-
nan_round_Series = Series({'col1': nan, 'col2':1})
3069-
expected_nan_round = DataFrame(
3070-
{'col1': [1.123, 2.123, 3.123], 'col2': [1.2, 2.2, 3.2]})
3071-
if sys.version < LooseVersion('2.7'):
3072-
# Rounding with decimal is a ValueError in Python < 2.7
3073-
with self.assertRaises(ValueError):
3074-
df.round(nan_round_Series)
3075-
else:
3076-
with self.assertRaises(TypeError):
3077-
df.round(nan_round_Series)
3078-
3079-
# Make sure this doesn't break existing Series.round
3080-
tm.assert_series_equal(df['col1'].round(1), expected_rounded['col1'])
3081-
3082-
def test_round_issue(self):
3083-
# GH11611
3084-
3085-
df = pd.DataFrame(np.random.random([3, 3]), columns=['A', 'B', 'C'],
3086-
index=['first', 'second', 'third'])
3087-
3088-
dfs = pd.concat((df, df), axis=1)
3089-
rounded = dfs.round()
3090-
self.assertTrue(rounded.index.equals(dfs.index))
3091-
3092-
decimals = pd.Series([1, 0, 2], index=['A', 'B', 'A'])
3093-
self.assertRaises(ValueError, df.round, decimals)
30942972

30952973
class TestSeriesFormatting(tm.TestCase):
30962974
_multiprocess_can_split_ = True

0 commit comments

Comments
 (0)