Home > Back-end >  More efficient way to re-assign or convert values?
More efficient way to re-assign or convert values?

Time:04-10

I have columns in R that looks similar to the one shown here:

Values     Type
----------------
  5.44     Good
 10.31     Bad
 25.09     Good
  4.22     Bad

I want to convert the 'Bad' values to negative, while keeping the 'Good' remain the same.

The end result looks like this:

Values   Type
--------------
  5.44   Good
-10.31   Bad
 25.09   Good
 -4.22   Bad

To achieve this, I've been doing this so far.

df$Values[df$Type=="Bad"] <- df$Values[df$Type=="Bad"]*(-1)

I was wondering if there was a better/more intuitive/more efficient way to do this.

Thanks!

CodePudding user response:

You could replace on a subset which is faster than ifelse (which is actually what you're doing):

rp <- dat$Type == 'Bad'
dat$Values[rp] <- -dat$Values[rp]
dat
#   Values Type
# 1   5.44 Good
# 2 -10.31  Bad
# 3  25.09 Good
# 4  -4.22  Bad

Microbenchmark:

dat <- dat[sample(nrow(dat), 1e6, replace=T), ]

> microbenchmark::microbenchmark(
    ifelse=dat$Values <- ifelse(dat$Type == 'Bad', -dat$Values, dat$Values),
    repl={
      rp <- dat$Type == 'Bad'
      dat$Values[rp] <- -dat$Values[rp]
    }, 
    repl2={
      rp <- dat$Type == 'Bad'
      dat$Values[rp] <- dat$Values[rp]*(-1)
    }, 
    times=100
  )
Unit: milliseconds
   expr      min       lq     mean   median        uq      max neval cld
 ifelse 41.82709 70.56517 91.43609 74.06420 102.21062 265.3104   100   b
   repl 21.93701 22.46768 38.71844 23.74447  50.53454 142.1708   100  a 
  repl2 21.91698 22.90829 41.39714 27.58037  51.81883 143.1500   100  a 

Data:

dat <- structure(list(Values = c(5.44, 10.31, 25.09, 4.22), Type = c("Good", 
"Bad", "Good", "Bad")), class = "data.frame", row.names = c(NA, 
-4L))

CodePudding user response:

Using data.table:

library(data.table)
setDT(df)[Type=='Bad', Values:=-Values]

CodePudding user response:

With dplyr

library(dplyr)
df <- df %>% mutate(Values = if_else(Type=="Bad", (-1)*Values, Values)))

CodePudding user response:

Many people find mutate from dplyr more intuitive.

The code below basically reads:

  1. Take df
  2. Change the column Values according to the following condition:
  3. If in a given row Type is "Bad", change the value.
  4. Otherwise, keep the same value.
  5. Assign this to df so you replace the old dataset.
df <- df |> dplyr::mutate(Values = ifelse(Type == "Bad", Values*(-1), Values))

CodePudding user response:

df$Values=ifelse(df$Type=="Bad",df$Values * -1, df$Values)
  •  Tags:  
  • r
  • Related