2013-05-09 15 views
9

ho un bisogno specifico di "trasformare" un numero in R. Per fare un esempio,numeri trasformandosi in R

A "piano" operazione si comportano come:

138 -> 100 
1233 -> 1000 

Un "tetto" operazione si comportano come:

138 -> 200 
1233 -> 2000 

Esiste un modo semplice per eseguire questa operazione in R? grazie

+0

sono i numeri che vanno a essere singolare? O c'è un vettore di numeri su cui pensi di farlo? –

+0

Che ne dici di questo? 'floor (x/10^(nchar (x) -1)) * 10^(nchar (x) -1)' – Arun

+0

cosa fai con i numeri negativi? o inferiore a 1, ad es. 1.2e-3? – baptiste

risposta

12

Si potrebbe estrarre l'esponente separatamente:

floorEx <- function(x) { 
    ex <- 10^trunc(log10(x)) 
    return(trunc(x/ex)*ex) 
} 

ceilingEx <- function(x) { 
    ex <- 10^trunc(log10(x)) 
    return(ceiling(x/ex)*ex) 
} 

Esempi:

floorEx(123) 
# [1] 100 

ceilingEx(123) 
# [1] 200 

ceilingEx(c(123, 1234, 12345)) 
# [1] 200 2000 20000 

EDIT:

  • utilizzando trunc invece di floor e integrare vecchio ex Funzione (ex <- function(x)floor(log10(x))) per velocizzare il calcolo un po '
  • aggiuntivo punto di riferimento per confrontare contro @ di Eddi floorR

punto di riferimento:

## provided by @eddi 
floorR <- function(x) {r <- signif(x, 1); r - (r > x) * 10^trunc(log10(x))} 

library("microbenchmark") 

x <- 123; microbenchmark(floorEx(x), floorR(x), signif(x), times=1e4) 
# Unit: nanoseconds 
#  expr min lq median  uq max neval 
# floorEx(x) 2182 2414 2521 2683.0 704190 10000 
# floorR(x) 2894 3150 3278 3505.5 22260 10000 
# signif(x) 372 472 507 556.0 10963 10000 

x <- 1:1000; microbenchmark(floorEx(x), floorR(x), signif(x), times=1e2) 
# Unit: microseconds 
#  expr  min  lq median  uq  max neval 
# floorEx(x) 100.560 101.2460 101.6945 115.6385 818.895 100 
# floorR(x) 354.848 355.4705 356.0420 375.9210 1074.582 100 
# signif(x) 114.608 115.2120 115.4695 119.1805 186.738 100 
+1

@ G.Grothendieck - Ma ciò darebbe risposte errate per, ad esempio, floorEx() con qualsiasi numero in 'c (750: 799, 851: 899, 950: 999)', tra molti altri ... –

+0

@Josh , Buon punto. Combina questa risposta con la risposta di Matteo invece e sostituisci la prima riga di ciascuna ... funzione Ex con 'expo <- nchar (x) - 1'. –

+0

@G.Grothendieck - Per la cronaca, ecco cosa avrei postato se non ci fossero già 4 risposte quando sono arrivato qui :) 'lx <- log10 (x); floor (10^(lx %% 1)) * 10^(lx% /% 1) '. –

8

non risponde direttamente alla tua domanda, ma si può anche dare un'occhiata a signif:

R> x <- 138 
R> signif(x,1) 
[1] 100 
R> x <- 1712 
R> signif(x,1) 
[1] 2000 
1

Ho giocato con regexing e il pavimento del soffitto fu nctions per ottenere questo:

ceil <- function(x) { 
    ceiling(as.numeric(sub("([[:digit:]])", "\\1.", x))) * (10^(nchar(x)-1)) 
} 

flr <- function(x) { 
    floor(as.numeric(sub("([[:digit:]])", "\\1.", x))) * (10^(nchar(x)-1)) 
} 


ceil(1233) 
ceil(138) 
flr(1233) 
flr(138) 


## > ceil(1233) 
## [1] 2000 
## > ceil(138) 
## [1] 200 
## > flr(1233) 
## [1] 1000 
## > flr(138) 
## [1] 100 
5

Un'altra opzione:

floor2 <- function(x) { 
    mag <- 10^(nchar(round(x))-1) 
    (x %/% mag) * mag 
} 

ceil2 <- function(x) { 
    mag <- 10^(nchar(round(x))-1) 
    ((x + mag) %/% mag) * mag 
} 
+0

Un buon approccio. Il mio preferito finora +1 –

1

Ecco un approccio diverso utilizzando @ suggerimento di Juba. Per ottenere da una risposta arrotondato al floor o ceil abbiamo semplicemente bisogno di correggere un po ':

floorR = function(x) { 
    rounded = signif(x, 1); 

    rounded - (rounded > x) * 10^trunc(log10(x)) 
} 

ceilR = function(x) { 
    rounded = signif(x, 1); 

    rounded + (rounded < x) * 10^trunc(log10(x)) 
} 

EDIT2: dopo vettorializzazione, le funzioni sono un po' più lento (vedere la storia di modifica per non vettorizzati le versioni). Sono ancora veloce per i piccoli vettori, ma non scala nonché di @ sgibb soluzione (in parte perché signif non scala molto bene):

x = 156; microbenchmark(floorEx(x), flr(x), floor2(x), signif(x), floorR(x), times = 10000) 
#Unit: nanoseconds 
#  expr min  lq median  uq  max neval 
# floorEx(x) 4008 8348 10018 12021 158934 10000 
#  flr(x) 84810 121204 135896 141571 6708248 10000 
# floor2(x) 32055 46078 51086 54091 360606 10000 
# signif(x)  0 1002 1336 1671 86813 10000 
# floorR(x) 3006 6679 8348 10017 207683 10000 

x = c(1:1000); microbenchmark(floorEx(x), signif(x), floorR(x), times = 100) 
#Unit: microseconds 
#  expr  min  lq median  uq  max neval 
# floorEx(x) 125.879 157.4315 158.934 161.4385 243.742 100 
# signif(x) 147.581 216.6975 217.365 220.5375 395.998 100 
# floorR(x) 252.758 360.6055 362.275 366.4485 619.373 100 
+0

Purtroppo il tuo 'floorR' non è vettorizzato (' floorR (c (123, 156)) # 100, 200'). Aggiungo una versione vettoriale del tuo 'floorR' alla mia risposta (per il confronto). – sgibb

+0

@sgibb true; nei vostri benchmark dovreste probabilmente modificare 'floorR' per usare' trunc', per rendere il confronto corretto – eddi

+0

Ho già cambiato 'floor' in' trunc' in 'floorR'. – sgibb

Problemi correlati