2

I have a df that looks like this:

Name No1 No2 No 3
Jack 10 20 30
Eli 10 20 30
Mae 10 20 30
Jack 10 20 30

I want to multiply all values by a factor of 10 in columns 2:4 (so all columns excluding the Name column) and I only want to select rows where Name == Jack.

so, my final data table should look like this:

Name No1 No2 No 3
Jack 100 200 300
Eli 10 20 30
Mae 10 20 30
Jack 100 200 300

I've tried various iterations of the following:

df %>% 
         filter(Name == "Jack") %>% 
         select(No1:No3) %>%
         df*10

including

df %>% 
         filter(Name == "Jack") %>% 
         df[2:4]*10

and I've also tried and if statement:

new_df <- if(df$name == "Jack"){
          df[2:4]*10}
Brenda Thompson
  • 327
  • 2
  • 9

1 Answers1

2

We may use across to loop over the columns that starts with 'No', then create a logical condition based on the 'Name' column, use either ifelse/if_else or case_when to do the change based on the logic

library(dplyr)
df <- df %>% 
  mutate(across(c(No1, No2, No3),
    ~ case_when(Name == "Jack" ~ .x * 10, TRUE ~ as.numeric(.x))))

It can be passed as an index as well

df %>%
    mutate(across(c(2, 3, 4), # or if it is a range 2:4
        ~ case_when(Name == "Jack" ~ .x * 10, TRUE ~ as.numeric(.x))))

Or in base R, subset the columns and the rows (based on the logic), and assign back after multiplying with 10

df[df$Name == "Jack", -1] <- df[df$Name == "Jack", -1] * 10

data

df <- structure(list(Name = c("Jack", "Eli", "Mae", "Jack"), No1 = c(10L, 
10L, 10L, 10L), No2 = c(20L, 20L, 20L, 20L), No3 = c(30L, 30L, 
30L, 30L)), class = "data.frame", row.names = c(NA, -4L))
akrun
  • 874,273
  • 37
  • 540
  • 662
  • when I use the base R solution I get : `Error in FUN(left, right) : non-numeric argument to binary operator`. also I can't use your first solution where the mutation searches for columns that start with `NO` because in my actual dataset the columns do not have common characters, sorry about that. – Brenda Thompson Mar 31 '22 at 21:45
  • 1
    @BrendaThompson you can specify the column index or column names as `across(c(No1, No2, No3),..` In the second solution, I assumed that there are only 4 columns, and it is the first column you don't want to change i.e. why i used `-1`. You can pass a vector of column names as `df[df$Name == "Jack", c("No1", "No2", "No3")]` or whatever your column names are – akrun Mar 31 '22 at 21:48
  • so using your first solution and selecting my columns using `across(df[3:11])` I get ` Error in UseMethod("mutate") : no applicable method for mutate applied to an object of class NULL ` – Brenda Thompson Mar 31 '22 at 21:52
  • 1
    @BrendaThompson I already showed the syntax `across(3:11` or `across(c(3, 4, 5, 6, 7, 8, 9, 10, 11)` or `across(all_of(names(df)[3:11])` – akrun Mar 31 '22 at 21:57
  • okay got it I thought i needed a closing bracket after `(3:11`. – Brenda Thompson Mar 31 '22 at 22:02
  • 1
    @BrendaThompson the You can add the closing bracket but, it shouldn't close out the `across` i.e. `across(c(3:11), ....` is okay, but `across(3:11)` will close out the `across` without doing any operation – akrun Mar 31 '22 at 22:06