2016-01-17 12 views
27

Dalla funzione di guida R: Si noti che per arrotondare un 5, è previsto che venga utilizzato lo standard IEC 60559, "andare alla cifra pari". Pertanto round(0.5) è 0 e round(-1.5) è -2.round ma .5 deve essere pavimentato

> round(0.5) 
[1] 0 
> round(1.5) 
[1] 2 
> round(2.5) 
[1] 2 
> round(3.5) 
[1] 4 
> round(4.5) 
[1] 4 

Ma ho bisogno di arrotondare tutti i valori che terminano con .5. Tutti gli altri valori devono essere arrotondati come fanno con la funzione round(). Esempio:

round(3.5) = 3 
round(8.6) = 9 
round(8.1) = 8 
round(4.5) = 4 

C'è un modo veloce per farlo?

+15

Perché non solo 'ceil (x - 0.5)'? –

+1

@DietrichEpp Sono venuto a fare la stessa domanda: sento che la tua domanda dovrebbe probabilmente essere una risposta :) –

+4

Possiamo eseguire il backup di un momento e chiedere ** perché ** vuoi farlo. Stai introducendo un bias nel tuo set di dati arrotondato. Qual è il problema a portata di mano e perché credi che richieda questo particolare trattamento? –

risposta

28

Per Dietrich di Epp, è possibile utilizzare la funzione ceiling() con un offset di ottenere un veloce, vettorializzare, soluzione corretta:

round_down <- function(x) ceiling(x - 0.5) 
round_down(seq(-2, 3, by = 0.5)) 
## [1] -2 -2 -1 -1 0 0 1 1 2 2 3 

Penso che questo sia più veloce e molto più semplice di molte delle altre soluzioni mostrate qui.

Come notato da Carl Witthoft, questo aggiunge molto più pregiudizi ai dati rispetto agli arrotondamenti semplici. Confronta:

mean(round_down(seq(-2, 3, by = 0.5))) 
## [1] 0.2727273 
mean(round(seq(-2, 3, by = 0.5))) 
## [1] 0.4545455 
mean(seq(-2, 3, by = 0.5)) 
## [1] 0.5 

Qual è l'applicazione per tale procedura di arrotondamento?

+2

Questo è di gran lunga il modo migliore per farlo. –

20

Verificare se la restante x %% 1 è uguale a .5 e poi piano o intorno ai numeri:

x <- seq(1, 3, 0.1) 
ifelse(x %% 1 == 0.5, floor(x), round(x)) 
> 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 
10

Questa funzione trovando elementi che hanno parte decimale uguale a 0.5, e l'aggiunta di un piccolo numero negativo a loro prima di arrotondare, assicurandosi che siano arrotondati verso il basso. (Si basa -. Innocuo ma in modo leggermente offuscato --- sul fatto che un vettore booleano in R sarà convertita in un vettore di 0 's e 1' s moltiplicata per un vettore numerico)

f <- function(x) { 
    round(x - .1*(x%%1 == .5)) 
} 

x <- c(0.5,1,1.5,2,2.5,2.01,2.99) 
f(x) 
[1] 0 1 1 2 2 2 3 
8

La funzione (senza golf) è molto semplice e controlla se i decimali che sono rimasti sono .5 o meno. In effetti si potrebbe facilmente renderlo più utile e prendere 0.5 come argomento:

nice.round <- function(x, myLimit = 0.5) { 
    bX <- x 
    intX <- as.integer(x) 
    decimals <- x%%intX 
    if(is.na(decimals)) { 
    decimals <- 0 
    } 
    if(decimals <= myLimit) { 
    x <- floor(x) 
    } else { 
    x <- round(x) 
    } 
    if (bX > 0.5 & bX < 1) { 
    x <- 1 
    } 
    return(x) 
} 

Test

Attualmente, questa funzione non funziona correttamente con valori compresi tra 0,5 e 1,0.

> nice.round(1.5) 
[1] 1 
> nice.round(1.6) 
[1] 2 
> nice.round(10000.624541) 
[1] 10001 
> nice.round(0.4) 
[1] 0 
> nice.round(0.6) 
[1] 1 
+1

"non golfed", questo dovrebbe essere un * male * cosa ?? – wchargin

+0

@WChargin Assolutamente no, stavo solo indicando che la funzione potrebbe essere resa più breve. – Konrad

+0

Ecco un'osservazione di @Kreuvf che si occupa di modificare questo post per commentare: "Attualmente questa funzione non funziona correttamente con valori compresi tra 0.5 e 1.0.' Nice.round (0.6) 'restituisce 0." – vard

14

mi unirò il circo troppo:

rndflr <- function(x) { 
    sel <- vapply(x - floor(x), function(y) isTRUE(all.equal(y, 0.5)), FUN.VALUE=logical(1)) 
    x[sel] <- floor(x[sel]) 
    x[!sel] <- round(x[!sel]) 
    x 
} 

rndflr(c(3.5,8.6,8.1,4.5)) 
#[1] 3 9 8 4 
commento
+1

+1 da parte mia. L'unica risposta usando 'all.equal()', che IMHO è il modo corretto di gestire tali situazioni. – RHertel

Problemi correlati