Saya menulis fungsi untuk memplot data. Saya ingin menentukan angka bulat yang bagus untuk sumbu y max
yang lebih besar dari maks dataset.
Secara khusus, saya menginginkan fungsi foo
yang melakukan hal berikut:
foo(4) == 5
foo(6.1) == 10 #maybe 7 would be better
foo(30.1) == 40
foo(100.1) == 110
Saya sudah sejauh ini
foo <- function(x) ceiling(max(x)/10)*10
untuk pembulatan ke 10 terdekat, tetapi ini tidak berfungsi untuk interval pembulatan arbitrer.
Apakah ada cara yang lebih baik untuk melakukan ini di R?
?pretty
?foo(4)==5
dan tidak10
?Jawaban:
Jika Anda hanya ingin membulatkan ke pangkat 10 terdekat, maka tentukan saja:
roundUp <- function(x) 10^ceiling(log10(x))
Ini sebenarnya juga berfungsi ketika x adalah vektor:
> roundUp(c(0.0023, 3.99, 10, 1003)) [1] 1e-02 1e+01 1e+01 1e+04
..tetapi jika Anda ingin membulatkan ke angka yang "bagus", Anda harus terlebih dahulu menentukan apa itu angka yang "bagus". Berikut ini memungkinkan kita mendefinisikan "bagus" sebagai vektor dengan nilai dasar yang bagus dari 1 sampai 10. Defaultnya disetel ke bilangan genap ditambah 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]]]] }
Di atas tidak berfungsi ketika x adalah vektor - sekarang sudah larut malam :)
> 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]]
Jika pertanyaannya adalah bagaimana membulatkan ke nilai terdekat yang ditentukan (seperti 10 atau 100), maka jawaban Yakobus tampaknya paling tepat. Versi saya memungkinkan Anda mengambil nilai apa pun dan secara otomatis membulatkannya ke nilai yang cukup "bagus". Beberapa pilihan bagus lainnya dari vektor "bagus" di atas adalah:
1:10, c(1,5,10), seq(1, 10, 0.1)
Jika Anda memiliki rentang nilai dalam plot Anda, misalnya
[3996.225, 40001.893]
, cara otomatis harus mempertimbangkan ukuran rentang dan besarnya angkanya. Dan seperti yang dicatat oleh Hadley ,pretty()
fungsinya mungkin sesuai dengan keinginan Anda.sumber
Vectorize(roundUpNice)
cukup cepat =) +1 Pokoknya.roundUpNice(501, nice=c(5, 10)) # 1000
x < 0
dan menerapkannya- x
di log sebelum meletakkan-
kembali. Saya juga akan menambahkan pengecualian untuk situasi di manax = 0
The
plyr
perpustakaan memiliki fungsiround_any
yang cukup umum untuk melakukan segala macam pembulatan. Sebagai contohlibrary(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
sumber
dplyr
penggantinya, lihat: stackoverflow.com/a/46489816/435093Fungsi bulat di R memberikan arti khusus ke parameter digit jika negatif.
Ini berarti fungsi seperti berikut ini mendekati apa yang Anda minta.
foo <- function(x) { round(x+5,-1) }
Outputnya terlihat seperti berikut
foo(4) [1] 10 foo(6.1) [1] 10 foo(30.1) [1] 40 foo(100.1) [1] 110
sumber
Bagaimana tentang:
roundUp <- function(x,to=10) { to*(x%/%to + as.logical(x%%to)) }
Pemberian yang mana:
> roundUp(c(4,6.1,30.1,100.1)) [1] 10 10 40 110 > roundUp(4,5) [1] 5 > roundUp(12,7) [1] 14
sumber
pretty
mungkin pilihan terbaik.to * ceiling(x / to)
lebih bersih?Jika Anda menambahkan angka negatif ke argumen digit round (), R akan membulatkannya ke kelipatan 10, 100 dll.
round(9, digits = -1) [1] 10 round(89, digits = -1) [1] 90 round(89, digits = -2) [1] 100
sumber
Bulatkan angka APA PUN Naik / Turun hingga interval APA PUN
Anda dapat dengan mudah membulatkan angka ke interval tertentu menggunakan operator modulo
%%
.Fungsinya:
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) } } }
Contoh:
> 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
Bagaimana itu bekerja:
Operator modulo
%%
menentukan sisa pembagian bilangan pertama dengan bilangan kedua. Menambah atau mengurangi interval ini dengan jumlah minat Anda pada dasarnya dapat 'membulatkan' angka tersebut ke interval yang Anda pilih.> 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
Memperbarui:
Versi 2-argumen yang nyaman:
rounder <- function(x,y) { if(y >= 0) { x + (y - x %% y)} else { x - (x %% abs(y))} }
y
Nilai positifroundUp
, sedangkany
nilai negatifroundDown
:# rounder(7, -4.5) = 4.5, while rounder(7, 4.5) = 9.
Atau....
Fungsi yang secara otomatis membulatkan KE ATAS atau KE BAWAH berdasarkan aturan pembulatan standar:
Round <- function(x,y) { if((y - x %% y) <= x %% y) { x + (y - x %% y)} else { x - (x %% y)} }
Secara otomatis dibulatkan jika
x
nilainya berada di>
tengah antara contoh nilai pembulatan berikutnyay
:# 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
sumber
Round
ke VBA di 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
Mengenai pembulatan ke kelipatan angka acak , misalnya 10, berikut adalah alternatif sederhana untuk jawaban Yakobus.
Ini berfungsi untuk bilangan real apa pun yang dibulatkan (
from
) dan bilangan positif nyata apa pun yang dibulatkan ke (to
):> RoundUp <- function(from,to) ceiling(from/to)*to
Contoh:
> 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
sumber
Saya pikir kode Anda hanya berfungsi dengan baik dengan sedikit modifikasi:
foo <- function(x, round=10) ceiling(max(x+10^-9)/round + 1/round)*round
Dan contoh Anda berjalan:
> 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
Saya mengubah fungsi Anda dengan dua cara:
=1e-09
, silakan memodifikasi!) kemax(x)
jika Anda menginginkan angka yang lebih besarsumber
Jika Anda selalu ingin membulatkan angka ke atas ke X terdekat, Anda dapat menggunakan
ceiling
fungsi:#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
Demikian pula, jika Anda selalu ingin membulatkan ke bawah , gunakan
floor
fungsinya. Jika Anda ingin membulatkan ke atas atau ke bawah ke Z terdekat, gunakanround
saja.> Z=5 > round(367.8/Z)*Z [1] 370 > round(367.2/Z)*Z [1] 365
sumber
Anda akan menemukan versi yang ditingkatkan dari jawaban Tommy yang memperhitungkan beberapa kasus:
Di bawah kode:
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) } } }
sumber
> round.up.nice(.01) [1] 0 > round.up.nice(4.5) [1] 0 > round.up.nice(56) [1] 50
nice_big
dannice_small
didefinisikan mundur, (jika kita membalik fungsi mereka,round.up.nice(4.5)
menjadi4
) tetapi masih membulatkan ke bawah.Saya mencoba ini tanpa menggunakan pustaka eksternal atau fitur samar dan berhasil!
Semoga bisa membantu seseorang.
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
sumber