Использование Floor / Ceil для округления десятичных дробей до целых 5 - PullRequest
0 голосов
/ 03 февраля 2020

Я использовал приведенный ниже код для удобного округления до 1dp, где мне нужно было .5s для округления вверх, например, я хотел получить значение, например, 36,25 для округления до 36,3, а не 36,2.

def my_round(n, ndigits=1):
    try:
       part = n * 10 ** ndigits
       delta = part - int(part)
       # always round "away from 0"
       if delta >= 0.5 or -0.5 < delta <= 0:
           part = math.ceil(part)
       else:
           part = math.floor(part)
       val =  part/(10 ** ndigits)
    except ValueError:
       val = np.nan
    return val

Теперь мне нужно округлить другой десятичный столбец в df до ближайших 5 целых чисел. Может кто-нибудь помочь подсказать, как я могу настроить мой оригинальный код выше, чтобы сделать это? Мне нужно, например, значение, такое как округление 702.5000 до 705. При использовании обычного Round () оно, очевидно, переходит к 700. В этом примере должны применяться все другие нормальные правила округления, например,

702.222 для 700,
707,466 до 705,
703,021 до 705

Ответы [ 6 ]

1 голос
/ 03 февраля 2020

Чтобы округлить до определенного количества десятичных знаков, используйте это:

def my_round(x: float, round_to: float = 5, dp: int = 0) -> float: 
    round_to *= 10**dp 
    x *= 10**dp 
    return ((x + round_to / 2) // round_to * round_to) / 10**dp 

Тестирование:

values = [702.500, 702.222, 707.466, 703.021]
targets = [705., 700., 705., 705.]
assert [my_round(x, 5, 0) for x in values] == targets
assert my_round(3.25, 0.1, 1) == 36.3
1 голос
/ 03 февраля 2020

Самый быстрый способ - разделить на 5, округлить, а затем умножить на 5. Это чисто математический факт, что это сработает.

5*round(n/5)

И в этом нет необходимости Если оператор решает, когда использовать floor или ceil, поскольку round уже по умолчанию использует этот лог c.

РЕДАКТИРОВАТЬ: Как указано, это работает для всех значений, кроме тех, которые заканчиваются в 2.5, когда требуется что это округляется (на практике многим примерам это не понадобится).

Поскольку ответ Эшвина уже достиг этого, я дам исправление, чтобы сделать это в одной строке без определения функции, хотя это не очень красиво. :

5 * (int(x/5) + 1 - round(x/5 % 1))

Или немного чище, используя ceil:

5*(math.ceil(x/5) - round(x/5 % 1))

, используя тот факт, что раунд ведет себя так, как мы хотели бы сверху. Более того, определите:

def my_round(x): return int(x + 1) - round(x % 1)
def round5(x): return 5*my_round(x/5)

, чтобы «исправить» функцию округления и создать красивую функцию round5 в 2 строки. Это то, что я бы сделал.

1 голос
/ 03 февраля 2020
def my_round(n):
    lower = (n//5)*5;
    upper = lower+5;

    if (n-lower)<(upper-n):
        return int(lower)
    return int(upper)

print(my_round(703.021))

Приведенная выше программа пытается найти правильное значение, кратное 5, до и после заданного числа. Затем он находит различия между нижним и верхним возможным числом и возвращает число с наименьшей разницей. Это так же хорошо, как округление.

0 голосов
/ 03 февраля 2020

Предполагая, что вы используете Python 3, будет ли следующая строка выполнять работу?

5*(x//5)+5*(x%5>=2.5)

Кажется, это работает для x, являющегося скаляром, numpy.array или pandas.series

0 голосов
/ 03 февраля 2020

Надеюсь, это поможет

# my standard point to which rounding shoulding happen
>>> standard_nums = [700, 702, 705, 708]


# example value I am taking
>>> my_num = 702.5 


# this is how I would round my number
>>> ret = abs(standard_nums[0] - my_num)
>>> val = standard_nums[0]
>>> for each in standard_nums[1:]:
...     if abs(each - my_num) < ret:
...             ret = abs(each - my_num)
...             val = each
...
>>> ret # min diff I can find
0.5
>>> val # value you are lookin for
702
>>>

## this above has a complexity of O(N)
## where N is the size of your standard number
0 голосов
/ 03 февраля 2020

Вы можете разделить число, которое вы пытаетесь округлить, на 5, затем взять его round() и умножить снова на пять:

num = 707.466
int = num / 5 # returns 141.4932
rounded = round(int) # returns 141
answer = rounded * 5 # 705

Или как функцию:

def round_to_five(num):
    num = num / 5
    num = round(num)
    return num * 5
...