Reputation: 730
Is there a cleaner way to compare my 3rd column of my dataframe and divide it accordingly by either 1000, 100 or 10? My code works but is there a better way to write this?
After dividing, I would like to assign it to either "Round to 1000" and so on.
df <- data.frame(y = c(1,2,3), y1 = c(2,3,4), y2 = c(1000, 100, 10))
df$Type <- 0
for (i in 1:nrow(df)){
if (df[i,3] %% 1000 == 0 ){
df[i,4] <- "Round to 1000"
} else if (df[i,3] %% 100 == 0){
df[i,4] <- "Round to 100"
} else if (df[i,3] %% 10 == 0){
df[i,4] <- "Round to 10"
} else {
df[i,4] <- "None"
}
}
Upvotes: 0
Views: 77
Reputation: 5456
Or:
df <- data.frame(y = c(1,2,3), y1 = c(2,3,4), y2 = c(1000, 100, 10))
txt <- c("Round to 1000", "Round to 100", "Round to 10", "None")
div <- c(1000, 100, 10, 1)
df$Type <- lapply(df$y2, function(x) {
txt[which.max(unlist(lapply(div, function(y) (x %% y) == 0)))]
})
#> df
#y y1 y2 Type
#1 1 2 1000 Round to 1000
#2 2 3 100 Round to 100
#3 3 4 10 Round to 10
Upvotes: 0
Reputation: 7832
From my experience, most nested if-else statements can be replaced by switch()
or dplyr::case_when()
:
library(dplyr)
df <- data.frame(
y = c(1, 2, 3, 5),
y1 = c(2, 3, 4, 5),
y2 = c(1000, 100, 10, 5)
)
df %>%
mutate(Type = case_when(
y2 %% 1000 == 0 ~ "Round to 1000",
y2 %% 100 == 0 ~ "Round to 100",
y2 %% 10 == 0 ~ "Round to 10",
TRUE ~ "NONE"
))
#> y y1 y2 Type
#> 1 1 2 1000 Round to 1000
#> 2 2 3 100 Round to 100
#> 3 3 4 10 Round to 10
#> 4 5 5 5 NONE
In my opinion, case_when()
can be written in a clean, readable way...
Upvotes: 3
Reputation: 37879
In these cases I usually go for sapply
. It helps because it outputs an atomic vector which can be inserted in your data.frame.
df$type <- sapply(df$y2, function(x) {
if (x %% 1000 == 0 ){
out <- "Round to 1000"
} else if (x %% 100 == 0){
out <- "Round to 100"
} else if (x %% 10 == 0){
out <- "Round to 10"
} else {
out <- "None"
}
out
})
Output
df
# y y1 y2 type
#1 1 2 1000 Round to 1000
#2 2 3 100 Round to 100
#3 3 4 10 Round to 10
Talking about best ways, the following using standard subsetting is an option.
df$type <- 'None'
for (i in c(10, 100, 1000)) {
df$type[df$y2 %% i == 0] <- paste('Round to', i)
}
Upvotes: 2