Loop through rows and change values when meeting a condition

Viewed 57

Sample data:

df <- data.frame(bucket = c("A", "B", "C", "D"),
                 apples = c("<4", "U", "22", "9"),
                 oranges = c("U", "<4", "15", "7"),
                 bananas = c("8", "6", "16", "<4"),
                 pears = c("U", "7", "<4", "10"))

My desired output:

  bucket apples oranges bananas pears
1      A     <4       U       8     U
2      B      U      <4       6     7
3      C     22       U      16    <4
4      D      9       U      <4    10

The idea is I am trying to replace the lowest number value with the letter "U" in each row. Also note I am treating the 'bucket column' as having non-unique rows.

However, there are a few exceptions to this;

  1. If the row has more than 1 instance of "<4", then don't change anything in the row.
  2. If the row already has at least 1 instance of "U", then don't change anything in the row.

What I have tried:

for(i in 1:nrow(df)){
  
  if(sum(df[i,] == "U") > 0 || sum(df[i,] == "<4") > 1){
    
    next
    
  } else {
    
    df <- df %>%
      rowwise() %>%
      mutate(across(everything(),
                    ~replace(.x, which.min(.x), "U")))
  }
}

As a primarily tidyverse user, I can't seem to understand how to use rowwise with mutate and across properly.

A tidyverse solution would be awesome, but will happily take other solutions.

1 Answers

A way is to convert to long, convert and go back to wide again, i.e.

library(dplyr)
library(tidyr)

df %>% 
 pivot_longer(-1) %>% 
 group_by(bucket) %>% 
 mutate(value1 = value, 
        U_Exists = any(value == 'U'), 
        value = as.numeric(value), 
        value = replace(value, which.min(value), 'U'), 
        value_final = ifelse(!U_Exists, value, value1), 
        value_final = replace(value_final, is.na(value_final), value1[is.na(value_final)])) %>% 
 select(-c(value, value1, U_Exists)) %>% 
 pivot_wider(names_from = name, values_from = value_final)

# A tibble: 4 x 5
# Groups:   bucket [4]
  bucket apples oranges bananas pears
  <chr>  <chr>  <chr>   <chr>   <chr>
1 A      <4     U       8       U    
2 B      U      <4      6       7    
3 C      22     U       16      <4   
4 D      9      U       <4      10   

NOTE: The (benign) warnings are due to the NAs we get when we convert to numeric.

Related