I have implemented a custom rounding function in Python using Pandas, but it’s not producing the expected results in certain cases. It basically should always round down to the nearest step.Here’s the function and how I’m applying it:
import pandas as pd
# Define the custom rounding function
def custom_round(x, step):
return x if round(x / step) * step == x else (x // step) * step
# Sample DataFrame similar to my data structure
data = {
"1": [1.300, 1.400, 1.333, 1.364, 1.400],
"X": [5.0, 5.0, 5.0, 4.5, 4.5]
}
outcome = pd.DataFrame(data)
# Define the step for rounding
step = 0.1
# Apply custom_round to create new columns
outcome["1_cluster"] = outcome["1"].apply(lambda x: custom_round(x, step))
outcome["X_cluster"] = outcome["X"].apply(lambda x: custom_round(x, step))
print(outcome)
The output I get from this script is:
1 X 1_cluster X_cluster
0 1.300 5.0 1.3 5.0
1 1.400 5.0 1.3 5.0
2 1.333 5.0 1.3 5.0
3 1.364 4.5 1.3 4.5
4 1.400 4.5 1.3 4.5
However, the correct output for 1_cluster and X_cluster should be:
1 X 1_cluster X_cluster
0 1.300 5.0 1.3 5.0
1 1.400 5.0 1.4 5.0
2 1.333 5.0 1.3 5.0
3 1.364 4.5 1.3 4.5
4 1.400 4.5 1.4 4.5
It seems the function custom_round correctly rounds to 5.0 or 4.5 but fails to round correctly to 1.4 when it should. How can I modify custom_round to ensure it correctly rounds to 1.4 as well?
I appreciate any insights or suggestions. Thank you!
4
Here is a custom rounding solution that rounds down to the nearest step by finding the number decimal point move, n
, needed to make the step an integer, multiplying the step and the decimal part of the value by 10**n
, performing integer division to get the number of step chunks in the decimal, and finally reassembling the number with just the step chunks as the decimal.
def custom_round(x, step):
if step >= 1:
raise ValueError('Step must be less than 1')
n = 0
new_step = step
if step < 1:
while (new_step % 10 != 0):
n += 1
new_step = new_step * 10
m = 10 ** n
new_step = int(step * m)
x_whole, x_frac = divmod(x, 1)
new_x_frac = round(x_frac * m)
chunks = int(new_x_frac // new_step)
return round(x_whole + (chunks * new_step / m), n)
for x in [1.300, 1.400, 1.333, 1.364, 1.400]:
print('#', custom_round(x, 0.1))
# prints:
# 1.3
# 1.4
# 1.3
# 1.3
# 1.4
1