web-dev-qa-db-fra.com

Comment arrondir au 10 (ou au 100 ou au X) le plus proche?

J'écris une fonction pour tracer des données. J'aimerais spécifier un nombre rond de Nice pour l'axe des y max qui est supérieur au max de l'ensemble de données.

Plus précisément, j'aimerais une fonction foo qui effectue les opérations suivantes:

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

J'ai eu jusqu'à

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

arrondi au 10 le plus proche, mais cela ne fonctionne pas pour des intervalles d’arrondis arbitraires.

Y a-t-il une meilleure façon de faire cela en R?

69
Abe

Si vous voulez juste arrondir à la puissance 10 la plus proche, définissez simplement:

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

Cela fonctionne aussi quand x est un vecteur:

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

..mais si vous voulez arrondir à un numéro "Nice", vous devez d'abord définir ce qu'est un numéro "Nice". Ce qui suit nous permet de définir "Nice" en tant que vecteur avec des valeurs de base de Nice comprises entre 1 et 10. La valeur par défaut est définie sur les nombres pairs 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]]]]
}

Ce qui précède ne fonctionne pas lorsque x est un vecteur - trop tard dans la soirée pour le moment :)

> 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

[[MODIFIER]]

Si la question est de savoir comment arrondir à la valeur la plus proche spécifiée (telle que 10 ou 100), alors James réponse semble le plus approprié. Ma version vous permet de prendre n'importe quelle valeur et de l'arrondir automatiquement à une valeur raisonnablement "agréable". Quelques autres bons choix du vecteur "Nice" ci-dessus sont: 1:10, c(1,5,10), seq(1, 10, 0.1)

Si vous avez une plage de valeurs dans votre graphique, par exemple [3996.225, 40001.893], la méthode automatique doit tenir compte à la fois de la taille de la plage et de la magnitude des nombres. Et comme noté par Hadley , la fonction pretty() pourrait être ce que vous voulez.

57
Tommy

La bibliothèque plyr a une fonction round_any qui est assez générique pour effectuer toutes sortes d'arrondis. Par exemple

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
113
Ramnath

La fonction round dans R attribue une signification spéciale au paramètre digits s'il est négatif.

rond (x, chiffres = 0)

Arrondir à un nombre négatif de chiffres signifie arrondir à une puissance de dix; ainsi, par exemple, arrondir (x, chiffres = -2) arrondit à la centaine la plus proche. 

Cela signifie qu'une fonction comme celle-ci obtientassez prochede ce que vous demandez.

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

La sortie ressemble à la suivante

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

Que diriez-vous:

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

Qui donne:

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

Si vous ajoutez un nombre négatif à l'argument digits de round (), R l'arrondira aux multiples de 10, 100, etc. 

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

Arrondir TOUT chiffre Haut/Bas à TOUT intervalle 

Vous pouvez facilement arrondir les nombres à un intervalle spécifique à l’aide de opérateur modulo%%

La fonction:

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

Exemples:

> 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

Comment ça marche:

L'opérateur modulo %% détermine le reste de la division du premier nombre par le second. Ajouter ou soustraire cet intervalle à votre numéro d'intérêt peut essentiellement "arrondir" ce nombre à un intervalle de votre choix.

> 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

Mettre à jour:

La pratique version à 2 arguments: _

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

y positif roundUp, alors que y négatif roundDown:

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

Ou....

Fonction qui automatiquement arrondit UP ou DOWN selon les règles d'arrondi standard

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

Arrondit automatiquement si la valeur x est > à mi-chemin entre les instances suivantes de la valeur arrondie 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
9
theforestecologist

En ce qui concerne le arrondi à la multiplicité d’un nombre arbitraire, par ex. 10, voici une alternative simple à la réponse de James. 

Cela fonctionne pour tout nombre réel arrondi (from) et tout nombre réel positif arrondi à (to):

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

Exemple:

> 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
7
hannafrc

Je pense que votre code fonctionne très bien avec une petite modification:

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

Et vos exemples courent:

> 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

J'ai modifié votre fonction de deux manières:

  • deuxième argument ajouté (pour votreXspécifié)
  • ajouté une petite valeur (=1e-09, n'hésitez pas à modifier!) à la max(x) si vous voulez un plus grand nombre
1
daroczig

J'ai essayé cela sans utiliser aucune bibliothèque externe ou fonctionnalités cryptiques et cela fonctionne!

J'espère que ça aide quelqu'un.

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
0
Rahul Chawla

Si vous voulez toujours arrondir un nombre en haut au X le plus proche, vous pouvez utiliser la fonction 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

De même, si vous voulez toujours arrondir vers le bas, utilisez la fonction floor. Si vous voulez simplement arrondir au Z le plus proche, utilisez plutôt round.

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

Vous trouverez une version améliorée de La réponse de Tommy qui prend en compte plusieurs cas:

  • Choisir entre la limite inférieure ou supérieure
  • Prise en compte des valeurs négatives et nulles
  • deux échelles de Nice différentes au cas où vous voudriez que la fonction arrondisse différemment les petits et les grands nombres. Exemple: 4 serait arrondi à 0, tandis que 400 serait arrondi à 400.

En dessous du code:

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)
    }
  }
}
0
Yohan Obadia