En yakın 10'a (veya 100 veya X) nasıl yuvarlanır?


95

Verileri çizmek için bir fonksiyon yazıyorum. maxVeri kümesinin maksimumundan daha büyük olan y ekseni için güzel bir yuvarlak sayı belirtmek istiyorum .

Özellikle, fooaşağıdakileri gerçekleştiren bir işlev istiyorum :

foo(4) == 5
foo(6.1) == 10 #maybe 7 would be better
foo(30.1) == 40
foo(100.1) == 110 

Kadar uzağa gittim

foo <- function(x) ceiling(max(x)/10)*10

en yakın 10'a yuvarlamak için, ancak bu keyfi yuvarlama aralıkları için çalışmaz.

Bunu R'de yapmanın daha iyi bir yolu var mı?


Grafik oluştururken R varsayılan davranışı, çizim sınırlarını her yöndeki veri aralığının ~% 4 dışında ayarlamaktır. Bu sizi tatmin etmiyorsa, sadece daha yüksek veya daha düşük bir yüzde oranında çıkan bir şey yazabilirsiniz.
joran

@joran bilgi için teşekkürler, ancak hepsinin aynı eksen sınırlarına ve işaretlere sahip birden fazla grafik istiyorum ve bunun nasıl yardımcı olduğundan emin değilim.
Abe

1
Arka planı bilmediğim için burada karanlıkta el yordamıyla hareket ediyorum. Eğer başka bir X parametresi eklerseniz ve her iki 10'u da X ile değiştirirseniz, foo'nuz en yakın X'e yuvarlanacaktır. Ya da fasetlemeyi kullanabilirsiniz.
joran

15
Aradığınız ?pretty?
hadley

Neden oluyor foo(4)==5ve değil 10?
James

Yanıtlar:


65

En yakın 10 kuvvetine yuvarlamak istiyorsanız, o zaman şunu tanımlayın:

roundUp <- function(x) 10^ceiling(log10(x))

Bu aslında x bir vektör olduğunda da işe yarar:

> roundUp(c(0.0023, 3.99, 10, 1003))
[1] 1e-02 1e+01 1e+01 1e+04

..ama "güzel" bir sayıya yuvarlamak istiyorsanız, önce "güzel" sayının ne olduğunu tanımlamanız gerekir. Aşağıdaki, "güzel" i 1'den 10'a kadar güzel temel değerlere sahip bir vektör olarak tanımlamamıza izin verir. Varsayılan, çift sayılar artı 5'e ayarlanmıştır.

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]]]]
}

Yukarıdakiler x bir vektör olduğunda çalışmaz - şu anda akşam çok geç :)

> 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

[[DÜZENLE]]

Soru, belirli bir en yakın değere nasıl yuvarlanacağı ise (10 veya 100 gibi), James cevabı en uygun gibi görünüyor. Benim versiyonum herhangi bir değeri alıp otomatik olarak makul bir şekilde "hoş" bir değere yuvarlamanıza izin veriyor. Yukarıdaki "güzel" vektörün diğer bazı iyi seçimleri şunlardır:1:10, c(1,5,10), seq(1, 10, 0.1)

Örneğin grafiğinizde bir dizi değeriniz [3996.225, 40001.893]varsa, otomatik yöntem hem aralığın boyutunu hem de sayıların büyüklüğünü hesaba katmalıdır. Ve Hadley'in belirttiği gibi , pretty()işlev istediğiniz şey olabilir.


1
Vectorize(roundUpNice)oldukça hızlı =) +1 Neyse.
mbq

Orijinal değer daha düşükse, roundUp işlevini nihai sonucun yarısına düzenlemenin bir yolu olup olmadığını merak ediyordum. örneğin 101-500 arası bir sayı 500'e yuvarlanır ve 501-999 sayıları 1000'e yuvarlanır? hepsini 1000'e yuvarlamak yerine?
helen.h

Sadece güzel vektörü değiştirin:roundUpNice(501, nice=c(5, 10)) # 1000
Tommy

1
Sadece bir uyarı Fonksiyonunuzda logaritma ile çalışmak beri, 2 vaka, biri vardı olurdu x < 0ve uygulamak - xkoymadan önce günlüğüne -geri. Ayrıca şu durum için bir istisna ekleyeceğimx = 0
Yohan Obadia

Güzel işlev ihtiyaçlarım için gerçekten iyi çalıştı (bir grafiğin X eksenine güzel bir sınır koymak için)
Joon

132

plyrKütüphane bir işlevi vardır round_anyyuvarlama her türlü yapmak oldukça geneldir. Örneğin

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

Bir İçin dplyrdeğiştirilmesi, bkz: stackoverflow.com/a/46489816/435093
slhck

46

R'deki yuvarlak işlevi, negatifse rakamlar parametresine özel bir anlam atar.

round (x, rakamlar = 0)

Negatif bir basamak sayısına yuvarlama, on üssüne yuvarlama anlamına gelir; bu nedenle, örneğin (x, rakamlar = -2) en yakın yüze yuvarlar.

Bu, aşağıdaki gibi bir işlevin istediğiniz şeye oldukça yaklaştığı anlamına gelir .

foo <- function(x)
{
    round(x+5,-1)
}

Çıktı aşağıdaki gibi görünür

foo(4)
[1] 10
foo(6.1)
[1] 10
foo(30.1)
[1] 40
foo(100.1)
[1] 110

2
Harika! Cevabınız doğru cevap olarak işaretlenmelidir!
Alessandro Jacopson

+1. Ancak @Alessandro benim fonksiyonlar cevap çok daha çok yönlüdür: Eğer tamamlayabilirler HERHANGİ sayıyı VEYA aşağı HERHANGİ aralık.
theforestecologist

@theforestecologist ipucu için teşekkür ederim! Kişisel bir zevk olarak, genellikle özel bir çözüm yerine yerleşik bir dilde yerleşik çözümü tercih ederim.
Alessandro Jacopson

27

Peki ya:

roundUp <- function(x,to=10)
{
  to*(x%/%to + as.logical(x%%to))
}

Hangi verir:

> roundUp(c(4,6.1,30.1,100.1))
[1]  10  10  40 110
> roundUp(4,5)
[1] 5
> roundUp(12,7)
[1] 14

1
@daroczig Soru biraz kafa karıştırıcı, bunu "keyfi X" gereksinimine odaklanarak yazdım, ancak açıkça tüm beklenen değerler "en yakın X'e kadar tek bir yuvarlama" çözümüyle üretilemezdi. Görünüşe göre OP bir eksen için değerler üretmek istiyor, bu yüzden prettymuhtemelen en iyi seçenek.
James

1
Belli ki bu partiye geç, ama daha to * ceiling(x / to)temiz olmaz mıydı ?
jared

27

Round () 'un basamak bağımsız değişkenine negatif bir sayı eklerseniz, R onu 10'un, 100'ün vb. Katlarına yuvarlar.

    round(9, digits = -1) 
    [1] 10    
    round(89, digits = -1) 
    [1] 90
    round(89, digits = -2) 
    [1] 100

17

HERHANGİ bir sayıyı HERHANGİ bir aralığa Yukarı / Aşağı yuvarlayın

Modulo operatörünü kullanarak sayıları kolayca belirli bir aralığa yuvarlayabilirsiniz %%.

İşlev:

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)
    }
  }
}

Örnekler:

> 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

Nasıl çalışır:

Modulo operatörü %%, ilk sayıyı 2.'ye bölmenin kalanını belirler. Bu aralığı ilgilendiğiniz sayıya eklemek veya çıkarmak, esasen sayıyı seçtiğiniz bir aralığa 'yuvarlayabilir'.

> 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

Güncelleme:

Kullanışlı 2 bağımsız değişkenli versiyon:

rounder <- function(x,y) {
  if(y >= 0) { x + (y - x %% y)}
  else { x - (x %% abs(y))}
}

Pozitif ydeğerler roundUp, negatif ydeğerler ise roundDown:

 # rounder(7, -4.5) = 4.5, while rounder(7, 4.5) = 9.

Veya....

Standart yuvarlama kurallarına göre otomatik olarak YUKARI veya AŞAĞI yuvarlayan işlev :

Round <- function(x,y) {
  if((y - x %% y) <= x %% y) { x + (y - x %% y)}
  else { x - (x %% y)}
}

xDeğer, >yuvarlama değerinin sonraki örnekleri arasında orta noktadaysa otomatik olarak yukarı yuvarlar 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

RoundExcel'de 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
VBA'ya

@Belki 4 yıl sonra sorduğumdan beri cevabımı söyleyip söylemediğinden emin değildim, ama sanırım cevabımı oldukça zarif ve ÇOK YÖNLÜ bulabilirsin. Umarım yardımcı olur!
theforestecologist

7

Rasgele bir sayının çokluğuna yuvarlama ile ilgili olarak , örneğin 10, burada James'in cevabına basit bir alternatif var.

Herhangi biri için Çalışıyor gerçek sayı (yuvarlanır ediliyor from) ve her türlü gerçek pozitif sayı (yuvarlanır to):

> RoundUp <- function(from,to) ceiling(from/to)*to

Misal:

> 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

2

Kodunuzun küçük bir değişiklikle harika çalıştığını düşünüyorum:

foo <- function(x, round=10) ceiling(max(x+10^-9)/round + 1/round)*round

Ve örnekleriniz:

> 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

İşlevini iki şekilde değiştirdim:

  • ikinci argüman eklendi (belirttiğiniz X için )
  • daha büyük bir sayı istiyorsanız =1e-09, küçük bir değer ( , değiştirmekten çekinmeyin!)max(x)

1

Her zaman bir sayıyı yuvarlamak istiyorsanız kadar yakın X'e kullanabileceğiniz ceilingişlevi:

#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

Benzer şekilde, her zaman aşağı yuvarlamak istiyorsanız , floorişlevi kullanın . En yakın Z'ye basitçe yukarı veya aşağı yuvarlamak istiyorsanız, roundbunun yerine kullanın.

> Z=5
> round(367.8/Z)*Z
[1] 370
> round(367.2/Z)*Z
[1] 365

0

Birkaç durumu hesaba katan Tommy'nin yanıtının yükseltilmiş bir versiyonunu bulacaksınız :

  • Alt veya üst sınır arasında seçim yapma
  • Negatif ve sıfır değerleri hesaba katmak
  • İşlevin küçük ve büyük sayıları farklı şekilde yuvarlamasını istiyorsanız, iki farklı güzel ölçek. Örnek: 4, 0'a yuvarlanırken, 400, 400'e yuvarlanır.

Kodun altında:

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)
    }
  }
}

Bunun varsayılan çıktısı aşağı yuvarlamadır:> round.up.nice(.01) [1] 0 > round.up.nice(4.5) [1] 0 > round.up.nice(56) [1] 50
jessi

Bence problemin bir kısmı şudur nice_bigve nice_smallgeriye doğru tanımlanır (onları işlevde çevirirsek round.up.nice(4.5)olur 4) ama yine de aşağı yuvarlanır.
jessi

0

Bunu herhangi bir harici kitaplık veya şifreli özellik kullanmadan denedim ve işe yarıyor!

Umarım birine yardımcı olur.

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.