Renaming multiple columns with dplyr rename(across(
We can use rename_with
instead of rename
library(dplyr)
library(stringr)
data %>%
rename_with(~str_c("Last_", .), everything())
Reproducible example
data(iris)
head(iris) %>%
rename_with(~str_c("Last_", .), .cols = everything())
# Last_Sepal.Length Last_Sepal.Width Last_Petal.Length Last_Petal.Width Last_Species
#1 5.1 3.5 1.4 0.2 setosa
#2 4.9 3.0 1.4 0.2 setosa
#3 4.7 3.2 1.3 0.2 setosa
#4 4.6 3.1 1.5 0.2 setosa
#5 5.0 3.6 1.4 0.2 setosa
#6 5.4 3.9 1.7 0.4 setosa
According to ?rename
rename() changes the names of individual variables using new_name = old_name syntax; rename_with() renames columns using a function.
and in ?across
across() makes it easy to apply the same transformation to multiple
columns, allowing you to use select() semantics inside in summarise()
and mutate().
The description says its use within mutate/summarise
(and transmute
?), and no indication of usage with any other functions i.e. it would fail with select
Rename multiple columns by names
setnames
from the data.table
package will work on data.frame
s or data.table
s
library(data.table)
d <- data.frame(a=1:2,b=2:3,d=4:5)
setnames(d, old = c('a','d'), new = c('anew','dnew'))
d
# anew b dnew
# 1 1 2 4
# 2 2 3 5
Note that changes are made by reference, so no copying (even for data.frames!)
A quick way to rename multiple columns with unique names using dplyr
We can use !!!
with rename
by passing a named vector
library(dplyr)
library(stringr)
df1 <- df %>%
rename(!!! setNames(names(df)[-1], str_c(month.abb[1:4], 17)))
-output
df1
# A tibble: 2 x 5
# Product Jan17 Feb17 Mar17 Apr17
# <chr> <dbl> <dbl> <dbl> <dbl>
#1 Eggs 35.8 39.2 40.1 41.1
#2 Chicken 36.8 39.8 43.4 41.3
Or use rename_with
df %>%
rename_with(~str_c(month.abb[1:4], 17), -1)
If the column names should be converted to Date
formatted
nm1 <- format(as.Date(as.numeric(names(df)[-1]), origin = '1896-01-01'), '%b%y')
df %>%
rename_with(~ nm1, -1)
# A tibble: 2 x 5
# Product Jan17 Feb17 Mar17 Apr17
# <chr> <dbl> <dbl> <dbl> <dbl>
#1 Eggs 35.8 39.2 40.1 41.1
#2 Chicken 36.8 39.8 43.4 41.3
How can I keep old columns and rename new columns when using `mutate` with `across`
Use the .names
argument of across
across
names its outputs using the argument .names
, which is an argument passed to glue::glue()
. This is a string in which "{.col}"
and "{.fn}"
are replaced by the names of your columns (specified by .cols
) and functions (specified by .fns
)
The default value for .names
is NULL, which is equivalent to "{.col}"
. This means that every mutated column is assigned the same name its counterpart in .cols
, which effectively 'overwrites' these columns in the output.
To produce your desired table you would need to do:
require(dplyr)
#> Loading required package: dplyr
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
require(magrittr)
#> Loading required package: magrittr
set.seed(7337)
## Create arbitrary tibble
myTibble <- tibble(x = 1:10,
y = runif(10),
z = y * pi)
mutate(myTibble, across(everything(), multiply_by, 2, .names = "{.col}_double"))
#> # A tibble: 10 x 6
#> x y z x_double y_double z_double
#> <int> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 0.889 2.79 2 1.78 5.58
#> 2 2 0.329 1.03 4 0.658 2.07
#> 3 3 0.0527 0.165 6 0.105 0.331
#> 4 4 0.875 2.75 8 1.75 5.50
#> 5 5 0.666 2.09 10 1.33 4.19
#> 6 6 0.509 1.60 12 1.02 3.20
#> 7 7 0.598 1.88 14 1.20 3.75
#> 8 8 0.00397 0.0125 16 0.00794 0.0250
#> 9 9 0.0541 0.170 18 0.108 0.340
#> 10 10 0.868 2.73 20 1.74 5.45
Created on 2021-09-16 by the reprex package (v2.0.1)
In this way, you can use across
with .fns
and .names
to do quite a lot:
mutate(myTibble, across(everything(),
.fns = list(double = multiply_by, half = divide_by),
2,
.names = "{.col}_{.fn}"))
#> # A tibble: 10 x 9
#> x y z x_double x_half y_double y_half z_double z_half
#> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 0.889 2.79 2 0.5 1.78 0.444 5.58 1.40
#> 2 2 0.329 1.03 4 1 0.658 0.165 2.07 0.517
#> 3 3 0.0527 0.165 6 1.5 0.105 0.0263 0.331 0.0827
#> 4 4 0.875 2.75 8 2 1.75 0.437 5.50 1.37
#> 5 5 0.666 2.09 10 2.5 1.33 0.333 4.19 1.05
#> 6 6 0.509 1.60 12 3 1.02 0.255 3.20 0.800
#> 7 7 0.598 1.88 14 3.5 1.20 0.299 3.75 0.939
#> 8 8 0.00397 0.0125 16 4 0.00794 0.00199 0.0250 0.00624
#> 9 9 0.0541 0.170 18 4.5 0.108 0.0271 0.340 0.0850
#> 10 10 0.868 2.73 20 5 1.74 0.434 5.45 1.36
Renaming multiple columns from vector in dplyr chain
An option with rename_at
would be
df %>%
rename_at(vars(starts_with('old_name')), ~ new_names)
# A tibble: 1 x 6
# RID Var1 Var2 new_name1 new_name2 new_name3
# <dbl> <chr> <chr> <dbl> <dbl> <dbl>
#1 1.00 A B 4.00 8.00 20.0
But, it is possible to make a function that works with rename_if
by creating a logical index on the column names
df %>%
rename_if(grepl("^old_name", names(.)), ~ new_names)
# A tibble: 1 x 6
# RID Var1 Var2 new_name1 new_name2 new_name3
# <dbl> <chr> <chr> <dbl> <dbl> <dbl>
#1 1.00 A B 4.00 8.00 20.0
The rename_if
in general is checking at the values of the columns instead of the column names i.e.
new_names2 <- c('var1', 'var2')
df %>%
rename_if(is.character, ~ new_names2)
# A tibble: 1 x 6
# RID var1 var2 old_name1 old_name2 old_name3
# <dbl> <chr> <chr> <dbl> <dbl> <dbl>
#1 1.00 A B 4.00 8.00 20.0
R rename multiple columns with wildcard with rename_with()
We can use rename_all
with str_replace
library(dplyr)
library(stringr)
tbl2 <- tbl1 %>%
rename_all(~ str_replace_all(str_replace(., '^[^_]+_(.*)_(.)[^.]+$', "\\1\\2"), '_', "-"))
-output
tbl2
# A tibble: 0 x 3
# … with 3 variables: `BBB1-P1E` <dbl>, `BBB2-P2E` <dbl>, `BBB2-P3E` <dbl>
data
tbl1 <- structure(list(AAA_BBB1_P1_Elev = numeric(0), AAA_BBB2_P2_Elev = numeric(0),
AAA_BBB2_P3_Elev = numeric(0)), row.names = integer(0), class = c("tbl_df",
"tbl", "data.frame"))
How to rename all columns between two sets of columns in a dataframe using R?
You can try -
library(dplyr)
mtcars %>%
rename_with(~paste0(., '_Value'), -c(mpg:cyl, vs:carb)) %>%
head
# mpg cyl disp_Value hp_Value drat_Value wt_Value qsec_Value vs am gear carb
#Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
#Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
#Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
#Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
#Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
#Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
If you have other columns in the data and to rename the columns specifically between cyl
and vs
you can do -
start <- match('cyl', names(mtcars))
end <- match('vs', names(mtcars))
cols <- (start + 1):(end - 1)
names(mtcars)[cols] <- paste0(names(mtcars)[cols], '_Value')
Renaming multiple columns and gathering with dplyr in R
You could do it like this:
library(tidyverse)
df %>%
gather(measure, value, -a, -b) %>%
separate(measure, into = c("type", "year"), sep = "_") %>%
mutate(type = case_when(type == "tmp" ~ "temp", type == "pre" ~ "precip")) %>%
spread(type, value)
# a b year precip temp
# 1 1 2 2000 100 23
# 2 1 2 2001 103 22.1
# 3 1 2 2002 189 25
We first gather all of the data in long format, then we separate the year from the measurement, then we change the names of the measurements, and lastly we spread the data back to wide format.
Related Topics
Data.Table - Left Outer Join on Multiple Tables
Filled Contour Plot with R/Ggplot/Ggmap
How to Add Overlapping Histograms with Lattice
How to Create a Plot with Customized Points in R
Gap in Polar Time Plot - How to Connect Start and End Points in Geom_Line or Remove Blank Space
R: Ggplot2 Make Two Geom_Tile Plots Have Equal Height
Merge Records Over Time Interval
\Sexpr{} Special Latex Characters ($, &, %, # etc.) in .Rnw-File
Vectorised Rcpp Random Binomial Draws
Creating a Specific Sequence of Date/Times in R
Doing T.Test for Columns for Each Row in Data Set
Inserting Rows into Data Frame When Values Missing in Category
Glmulti and Liner Mixed Models
How to Set Different Scale Limits for Different Facets