Reputation: 233
The data frame sg is as follwoing:
v1 v2 v3
A B C
B A B
C A A
I used a function
definition <- funciton(x){
if (x =='A') definition <- paste(x, ": MINIMUM_RED")
else if (x =='B') definition <- paste(x, ": PASSIVE_RED") ## Passive red (no green demand during red)
else if (x =='C') definition <- paste(x, ": RED_REQUEST") ## During red the group has a green demand
else if (x =='D') definition <- paste(x, ": RED_PRIORITY")
else if (x =='E') definition <- paste(x, ": RED_PRIVILEGE") ## During red possilbe to go green
else definition <- paste(x, ": RED_WAIT") ##
}
I want to use the function definition for every value in the data frame sg, so I used apply function:
sgdf <- apply(sg,2,defination)
The result is as following:
[,1] [,2] [,3]
[1,] "A : MINIMUM_RED" "B : PASSIVE_RED" "C : RED_REQUEST"
[2,] "B : MINIMUM_RED" "A : PASSIVE_RED" "B : RED_REQUEST"
[3,] "C : MINIMUM_RED" "A : PASSIVE_RED" "A : RED_REQUEST"
Obviously, the function only works on the first element in every column, is any way I can get the right definition of every value?
Upvotes: 2
Views: 379
Reputation: 22343
There are some better suggested solutions, but if you want to change your current code as little as possible, just adding a sapply
in your last line should work:
sgdf <- apply(sg, 2, sapply, definition)
Another possibility is to use match
with nomatch=6
as an indicator variable. This has the advantage over some of the suggestions that it also works for matrix entries that are not in A-E, i.e. the case of paste(x, ": RED_WAIT")
.
newvals <- c(": MINIMUM_RED", ": PASSIVE_RED", ": RED_REQUEST",
": RED_PRIORITY", ": RED_PRIVILEGE", ": RED_WAIT")
ind <- match(as.matrix(sg), c("A", "B", "C", "D", "E"), nomatch=6)
matrix(paste(as.matrix(sg), newvals[ind]), ncol = ncol(sg))
Upvotes: 3
Reputation: 99371
How about a switch
statement? They're nice and clean, and switch
is a .Primitive
definition <- function(data)
{
m <- as.matrix(data)
for(i in seq_along(m)){
if(m[i] %in% LETTERS[1:5]){
m[i] <- switch(m[i],
A = paste(m[i], ": MINIMUM_RED"),
B = paste(m[i], ": PASSIVE_RED"),
C = paste(m[i], ": RED_REQUEST"),
D = paste(m[i], ": RED_PRIORITY"),
E = paste(m[i], ": RED_PRIVILEGE")
)
} else {
m[i] = paste(m[i], ": RED_WAIT")
}
}
return(m)
}
The resulting matrix is
definition(dat)
# v1 v2 v3
# [1,] "A : MINIMUM_RED" "B : PASSIVE_RED" "C : RED_REQUEST"
# [2,] "B : PASSIVE_RED" "A : MINIMUM_RED" "B : PASSIVE_RED"
# [3,] "C : RED_REQUEST" "A : MINIMUM_RED" "A : MINIMUM_RED"
and dat
is
dat <-
structure(list(v1 = structure(1:3, .Label = c("A", "B", "C"), class = "factor"),
v2 = structure(c(2L, 1L, 1L), .Label = c("A", "B"), class = "factor"),
v3 = structure(c(3L, 2L, 1L), .Label = c("A", "B", "C"), class = "factor")), .Names = c("v1",
"v2", "v3"), class = "data.frame", row.names = c(NA, -3L))
Better yet, let's just vectorize it instead. Here's a new data frame with a few values that won't be matched
DF <- structure(list(v1 = structure(c(1L, 2L, 3L, 4L, 1L),
.Label = c("A", "B", "C", "F"), class = "factor"),
v2 = structure(c(2L, 1L, 1L, 3L, 4L), .Label = c("A", "B", "D", "E"), class = "factor"),
v3 = structure(c(3L, 2L, 1L, 4L, 5L), .Label = c("A", "B", "C", "G", "R"), class = "factor")),
.Names = c("v1", "v2", "v3"), row.names = c(NA, -5L), class = "data.frame")
> DF
# v1 v2 v3
# 1 A B C
# 2 B A B
# 3 C A A
# 4 F D G
# 5 A E R
And the replacement
> q <- c(": MINIMUM_RED", ": PASSIVE_RED", ": RED_REQUEST", ": RED_PRIORITY", ": RED_PRIVILEGE")
YES <- paste(LETTERS[1:5], q); NO <- "NA : RED_WAIT"
> m <- as.matrix(DF)
> for(i in seq(m)){ m[i] <- q[match(m[i], LETTERS[1:5])] }
> m[is.na(m)] <- NO
> m
# v1 v2 v3
# [1,] "A : MINIMUM_RED" "B : PASSIVE_RED" "C : RED_REQUEST"
# [2,] "B : PASSIVE_RED" "A : MINIMUM_RED" "B : PASSIVE_RED"
# [3,] "C : RED_REQUEST" "A : MINIMUM_RED" "A : MINIMUM_RED"
# [4,] "NA : RED_WAIT" "D : RED_PRIORITY" "NA : RED_WAIT"
# [5,] "A : MINIMUM_RED" "E : RED_PRIVILEGE" "NA : RED_WAIT"
Upvotes: 1
Reputation: 10263
You need to use the vectorized ifelse
in your function definition instead of if
and else
or use gsub
instead.
edit The following is the vectorized version for illustration, but I think the alterative answers by lookup are a much better solution. But this does illustrate that ifelse
is vectorized while if
is not.
definition <- function (x) {
y <-
ifelse(x =='A', "MINIMUM_RED",
ifelse(x =='B', "PASSIVE_RED",
ifelse(x =='C', "RED_REQUEST",
ifelse(x =='D', "RED_PRIORITY",
ifelse(x =='E', "RED_PRIVILEGE",
"RED_WAIT")))))
return(paste(x, ":", y))
}
x <- LETTERS[1:5]
definition(x)
#[1] "A : MINIMUM_RED" "B : PASSIVE_RED" "C : RED_REQUEST" "D : RED_PRIORITY"
#[5] "E : RED_PRIVILEGE"
Upvotes: 3
Reputation: 56249
Using lookup variables:
#dummy data
df <- read.table(text="v1 v2 v3
A B C
B A B
C A A ", header=TRUE)
#make lookup variables
ind <- c("A","B","C","D","E")
def <- paste0(ind,":",
c("MINIMUM_RED",
"PASSIVE_RED",
"RED_REQUEST",
"RED_PRIORITY",
"RED_PRIVILEGE"))
#result
sapply(df,function(i){def[order(i)]})
#output
# v1 v2 v3
# [1,] "A:MINIMUM_RED" "B:PASSIVE_RED" "C:RED_REQUEST"
# [2,] "B:PASSIVE_RED" "C:RED_REQUEST" "B:PASSIVE_RED"
# [3,] "C:RED_REQUEST" "A:MINIMUM_RED" "A:MINIMUM_RED"
Upvotes: 3
Reputation: 51680
You may just use a list to map each character to a definition.
For instance
sg <- data.frame(v1=c("A", "B", "C"),
v2=c("B", "A", "A"),
v3=c("C", "A", "A"))
defs <- list("A" = "MINIMUM_RED",
"B" = "PASSIVE_RED",
"C" = "RED_REQUEST",
"D" = "RED_PRIORITY",
"E" = "RED_PRIVILEGE")
# Convert the data frame in a matrix, so we can use it to index the list
tmp <- as.matrix(sg)
# note that paste works on vectors
res <- matrix(paste(tmp, defs[tmp]), ncol=ncol(tmp))
Resulting in:
[,1] [,2] [,3]
[1,] "A MINIMUM_RED" "B PASSIVE_RED" "C RED_REQUEST"
[2,] "B PASSIVE_RED" "A MINIMUM_RED" "A MINIMUM_RED"
[3,] "C RED_REQUEST" "A MINIMUM_RED" "A MINIMUM_RED"
Upvotes: 5