Rename all columns except id column by adding a prefix using dplyr
Asked Answered
O

2

9

I have a dataframe with columns id, feature_1, feature_2, feature_3 as follows.

df = data.frame(
  id = sample(letters, 5),
  feature_1 = sample(1:10, 5),
  feature_2 = runif(5),
  feature_3 = rnorm(5)
)

I want to rename all the feature columns by adding a prefix. The following line doesn't work and output error.

df %>%
  rename_with(~(ifelse(names(.x) == "id", paste0("source_", names(.x)), "id")))

Error in names[cols] <- .fn(names[cols], ...) : 
  replacement has length zero

Any hint on how to modify this? What does .x represent inside rename_with? Thanks in advance!

Oozy answered 19/3, 2021 at 18:41 Comment(0)
H
19
library(dplyr)

df %>% 
  rename_with(~ paste0("source_", .), -id)

The third argument to rename_with is .cols, where you can use tidyselect syntax to select the columns. Here -id excludes this column.


Per the comments the . syntax is a cleaner/simpler style than an writing an anonymous function, but you could accomplish this equivalently as:

df %>% 
  rename_with(function(x) paste0("source_", x), -id)

# R >= 4.1.0
df %>% 
  rename_with(\(x) paste0("source_", x), -id)
Handfasting answered 19/3, 2021 at 18:48 Comment(5)
Thanks LMc! What does the dot represent inside rename_with? I notice some dplyr functions use dot and some others use .x. What are the differences between them?Oozy
The dot syntax refers to the column over which the function is being applied. Either . or .x will be recognized as this reference.Handfasting
For rename_with, it seems the dot represents the column name? If I change the command to df %>% rename_with(~(ifelse(.x == "id", paste0("source_", .x), "id"))), it doesn't work either.Oozy
In this specific function, but more generally that's what the dots represent. For example df %>% mutate(across(starts_with("feature"), ~ . + 1)) the dot does not represent the column name.Handfasting
Thanks LMc! For my purposes I needed to exclude multiple columns using column id, so here's the syntax in case others need it. df %>% rename_with(~ paste0("source_", .), .cols = -c(1:2,4))Galenism
A
1
names(df) <- paste0("Source_", names(df))

This is a model for the solution. To apply the modification to a subset of names, use indexing, as in

i <- grep("feature", names(df))
names(df)[i] <-  paste0("Source_", names(df)[i])

Here, i is an array of indexes of the names to modify. It doesn't matter how it's created, but grep is a great way to do so when the criterion is based on the name itself.

Autostrada answered 19/3, 2021 at 18:43 Comment(2)
Thanks whuber! I'm curious about the implementation in dplyr using pipe format r code and the functionality of .x passing inside rename_with function.Oozy
That seems like (at best) a roundabout way of doing something that is simple and directly supported in base R.Autostrada

© 2022 - 2024 — McMap. All rights reserved.