Reputation: 59
I'm trying to get the following function to work for windsorizing attributes but I can't get the if elseif working in a function. It gives the following error: "the condition has length > 1 and only the first element will be used". I'm hoping someone can suggest a solution or alternative.
Example:
x <- data.frame(runif(100, 0, 100))
colnames(x) <- "test"
WINSORIZE <- function(x){
WIN_MEAN <- mean(x)
WIN_SD <- sd(x)
WIN_UPPER <- sum(WIN_MEAN + (3 * WIN_SD))
WIN_LOWER <- sum(WIN_MEAN - (3 * WIN_SD))
if(x > WIN_UPPER){
WIN_UPPER
} else if (x < WIN_LOWER) {WIN_LOWER
} else x
}
WINSORIZE(x$test)
Upvotes: 0
Views: 1885
Reputation: 9865
Solution
Use R's immanent vectorized ability. Select by [
and change the value by <-
assignment.
This solution is very R
-ish:
winsorize <- function(x) {
m <- mean(x)
s <- sd(x)
u <- m + 3 * s
l <- m - 3 * s
x[ x > u ] <- u # select elements > u and assign to them u in situ
x[ x < l ] <- l # select elements < l and assign to them l in situ
x # return the resulting vector
}
And also this solution is very R
-ish with the already vectorized ifelse()
function:
winsorize <- function(x) {
m <- mean(x)
s <- sd(x)
u <- m + 3 * s
l <- m - 3 * s
ifelse( x > u, u, ifelse( x < l, l, x))
}
Solution with sapply()
Another possibility is to use sapply(x, ...)
to apply your if-else constructs on each element of x.
winsorize <- function(x){
m <- mean(x)
s <- sd(x)
upper <- m + 3 * s
lower <- m - 3 * s
# apply your if-else construct on each individual element (el) of x
# using `sapply()`
sapply(x, function(el) if(el > upper){
upper
} else if (el < lower) {
lower
} else {
el})
}
Or the same with ifelse()
:
winsorize <- function(x){
m <- mean(x)
s <- sd(x)
upper <- m + 3 * s
lower <- m - 3 * s
sapply(x, function(el)
ifelse(el > upper, upper, ifelse(el < lower, lower, el))
}
Solution with Vectorize()
Or make a function out of your if-else
construct, vectorize this function using Vectorize()
before you apply it on x
:
winsorize <- function(x){
m <- mean(x)
s <- sd(x)
upper <- m + 3 * s
lower <- m - 3 * s
# define function for one element
winsorize.one.element <- function(el) {
if(el > upper){ upper } else if (el < lower) { lower } else { el}
}
# Vectorize this function
winsorize.elements <- Vectorize(winsorize.one.element)
# Apply the vectorized function to the vector and return the result
winsorize.elements(x)
}
This winsorize.one.element
function can be written neater by ifelse
,
but although ifelse
is vectorized
Upvotes: 1