Я пишу функцию для построения данных. Я хотел бы указать красивое круглое число для оси 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?
?pretty
?foo(4)==5
и нет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
..но если вы хотите округлить до "хорошего" числа, вам сначала нужно определить, что такое "хорошее" число. Следующее позволяет нам определить «хороший» как вектор с хорошими базовыми значениями от 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
[[РЕДАКТИРОВАТЬ]]
Если вопрос заключается в том, как округлить до указанного ближайшего значения (например, 10 или 100), то ответ Джеймса кажется наиболее подходящим. Моя версия позволяет вам взять любое значение и автоматически округлить его до разумно «хорошего» значения. Вот еще несколько хороших вариантов "хорошего" вектора, приведенного выше:
1:10, c(1,5,10), seq(1, 10, 0.1)
Если у вас есть диапазон значений на вашем графике, например,
[3996.225, 40001.893]
тогда автоматический способ должен учитывать как размер диапазона, так и величину чисел. И, как заметил Хэдли ,pretty()
функция может быть такой, какой вы хотите.источник
Vectorize(roundUpNice)
довольно быстро =) +1 Все равно.roundUpNice(501, nice=c(5, 10)) # 1000
x < 0
и применить- x
в журнале, прежде чем-
возвращать обратно. Я бы также добавил исключение для ситуации, когдаx = 0
В
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
источник
dplyr
замены см .: stackoverflow.com/a/46489816/435093Функция округления в R придает особое значение параметру digits, если он отрицательный.
Это означает, что функция, подобная следующей, очень близка к тому, что вы просите.
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
источник
pretty
, вероятно, это лучший вариант.to * ceiling(x / to)
будет чище?Если вы добавите отрицательное число к аргументу-разряду round (), R округлит его до кратных 10, 100 и т. Д.
round(9, digits = -1) [1] 10 round(89, digits = -1) [1] 90 round(89, digits = -2) [1] 100
источник
Округлить ЛЮБОЕ число вверх / вниз до ЛЮБОГО интервала
Вы можете легко округлить числа до определенного интервала, используя оператор по модулю
%%
.Функция:
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
Как это работает:
Оператор по модулю
%%
определяет остаток от деления первого числа на второе. Добавление или вычитание этого интервала к интересующему вас числу может существенно «округлить» число до выбранного вами интервала.> 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
Обновить:
Удобная версия с двумя аргументами:
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.
Или....
Функция, которая автоматически округляет ВВЕРХ или ВНИЗ на основе стандартных правил округления:
Round <- function(x,y) { if((y - x %% y) <= x %% y) { x + (y - x %% y)} else { x - (x %% y)} }
Автоматически округляет в большую сторону, если
x
значение находится>
на полпути между последующими экземплярами значения округленияy
:# Round(1.3,1) = 1 while Round(1.6,1) = 2 # Round(1.024,0.05) = 1 while Round(1.03,0.05) = 1.05
источник
Round
в VBA в Excel:Function ROUND(x,y) 'Function that automatically rounds UP or DOWN based on standard rounding rules. 'Automatically rounds up if the "x" value is > halfway between subsequent instances of the rounding value "y": If (y - (Evaluate("Mod(" & x & "," & y & ")"))) <= (Evaluate("Mod(" & x & "," & y & ")")) Then Ans = x + (y - (Evaluate("Mod(" & x & "," & y & ")"))) Else Ans = x - (Evaluate("Mod(" & x & "," & y & ")")) End If ROUND = Ans End Function
Что касается округления до кратности произвольного числа , например 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
источник
Я думаю, ваш код отлично работает с небольшой модификацией:
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
Я изменил вашу функцию двумя способами:
=1e-09
стесняйтесь изменять!) к,max(x)
если вы хотите большее числоисточник
Если вы всегда хотите округлять число до ближайшего X, вы можете использовать
ceiling
функцию:#Round 354 up to the nearest 100: > X=100 > ceiling(354/X)*X [1] 400 #Round 47 up to the nearest 30: > Y=30 > ceiling(47/Y)*Y [1] 60
Точно так же, если вы всегда хотите округлять в меньшую сторону , используйте
floor
функцию. Если вы хотите просто округлить до ближайшего Z, используйтеround
вместо этого.> Z=5 > round(367.8/Z)*Z [1] 370 > round(367.2/Z)*Z [1] 365
источник
Вы найдете обновленную версию ответа Томми, которая учитывает несколько случаев:
Ниже кода:
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) } } }
источник
> round.up.nice(.01) [1] 0 > round.up.nice(4.5) [1] 0 > round.up.nice(56) [1] 50
nice_big
иnice_small
определены в обратном порядке (если мы перевернем их в функции,round.up.nice(4.5)
становится4
), но все равно округляется.Я пробовал это без использования какой-либо внешней библиотеки или загадочных функций, и он работает!
Надеюсь, это кому-то поможет.
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
источник