Piszę funkcję do wykreślania danych. Chciałbym określić ładną okrągłą liczbę dla osi Y, max
która jest większa niż maksymalna wartość zbioru danych.
W szczególności chciałbym mieć funkcję, foo
która wykonuje następujące czynności:
foo(4) == 5
foo(6.1) == 10 #maybe 7 would be better
foo(30.1) == 40
foo(100.1) == 110
Dotarłem tak daleko
foo <- function(x) ceiling(max(x)/10)*10
do zaokrąglania do najbliższych 10, ale nie działa to w przypadku dowolnych interwałów zaokrąglania.
Czy jest lepszy sposób na zrobienie tego w R?
?pretty
?foo(4)==5
a nie10
?Odpowiedzi:
Jeśli chcesz zaokrąglić w górę do najbliższej potęgi 10, po prostu zdefiniuj:
roundUp <- function(x) 10^ceiling(log10(x))
Działa to również, gdy x jest wektorem:
> roundUp(c(0.0023, 3.99, 10, 1003)) [1] 1e-02 1e+01 1e+01 1e+04
..ale jeśli chcesz zaokrąglić do „ładnej” liczby, musisz najpierw zdefiniować, czym jest „ładna” liczba. Poniższy opis pozwala nam zdefiniować „ładny” jako wektor z ładnymi wartościami bazowymi od 1 do 10. Domyślnie jest to liczba parzysta plus 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]]]] }
Powyższe nie działa, gdy x jest wektorem - teraz za późno wieczorem :)
> 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
[[EDYTOWAĆ]]
Jeśli pytanie brzmi, jak zaokrąglić do określonej najbliższej wartości (np. 10 lub 100), odpowiedź Jamesa wydaje się najbardziej odpowiednia. W mojej wersji możesz wziąć dowolną wartość i automatycznie zaokrąglić ją do rozsądnie „ładnej” wartości. Oto kilka innych dobrych opcji powyższego „ładnego” wektora:
1:10, c(1,5,10), seq(1, 10, 0.1)
Jeśli na przykład masz zakres wartości na swoim wykresie,
[3996.225, 40001.893]
wówczas sposób automatyczny powinien uwzględniać zarówno rozmiar zakresu, jak i wielkość liczb. Jak zauważył Hadley ,pretty()
funkcja może być tym, czego chcesz.źródło
Vectorize(roundUpNice)
jest dość szybki =) +1 W każdym razie.roundUpNice(501, nice=c(5, 10)) # 1000
x < 0
i zastosować- x
w dzienniku przed odłożeniem-
. Dodałbym również wyjątek dla sytuacji, w którejx = 0
plyr
Biblioteka posiada funkcjęround_any
, która jest całkiem rodzajowy zrobić wszystkie rodzaje zaokrągleń. Na przykładlibrary(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
źródło
dplyr
wymienić, patrz: stackoverflow.com/a/46489816/435093Funkcja round w R przypisuje specjalne znaczenie parametrowi cyfr, jeśli jest ujemny.
Oznacza to, że funkcja taka jak poniżej jest bardzo zbliżona do tego, o co prosisz.
foo <- function(x) { round(x+5,-1) }
Dane wyjściowe wyglądają następująco
foo(4) [1] 10 foo(6.1) [1] 10 foo(30.1) [1] 40 foo(100.1) [1] 110
źródło
Co powiesz na:
roundUp <- function(x,to=10) { to*(x%/%to + as.logical(x%%to)) }
Co daje:
> roundUp(c(4,6.1,30.1,100.1)) [1] 10 10 40 110 > roundUp(4,5) [1] 5 > roundUp(12,7) [1] 14
źródło
pretty
jest to prawdopodobnie najlepsza opcja.to * ceiling(x / to)
byłby czystszy?Jeśli dodasz liczbę ujemną do argumentu cyfr funkcji round (), R zaokrągli ją do wielokrotności 10, 100 itd.
round(9, digits = -1) [1] 10 round(89, digits = -1) [1] 90 round(89, digits = -2) [1] 100
źródło
Zaokrąglij DOWOLNĄ liczbę w górę / w dół do DOWOLNEGO przedziału
Możesz łatwo zaokrąglić liczby do określonego przedziału za pomocą operatora modulo
%%
.Funkcja:
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) } } }
Przykłady:
> 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
Jak to działa:
Operator modulo
%%
określa pozostałą część z dzielenia pierwszej liczby przez drugą. Dodanie lub odjęcie tego przedziału od liczby będącej przedmiotem zainteresowania może zasadniczo „zaokrąglić” liczbę do wybranego przedziału.> 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
Aktualizacja:
Wygodna wersja 2-argumentowa:
rounder <- function(x,y) { if(y >= 0) { x + (y - x %% y)} else { x - (x %% abs(y))} }
y
Wartości dodatnieroundUp
, natomiasty
wartości ujemneroundDown
:# rounder(7, -4.5) = 4.5, while rounder(7, 4.5) = 9.
Lub....
Funkcja, która automatycznie zaokrągla W GÓRĘ lub W DÓŁ w oparciu o standardowe zasady zaokrąglania:
Round <- function(x,y) { if((y - x %% y) <= x %% y) { x + (y - x %% y)} else { x - (x %% y)} }
Automatycznie zaokrągla w górę, jeśli
x
wartość znajduje się w>
połowie między kolejnymi wystąpieniami wartości zaokrągleniay
:# 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
źródło
Round
do VBA w Excelu: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
Odnośnie zaokrągleń w górę do wielokrotności dowolnej liczby , np. 10, jest prostą alternatywą dla odpowiedzi Jamesa.
Działa dla dowolnej liczby rzeczywistej zaokrąglanej w górę (
from
) i każdej rzeczywistej liczby dodatniej w górę do (to
):> RoundUp <- function(from,to) ceiling(from/to)*to
Przykład:
> 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
źródło
Myślę, że twój kod po prostu działa świetnie z małą modyfikacją:
foo <- function(x, round=10) ceiling(max(x+10^-9)/round + 1/round)*round
A twoje przykłady to:
> 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
Zmieniłem twoją funkcję na dwa sposoby:
=1e-09
krępuj się modyfikować!) domax(x)
jeśli chcesz większą liczbęźródło
Jeśli zawsze chcesz zaokrąglić liczbę w górę do najbliższego X, możesz użyć
ceiling
funkcji:#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
Podobnie, jeśli zawsze chcesz zaokrąglić w dół , użyj
floor
funkcji. Jeśli chcesz po prostu zaokrąglić w górę lub w dół do najbliższego Z, użyjround
zamiast tego.> Z=5 > round(367.8/Z)*Z [1] 370 > round(367.2/Z)*Z [1] 365
źródło
Znajdziesz ulepszoną wersję odpowiedzi Tommy'ego, która uwzględnia kilka przypadków:
Pod kodem:
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) } } }
źródło
> round.up.nice(.01) [1] 0 > round.up.nice(4.5) [1] 0 > round.up.nice(56) [1] 50
nice_big
inice_small
są zdefiniowane w tył, (jeśli je obracać w funkcji,round.up.nice(4.5)
staje się4
), ale nadal zaokrągla w dół.Próbowałem tego bez korzystania z zewnętrznej biblioteki lub tajemniczych funkcji i działa!
Mam nadzieję, że to komuś pomoże.
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
źródło