Home > OS >  How to round values based on rows in R?
How to round values based on rows in R?

Time:08-24

I'm wondering whether there is a clean way to round values differently based on row conditions. An example of the dataset I'm using is below where I want to round columns col1, col2, col3 and col4 based on var. For example, I want to round to 2 decimal places unless var equals var1|var2|var3 where I want to round to 3 decimal places instead. Is this doable? Thanks.

set.seed(10)

dat <- data.frame(      
  vel = rep(c("slo", "med", "fas"), each = 28),
  var = rep(paste0("var", 1:7), times = 12),
  col1 = rnorm(84, 0.03, 0.08),
  col2 = rnorm(84, 0.03, 0.08),
  col3 = rnorm(84, 0.03, 0.08),
  col4 = rnorm(84, 0.03, 0.08)     
)

CodePudding user response:

library(tidyverse) 

dat %>%
  rowwise() %>% 
  mutate(across(col1:col4, ~ case_when(
    var %in% c("var1", "var2", "var3") ~ round(.x, 3),
    TRUE ~ round(.x, 2)
  )))

# A tibble: 84 x 6
# Rowwise: 
   vel   var     col1   col2   col3   col4
   <chr> <chr>  <dbl>  <dbl>  <dbl>  <dbl>
 1 slo   var1   0.031  0.065  0.045 -0.087
 2 slo   var2   0.015  0.043 -0.085 -0.042
 3 slo   var3  -0.08   0.083 -0.061 -0.024
 4 slo   var4  -0.02   0.21   0      0.12 
 5 slo   var5   0.05  -0.06   0.04  -0.03 
 6 slo   var6   0.06   0.02   0.11  -0.06 
 7 slo   var7  -0.07   0     -0.02  -0.06 
 8 slo   var1   0.001  0.015  0.132 -0.051
 9 slo   var2  -0.1    0.036  0.048  0.063
10 slo   var3   0.009  0.122  0.005  0.068
# ... with 74 more rows

CodePudding user response:

Yes, the digits parameter is vectorized which makes this easy.

dat[, paste0(names(dat)[-(1:2)], "rounded")] <-
  lapply(dat[, -(1:2)], round, 
         digits = ifelse(dat$var %in% c("var1", "var2", "var3"), 3, 2))

CodePudding user response:

We can use across to specify all columns that starts_with the string "col" for rounding, and use ifelse to choose which row to round. Since the condition in each row is different, we need to include rowwise at the start of the piping chain.

library(dplyr)

dat %>% 
  rowwise() %>%  
  mutate(across(starts_with("col"), 
                ~ifelse(var %in% c("var1", "var2", "var3"), 
                        round(.x, digits = 3), 
                        round(.x, digits = 2)))) %>% 
  ungroup()

# A tibble: 84 × 6
   vel   var     col1   col2   col3   col4
   <chr> <chr>  <dbl>  <dbl>  <dbl>  <dbl>
 1 slo   var1   0.031  0.065  0.045 -0.087
 2 slo   var2   0.015  0.043 -0.085 -0.042
 3 slo   var3  -0.08   0.083 -0.061 -0.024
 4 slo   var4  -0.02   0.21   0      0.12 
 5 slo   var5   0.05  -0.06   0.04  -0.03 
 6 slo   var6   0.06   0.02   0.11  -0.06 
 7 slo   var7  -0.07   0     -0.02  -0.06 
 8 slo   var1   0.001  0.015  0.132 -0.051
 9 slo   var2  -0.1    0.036  0.048  0.063
10 slo   var3   0.009  0.122  0.005  0.068
# … with 74 more rows

CodePudding user response:

For this specific case

iii=dat$var %in% c("var1","var2","var3")
ccc=grepl("col",colnames(dat))

dat[iii,ccc]=round(dat[iii,ccc],3)
dat[!iii,ccc]=round(dat[!iii,ccc],2)
  • Related