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:
- Take
df
- Change the column
Values
according to the following condition: - If in a given row
Type
is "Bad", change the value. - Otherwise, keep the same value.
- 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)