Al14
Al14

Reputation: 1814

Use apply to replace multiple values in a dataframe

I want to use apply to replace values in a dataframe, if >8 1 star, if >10 2 stars, if >12 3 stars, else NS.

mydata<-data.frame(A=1:10, B=3:12, C=5:14)
apply(mydata, 2, function(x) ifelse(x > 12, "***"|x > 10, "**"|x >= 8, "*"|x <8, "NS", x))

Upvotes: 1

Views: 2978

Answers (5)

Jilber Urbina
Jilber Urbina

Reputation: 61164

ifelse(mydata >= 8 & mydata <= 10, "*",
         ifelse(mydata > 10 & mydata <= 12, "**", 
                ifelse(mydata > 12, "***", "NS" )))
      A    B    C    
 [1,] "NS" "NS" "NS" 
 [2,] "NS" "NS" "NS" 
 [3,] "NS" "NS" "NS" 
 [4,] "NS" "NS" "*"  
 [5,] "NS" "NS" "*"  
 [6,] "NS" "*"  "*"  
 [7,] "NS" "*"  "**" 
 [8,] "*"  "*"  "**" 
 [9,] "*"  "**" "***"
[10,] "*"  "**" "***"

Upvotes: 2

divibisan
divibisan

Reputation: 12155

This is not a place you need to use apply, just select rows using bracket notation:

ns <- mydata < 8
s3 <- mydata > 12
s2 <- mydata > 10 & mydata <= 12
s1 <- mydata >= 8 & mydata <= 10

mydata[ns] <- 'NS'
mydata[s3] <- '***'
mydata[s2] <- '**'
mydata[s1] <- '*'

NOTE: the conditional statements have to be before the assignment because once you assign a character value to any cell in a column, that column is converted from numeric to character and future conditional statements will use lexicographic comparison (1 < a < b < c < A) rather than numeric comparison.

Upvotes: 4

Jaap
Jaap

Reputation: 83235

A tidyverse alternative with case_when:

mydata %>% 
  mutate_all(funs(case_when(. > 12 ~ '***',
                            . > 10 & . <= 12 ~ '**',
                            . >= 8 & . <= 10 ~ '*',
                            . < 8 ~ 'NS')))

which gives:

    A  B   C
1  NS NS  NS
2  NS NS  NS
3  NS NS  NS
4  NS NS   *
5  NS NS   *
6  NS  *   *
7  NS  *  **
8   *  *  **
9   * ** ***
10  * ** ***

Upvotes: 6

emilliman5
emilliman5

Reputation: 5956

You can use cut and set the labels:

mydata<-data.frame(A=1:10, B=3:12, C=5:14)
as.data.frame(lapply(mydata, function(x) cut(x, breaks = c(-Inf, 8, 10, 12, Inf), labels = c("NS","*","**","***"))))
# A  B   C
# 1  NS NS  NS
# 2  NS NS  NS
# 3  NS NS  NS
# 4  NS NS  NS
# 5  NS NS   *
# 6  NS NS   *
# 7  NS  *  **
# 8  NS  *  **
# 9   * ** ***
# 10  * ** ***

Upvotes: 3

Florian
Florian

Reputation: 25385

Note that to use nested ifelse statements, you need to put the next ifelse as the third argument (the else argument) in the parent ifelse. So you could try the following:

ifelse(mydata > 12, "***", ifelse(mydata >= 10, "**", ifelse(mydata >= 8, "*", "NS")))

Output:

      A    B    C    
 [1,] "NS" "NS" "NS" 
 [2,] "NS" "NS" "NS" 
 [3,] "NS" "NS" "NS" 
 [4,] "NS" "NS" "*"  
 [5,] "NS" "NS" "*"  
 [6,] "NS" "*"  "**" 
 [7,] "NS" "*"  "**" 
 [8,] "*"  "**" "**" 
 [9,] "*"  "**" "***"
[10,] "**" "**" "***"

Hope this helps!

Upvotes: 5

Related Questions