Как округлить до ближайших 10 (или 100 или X)?
Я пишу функцию для данных участков. Я хотел бы указать хорошее круглое число для оси y max это больше, чем Макс набора данных.
в частности, я хотел бы функция foo это выполняет следующее:
foo(4) == 5
foo(6.1) == 10 #maybe 7 would be better
foo(30.1) == 40
foo(100.1) == 110
я добрался до
foo <- function(x) ceiling(max(x)/10)*10
для округления до ближайших 10, но это не работает для произвольных интервалов округления.
есть ли лучший способ сделать это в R?
10 ответов:
если вы просто хотите округлить до ближайшей степени 10, то просто определите:
roundUp <- function(x) 10^ceiling(log10(x))это на самом деле также работает, когда x является вектором:
> roundUp(c(0.0023, 3.99, 10, 1003)) [1] 1e-02 1e+01 1e+01 1e+04..но если вы хотите округлить до" хорошего "числа, вам сначала нужно определить, что такое" хороший " номер. Ниже мы определим "nice" как вектор с хорошими базовыми значениями от 1 до 10. По умолчанию установлено четное число плюс 5.
roundUpNice <- function(x, nice=c(1,2,4,5,6,8,10)) { if(length(x) != 1) stop("'x' must be of length 1") 10^floor(log10(x)) * nice[[which(x <= 10^floor(log10(x)) * nice)[[1]]]] }выше не работает, когда X является вектором - слишком поздно вечер прямо сейчас:)
> roundUpNice(0.0322) [1] 0.04 > roundUpNice(3.22) [1] 4 > roundUpNice(32.2) [1] 40 > roundUpNice(42.2) [1] 50 > roundUpNice(422.2) [1] 500[[EDIT]]
если вопрос заключается в том, как округлить до указанного ближайшего значения (например, 10 или 100), то Джеймс ответ кажется наиболее подходящим. Моя версия позволяет вам взять любое значение и автоматически округлить его до разумного "хорошего" значения. Некоторые другие хорошие варианты" хорошего " вектора выше:
1:10, c(1,5,10), seq(1, 10, 0.1)если у вас есть диапазон значений в ваш сюжет, например
[3996.225, 40001.893]затем автоматическом режиме следует учитывать как размер диапазона и величины. И как отметил Хэдли на
The
plyrбиблиотека имеет функциюround_anyэто довольно общий, чтобы сделать все виды округления. Напримерlibrary(plyr) round_any(132.1, 10) # returns 130 round_any(132.1, 10, f = ceiling) # returns 140 round_any(132.1, 5, f = ceiling) # returns 135
функция round в R присваивает особое значение параметру digits, если он отрицательный.
круглый (x, цифры = 0)
округление до отрицательного числа цифр означает округление до степени десять, поэтому, например, раунд (x, цифры = -2) округляется до ближайшей сотни.
это означает, что функция, как показано ниже получает довольно близко к тому, что вы просите.
foo <- function(x) { round(x+5,-1) }в вывод выглядит следующим образом
foo(4) [1] 10 foo(6.1) [1] 10 foo(30.1) [1] 40 foo(100.1) [1] 110
Как насчет:
roundUp <- function(x,to=10) { to*(x%/%to + as.logical(x%%to)) }что дает:
> roundUp(c(4,6.1,30.1,100.1)) [1] 10 10 40 110 > roundUp(4,5) [1] 5 > roundUp(12,7) [1] 14
Если вы добавите отрицательное число к цифрам-аргументу round (), R округлит его до кратных 10, 100 и т. д.
round(9, digits = -1) [1] 10 round(89, digits = -1) [1] 90 round(89, digits = -2) [1] 100
о округление до кратности произвольного числа, например, 10, вот простая альтернатива ответу Джеймса.
это работает для любого реальные число, округленное (
from) и положительное число округляется до (to):> RoundUp <- function(from,to) ceiling(from/to)*toпример:
> RoundUp(-11,10) [1] -10 > RoundUp(-0.1,10) [1] 0 > RoundUp(0,10) [1] 0 > RoundUp(8.9,10) [1] 10 > RoundUp(135,10) [1] 140 > RoundUp(from=c(1.3,2.4,5.6),to=1.1) [1] 2.2 3.3 6.6
округлить любое число вверх / вниз до любого интервала
вы можете легко округлить числа до определенного интервала с помощью оператор по модулю
%%.функции:
round.choose <- function(x, roundTo, dir = 1) { if(dir == 1) { ##ROUND UP x + (roundTo - x %% roundTo) } else { if(dir == 0) { ##ROUND DOWN x - (x %% roundTo) } } }примеры:
> round.choose(17,5,1) #round 17 UP to the next 5th [1] 20 > round.choose(17,5,0) #round 17 DOWN to the next 5th [1] 15 > round.choose(17,2,1) #round 17 UP to the next even number [1] 18 > round.choose(17,2,0) #round 17 DOWN to the next even number [1] 16как работает:
деление с остатком
%%определяет остаток от деления первого числа на 2-й. Добавление или вычитание этого интервала к вашему числу интерес может существенно "округлить" число до интервала по вашему выбору.> 7 + (5 - 7 %% 5) #round UP to the nearest 5 [1] 10 > 7 + (10 - 7 %% 10) #round UP to the nearest 10 [1] 10 > 7 + (2 - 7 %% 2) #round UP to the nearest even number [1] 8 > 7 + (100 - 7 %% 100) #round UP to the nearest 100 [1] 100 > 7 + (4 - 7 %% 4) #round UP to the nearest interval of 4 [1] 8 > 7 + (4.5 - 7 %% 4.5) #round UP to the nearest interval of 4.5 [1] 9 > 7 - (7 %% 5) #round DOWN to the nearest 5 [1] 5 > 7 - (7 %% 10) #round DOWN to the nearest 10 [1] 0 > 7 - (7 %% 2) #round DOWN to the nearest even number [1] 6
обновление:
удобная 2-аргумент версия:
rounder <- function(x,y) { if(y >= 0) { x + (y - x %% y)} else { x - (x %% abs(y))} }положительное
yзначенияroundUp, в то время как отрицательныйyзначенияroundDown:# rounder(7, -4.5) = 4.5, while rounder(7, 4.5) = 9.
или....
Я думаю, что ваш код просто отлично работает с небольшой модификацией:
foo <- function(x, round=10) ceiling(max(x+10^-9)/round + 1/round)*roundи ваши примеры выполнения:
> foo(4, round=1) == 5 [1] TRUE > foo(6.1) == 10 #maybe 7 would be better [1] TRUE > foo(6.1, round=1) == 7 # you got 7 [1] TRUE > foo(30.1) == 40 [1] TRUE > foo(100.1) == 110 [1] TRUE > # ALL in one: > foo(c(4, 6.1, 30.1, 100)) [1] 110 > foo(c(4, 6.1, 30.1, 100), round=10) [1] 110 > foo(c(4, 6.1, 30.1, 100), round=2.3) [1] 101.2Я изменил вашу функцию в двух направлениях:
- добавлен второй аргумент (для вашего указанного X)
- добавлено небольшое значение (
=1e-09, Не стесняйтесь изменять!) кmax(x)Если вы хотите больше количество
вы найдете обновленную версию Томми что учитывает несколько случаев:
- выбор между нижней или верхней границей
- С учетом отрицательных и нулевых значений
- два разных хороших масштаба в случае, если вы хотите, чтобы функция округляла по-разному маленькие и большие числа. Пример: 4 будет округлено на 0, а 400 будет округлено на 400.
ниже код :
round.up.nice <- function(x, lower_bound = TRUE, nice_small=c(0,5,10), nice_big=c(1,2,3,4,5,6,7,8,9,10)) { if (abs(x) > 100) { nice = nice_big } else { nice = nice_small } if (lower_bound == TRUE) { if (x > 0) { return(10^floor(log10(x)) * nice[[max(which(x >= 10^floor(log10(x)) * nice))[[1]]]]) } else if (x < 0) { return(- 10^floor(log10(-x)) * nice[[min(which(-x <= 10^floor(log10(-x)) * nice))[[1]]]]) } else { return(0) } } else { if (x > 0) { return(10^floor(log10(x)) * nice[[min(which(x <= 10^floor(log10(x)) * nice))[[1]]]]) } else if (x < 0) { return(- 10^floor(log10(-x)) * nice[[max(which(-x >= 10^floor(log10(-x)) * nice))[[1]]]]) } else { return(0) } } }
Я пробовал это без использования какой-либо внешней библиотеки или загадочных функций, и это работает!
надеюсь, что это поможет кому-то.
ceil <- function(val, multiple){ div = val/multiple int_div = as.integer(div) return (int_div * multiple + ceiling(div - int_div) * multiple) } > ceil(2.1, 2.2) [1] 2.2 > ceil(3, 2.2) [1] 4.4 > ceil(5, 10) [1] 10 > ceil(0, 10) [1] 0
Comments