pandas: Round, floor, and ceil for DataFrame and Series
You can round numbers in pandas.DataFrame
and pandas.Series
using the round()
method. Note that it uses bankers' rounding, which means it rounds half to even (e.g., 0.5
rounds to 0.0
).
- pandas.DataFrame.round — pandas 2.1.3 documentation
- pandas.Series.round — pandas 2.1.3 documentation
For standard rounding (rounding half up) and for rounding down and up decimals (floor and ceiling), use functions from NumPy or the decimal
module in Python's standard library.
For more information about Python's built-in round()
function and NumPy's np.round()
, see the following articles.
- Round numbers with round() and Decimal.quantize() in Python
- NumPy: Round array elements (np.round, np.around, np.rint)
The pandas version used in this article is as follows. Note that functionality may vary between versions.
import pandas as pd
print(pd.__version__)
# 2.1.2
The round()
method of pandas.Series
Consider a Series
with floating point numbers (float
).
s_f = pd.Series([123.456, 987.654])
print(s_f)
# 0 123.456
# 1 987.654
# dtype: float64
Specify the number of digits for rounding with the first argument, decimals
. The default is decimals=0
, rounding to zero decimal places, but the data type remains float
. To convert to an integer (int
), use the astype()
method.
print(s_f.round())
# 0 123.0
# 1 988.0
# dtype: float64
print(s_f.round().astype(int))
# 0 123
# 1 988
# dtype: int64
Positive decimals
values round to the specified number of decimal places, while negative values round to the corresponding integer places (e.g., -1
for tens, -2
for hundreds).
print(s_f.round(2))
# 0 123.46
# 1 987.65
# dtype: float64
print(s_f.round(-2))
# 0 100.0
# 1 1000.0
# dtype: float64
For a Series
with integers (int
), if decimals
is 0
(or if omitted) or positive, there is no change. If negative, it rounds to the corresponding integer place.
s_i = pd.Series([123, 987])
print(s_i)
# 0 123
# 1 987
# dtype: int64
print(s_i.round())
# 0 123
# 1 987
# dtype: int64
print(s_i.round(2))
# 0 123
# 1 987
# dtype: int64
print(s_i.round(-2))
# 0 100
# 1 1000
# dtype: int64
The round()
method returns a new object with rounded numbers, without changing the original object. The same applies to the round()
method of DataFrame
.
s_i_round = s_i.round(-2)
print(s_i_round)
# 0 100
# 1 1000
# dtype: int64
print(s_i)
# 0 123
# 1 987
# dtype: int64
Note that the round()
method rounds half to even (e.g., 0.5
rounds to 0.0
). Details will be discussed later.
The round()
method of pandas.DataFrame
Consider a DataFrame
with columns of floating point numbers (float
), integers (int
), and strings (str
).
df = pd.DataFrame({'f': [123.456, 987.654], 'i': [123, 987], 's': ['abc', 'xyz']})
print(df)
# f i s
# 0 123.456 123 abc
# 1 987.654 987 xyz
print(df.dtypes)
# f float64
# i int64
# s object
# dtype: object
Specify digits for all columns
If you omit the argument of round()
or specify an integer, all columns are rounded to the corresponding number of digits. String columns remain unchanged.
print(df.round())
# f i s
# 0 123.0 123 abc
# 1 988.0 987 xyz
print(df.round(2))
# f i s
# 0 123.46 123 abc
# 1 987.65 987 xyz
print(df.round(-2))
# f i s
# 0 100.0 100 abc
# 1 1000.0 1000 xyz
Specify digits individually for each column
You can specify the number of digits for each column individually using a dictionary, with column names as keys and the number of digits as values. This specification does not affect columns with string data. Any columns not included in the dictionary will remain unchanged.
print(df.round({'f': 2, 'i': -1, 's': 2}))
# f i s
# 0 123.46 120 abc
# 1 987.65 990 xyz
print(df.round({'i': -2}))
# f i s
# 0 123.456 100 abc
# 1 987.654 1000 xyz
The round()
method rounds half to even (bankers' rounding)
The round()
method in pandas uses bankers' rounding, which means it rounds half to even. For example, 0.5
and 2.5
are rounded to 0.0
and 2.0
, respectively.
s = pd.Series([0.5, 1.5, 2.5, 3.5, 4.5])
print(s)
# 0 0.5
# 1 1.5
# 2 2.5
# 3 3.5
# 4 4.5
# dtype: float64
print(s.round())
# 0 0.0
# 1 2.0
# 2 2.0
# 3 4.0
# 4 4.0
# dtype: float64
Rounding to even occurs only when the fraction is exactly 0.5
; for example, 2.5
is rounded to 2.0
, but 2.51
is rounded to 3.0
.
s = pd.Series([2.49, 2.5, 2.51])
print(s)
# 0 2.49
# 1 2.50
# 2 2.51
# dtype: float64
print(s.round())
# 0 2.0
# 1 2.0
# 2 3.0
# dtype: float64
This applies similarly when specifying the number of digits.
s = pd.Series([249, 250, 251])
print(s)
# 0 249
# 1 250
# 2 251
# dtype: int64
print(s.round(-2))
# 0 200
# 1 200
# 2 300
# dtype: int64
Round, floor, and ceil with NumPy functions
As of version 2.1, pandas does not provide methods for standard rounding (rounding half up) and rounding down and up decimals (floor and ceiling). Instead, you can use NumPy or the decimal
module in Python's standard library for these operations.
You can use NumPy functions for Series
and DataFrame
.
import numpy as np
s = pd.Series([-0.5, -0.25, 0.25, 0.5])
print(s)
# 0 -0.50
# 1 -0.25
# 2 0.25
# 3 0.50
# dtype: float64
print(np.floor(s))
# 0 -1.0
# 1 -1.0
# 2 0.0
# 3 0.0
# dtype: float64
print(np.trunc(s))
# 0 -0.0
# 1 -0.0
# 2 0.0
# 3 0.0
# dtype: float64
print(np.ceil(s))
# 0 -0.0
# 1 -0.0
# 2 1.0
# 3 1.0
# dtype: float64
np.floor()
rounds toward negative infinity, np.trunc()
rounds toward zero, np.ceil()
rounds toward positive infinity. For details, refer to the following article.
Although NumPy does not have a function for standard rounding (rounding half up), you can define a custom function to achieve this as follows.
def my_round(x, decimals=0):
return np.floor(x * 10**decimals + 0.5) / 10**decimals
s = pd.Series([0.5, 1.5, 2.5, 3.5, 4.5])
print(s)
# 0 0.5
# 1 1.5
# 2 2.5
# 3 3.5
# 4 4.5
# dtype: float64
print(my_round(s))
# 0 1.0
# 1 2.0
# 2 3.0
# 3 4.0
# 4 5.0
# dtype: float64
print(my_round(s * 10, -1))
# 0 10.0
# 1 20.0
# 2 30.0
# 3 40.0
# 4 50.0
# dtype: float64
Note that applying NumPy functions to a DataFrame
containing non-numeric columns like strings can result in errors. You can use select_dtypes()
to extract only numeric columns.
df = pd.DataFrame({'f': [123.456, 987.654], 'i': [123, 987], 's': ['abc', 'xyz']})
print(df)
# f i s
# 0 123.456 123 abc
# 1 987.654 987 xyz
# print(np.floor(df))
# TypeError: must be real number, not str
print(np.floor(df.select_dtypes('number')))
# f i
# 0 123.0 123.0
# 1 987.0 987.0
It's also possible to process the desired columns and add them as new columns.
df['f_floor'] = np.floor(df['f'])
print(df)
# f i s f_floor
# 0 123.456 123 abc 123.0
# 1 987.654 987 xyz 987.0
Round, floor, and ceil with Python's decimal
module
Using Python's standard library decimal
module, you can handle precise decimal floating point numbers.
Though slower than pandas or NumPy methods/functions, the decimal
module offers precise decimal processing in Series
and DataFrame
.
Import as follows:
from decimal import Decimal, ROUND_HALF_UP, ROUND_FLOOR, ROUND_CEILING
Convert numbers to strings using astype()
and then apply Decimal()
to each element using map()
.
s = pd.Series([0.123, 0.456, 0.789])
print(s)
# 0 0.123
# 1 0.456
# 2 0.789
# dtype: float64
s_decimal = s.astype(str).map(Decimal)
print(s_decimal)
# 0 0.123
# 1 0.456
# 2 0.789
# dtype: object
print(type(s_decimal[0]))
# <class 'decimal.Decimal'>
Note that if not converted to a string, it will be treated as a value that can be represented by a floating point number (float
).
print(s.map(Decimal))
# 0 0.12299999999999999822364316059974953532218933...
# 1 0.45600000000000001643130076445231679826974868...
# 2 0.78900000000000003463895836830488406121730804...
# dtype: object
The quantize()
method of Decimal
objects allows you to round to a specified number of digits with various rounding modes.
print(s_decimal.map(lambda x: x.quantize(Decimal('0.1'), ROUND_HALF_UP)))
# 0 0.1
# 1 0.5
# 2 0.8
# dtype: object
print(s_decimal.map(lambda x: x.quantize(Decimal('0.1'), ROUND_FLOOR)))
# 0 0.1
# 1 0.4
# 2 0.7
# dtype: object
print(s_decimal.map(lambda x: x.quantize(Decimal('0.1'), ROUND_CEILING)))
# 0 0.2
# 1 0.5
# 2 0.8
# dtype: object
For the first argument, specify a Decimal
with the desired number of digits, using a string format such as '0.1'
or '0.01'
. For rounding the integer part, use scientific notation, like '1E1'
. For more details, refer to the following article.
Specify the rounding mode as the second argument, such as ROUND_HALF_UP
for rounding half up, ROUND_FLOOR
for rounding toward negative infinity, and ROUND_CEILING
for rounding toward positive infinity. Other rounding modes can be found in the official documentation.
It's also possible to convert a Series
or DataFrame
with Decimal
objects back to floating point numbers (float
) using astype()
. However, the values will be converted to those representable by float
, so they may include errors.
print(s_decimal.astype(float))
# 0 0.123
# 1 0.456
# 2 0.789
# dtype: float64
print(s_decimal.astype(float).map(Decimal))
# 0 0.12299999999999999822364316059974953532218933...
# 1 0.45600000000000001643130076445231679826974868...
# 2 0.78900000000000003463895836830488406121730804...
# dtype: object