'More efficient way to re-assign or convert values?
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!
Solution 1:[1]
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))
Solution 2:[2]
Using data.table:
library(data.table)
setDT(df)[Type=='Bad', Values:=-Values]
Solution 3:[3]
With dplyr
library(dplyr)
df <- df %>% mutate(Values = if_else(Type=="Bad", (-1)*Values, Values)))
Solution 4:[4]
Many people find mutate from dplyr more intuitive.
The code below basically reads:
- Take
df - Change the column
Valuesaccording to the following condition: - If in a given row
Typeis "Bad", change the value. - Otherwise, keep the same value.
- Assign this to
dfso you replace the old dataset.
df <- df |> dplyr::mutate(Values = ifelse(Type == "Bad", Values*(-1), Values))
Solution 5:[5]
df$Values=ifelse(df$Type=="Bad",df$Values * -1, df$Values)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | jlhoward |
| Solution 3 | Valkyr |
| Solution 4 | Andrea M |
| Solution 5 | Martin Gal |
