2016-01-17 13 views
27

Z funkcji pomocy R: Należy zauważyć, że w przypadku zaokrąglania wartości 5 należy zastosować normę IEC 60559, "przejdź do parzystej cyfry". Zatem round(0.5) wynosi 0, a round(-1.5) wynosi -2.runda, ale .5 powinien być powleczony

> 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 

Ale potrzebuję, aby wszystkie wartości kończące się na .5 zostały zaokrąglone w dół. Wszystkie inne wartości powinny być zaokrąglone, ponieważ są wykonywane za pomocą funkcji round(). Przykład:

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

Czy istnieje szybki sposób na zrobienie tego?

+15

Dlaczego nie po prostu 'ceil (x - 0,5)'? –

+1

@DietrichEpp Przyszedłem, aby zadać to samo pytanie: Czuję, że twoje pytanie prawdopodobnie powinno być odpowiedzią :) –

+4

Czy możemy cofnąć chwilę i zapytać ** dlaczego ** chcesz to zrobić. Wprowadzasz odchylenie w swoim zaokrąglonym zbiorze danych. Jaki jest problem i dlaczego uważasz, że wymaga tego szczególnego traktowania? –

Odpowiedz

28

Per Dietricha EPP, można korzystać z funkcji ceiling() z offsetem, aby uzyskać szybki, wektorowy, prawidłowe rozwiązanie:

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 

Myślę, że jest to szybsze i znacznie prostsze niż wiele innych pokazanych tutaj rozwiązań.

Jak zauważył Carl Witthoft, powoduje to znacznie większe obciążenie danych niż proste zaokrąglanie. Porównaj:

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 

Jaki jest wniosek o taką procedurę zaokrąglania?

+2

To zdecydowanie najlepszy sposób na zrobienie tego. –

20

Sprawdź, czy pozostała część x %% 1 jest równa .5 a następnie podłoga lub okrągły numerami:

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

Funkcja ta działa poprzez znalezienie elementów, które mają część dziesiętną równą 0.5 i dodając małą liczbę ujemną do do nich przed zaokrągleniem, upewniając się, że zostaną zaokrąglone w dół. (Polega. - bez szkody, ale w nieco sposób ukrywane --- na tym, że logiczna wektora w R zostaną przekształcone do wektora 0 „S 1” s pomnożona przez wektor numerycznej)

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

Funkcja (bez gry w golfa) jest bardzo prosta i sprawdza, czy pozostały ułamki dziesiętne to .5 lub mniej. W efekcie można łatwo uczynić go bardziej użytecznym i wziąć 0.5 jako argument:

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

Testy

Obecnie ta funkcja nie działa prawidłowo z wartości pomiędzy 0,5 a 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

"nie gra w golfa" - czy to ma być * złe * coś? – wchargin

+0

@WChargin Absolutnie nie, ja tylko wskazałem, że funkcja może być łatwo skrócona. – Konrad

+0

Oto uwaga ze strony @Kreuvf, która bierze udział w edycji tego postu, aby skomentować: "Obecnie ta funkcja nie działa poprawnie z wartościami od 0,5 do 1,0.' Nice.round (0.6) 'zwraca 0." – vard

14

Dołączę do cyrku TOO:

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 
komentarz
+1

+1 ode mnie. Jedyną odpowiedzią przy użyciu 'all.equal()', której IMHO jest właściwym sposobem radzenia sobie w takich sytuacjach. – RHertel

Powiązane problemy