2012-12-13 29 views
15

W Mathematicą jest polecenie Clip[x, {min, max}] co daje x do min<=x<=max, min do x<min ii max do x>max patrzwartości zaciskowe między minimalnej i maksymalnej dopuszczalnej wartości R

http://reference.wolfram.com/mathematica/ref/Clip.html (mirror)

Jaki byłby najszybszy sposób osiągnięcia tego w R? Idealnie powinno być funkcja, która jest listable i powinno działać idealnie na każdej pojedynczej wartości, wektor, macierz lub dataframe ...

okrzyki, Tom

Odpowiedz

17

Rcpp ma clamp dla tego:

cppFunction('NumericVector rcpp_clip(NumericVector x, double a, double b){ 
    return clamp(a, x, b) ; 
}') 

Oto szybki odniesienia pokazujący, jak wykonuje w stosunku do innych metod omówionych:

pmin_pmax_clip <- function(x, a, b) pmax(a, pmin(x, b)) 
ifelse_clip <- function(x, a, b) { 
    ifelse(x <= a, a, ifelse(x >= b, b, x)) 
} 
operations_clip <- function(x, a, b) { 
    a + (x-a > 0)*(x-a) - (x-b > 0)*(x-b) 
} 
x <- rnorm(10000) 
require(microbenchmark) 

microbenchmark( 
    pmin_pmax_clip(x, -2, 2), 
    rcpp_clip(x, -2, 2), 
    ifelse_clip(x, -2, 2), 
    operations_clip(x, -2, 2) 
) 
# Unit: microseconds 
#      expr  min  lq median  uq  max 
# 1  ifelse_clip(x, -2, 2) 2809.211 3812.7350 3911.461 4481.0790 43244.543 
# 2 operations_clip(x, -2, 2) 228.282 248.2500 266.605 1120.8855 40703.937 
# 3 pmin_pmax_clip(x, -2, 2) 260.630 284.0985 308.426 336.9280 1353.721 
# 4  rcpp_clip(x, -2, 2) 65.413 70.7120 84.568 92.2875 1097.039  
+0

Te czasy są bardzo rockin '. –

+0

Po prostu wklejenie linii kodu zaciskowego w sesji konsoli to oczywiście nie to, co zamierzałeś zrobić z dziewięcioma raperami. –

+0

Prawie. Zobacz moje użycie 'cppFunction' w mojej edycji. (ale potrzebujesz aktualnej wersji devel 'Rcpp', ponieważ' clamp' zostało poprawione od ostatniej wersji). –

7

Oto jedna funkcja, która będzie pracować dla obu wektorów i macierze.

myClip <- function(x, a, b) { 
    ifelse(x <= a, a, ifelse(x >= b, b, x)) 
} 

myClip(x = 0:10, a = 3,b = 7) 
# [1] 3 3 3 3 4 5 6 7 7 7 7 

myClip(x = matrix(1:12/10, ncol=4), a=.2, b=0.7) 
# myClip(x = matrix(1:12/10, ncol=4), a=.2, b=0.7) 
#  [,1] [,2] [,3] [,4] 
# [1,] 0.2 0.4 0.7 0.7 
# [2,] 0.2 0.5 0.7 0.7 
# [3,] 0.3 0.6 0.7 0.7 

A oto kolejny:

myClip2 <- function(x, a, b) { 
    a + (x-a > 0)*(x-a) - (x-b > 0)*(x-b) 
} 

myClip2(-10:10, 0, 4) 
# [1] 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 4 4 4 4 4 4 
+0

Świetne !! Dzięki wielkie!! Moja funkcja do tego była wolniejsza, ale działa dość szybko! –

+1

To powinno znajdować się w bibliotece podstawowej R! – smci

13

Oto metoda z zagnieżdżonego pmin i pmax ustalającego granice:

fenced.var <- pmax(LB, pmin(var, UB)) 

To będzie trudno znaleźć metodę, która jest szybsza. Zawinięte w funkcji, która domyślnie przedziale 3 i 7:

fence <- function(vec, UB=7, LB=3) pmax(LB, pmin(vec, UB)) 

> fence(1:10) 
[1] 3 3 3 4 5 6 7 7 7 7 
+0

słodki .......... –

+0

Bardzo elegancki - to świetnie! –

+0

Używam tego bardzo. Mam duży zbiór danych, który ma wiele zmiennych, które nie są realnie prawdziwe poniżej 0 i które powinny być rozsądnie ograniczone również w górnym końcu. Prawdziwą sztuczką jest pamiętanie, aby ustawić maksimum za pomocą 'pmin' i ustawić min za pomocą' pmax'. –