I have a dataframe that similar to this: (in fact, 16 in a for-loop)
head(data)
# A tibble: 1 x 4
AAA AAC AB AC
1 18 25 39 9
2 20 25 30 7
- I want to dinamically change all collumns names based on the columns’ original names, something like this (I’ve tried with
str_glue, but I get an error):
### I have a for-loop: (NOT WORKING) (this is a part of the loop)
assign(str_glue("df_{str_sub(data[i], 23, - 5)}"),
read.delim(data[i], sep = ",", header = T) %>%
mutate(ID = Participants,
str_glue("New_{str_sub(data[i], 23, - 5)}_AAA") = AAA,
str_glue("New_{str_sub(data[i], 23, - 5)}_AAB") = AAC,
str_glue("New_{str_sub(data[i], 23, - 5)}_AB") = AB,
str_glue("New_{str_sub(data[i], 23, - 5)}_AC") = AC)
- desired output:
### Note:
### depending on the index-i,
### str_glue("New_{str_sub(data[i], 23, - 5)}_AAA") will get me either 50,100 or 150
### desired output for i = 1
New_50_AAA New_50_AAC New_50_AB New_50_AC
1 18 25 39 9
2 20 25 30 7
-
I’m sure that there’s an elegant way to do that. I’ve seen some related posts, but none seemed to help me. Any ideas? Thanks 🙂
-
ps: If there’s also a way to dinamically repeat the original’s column name without repeating it with str_, that would be perfect, it would save me 4 lines
-
EDIT
The whole loop looks like this:
"data" is a list of 16 .txt files, each one is called "xxxxxxxxx_xx_50.txt", "xxxxxxxxx_xx_100.txt" (so on)
for (i in 1:length(data)) {
if (grepl("xxxxxxxxx_x1_.txt$", data[i])) {
assign(str_glue("df_narr{str_sub(data[i], 23, - 5)}"),
read.delim(data[i], sep = ",", header = T) %>%
mutate(ID = Participants,
str_glue("New_1{str_sub(data[i], 23, - 5)}_AAA") = AAA,
str_glue("New_1{str_sub(data[i], 23, - 5)}_AAB") = AAC,
str_glue("New_1{str_sub(data[i], 23, - 5)}_AB") = AB,
str_glue("New_1{str_sub(data[i], 23, - 5)}_AC") = AC) %>%
mutate_if(is.numeric, round, digits = 2))
} else if (grepl("xxxxxxxxx_x2_.txt$", data[i])) {
assign(str_glue("df_narr{str_sub(data[i], 23, - 5)}"),
read.delim(data[i], sep = ",", header = T) %>%
mutate(ID = Participants,
str_glue("New_2{str_sub(data[i], 23, - 5)}_AAA") = AAA,
str_glue("New_2{str_sub(data[i], 23, - 5)}_AAB") = AAC,
str_glue("New_2{str_sub(data[i], 23, - 5)}_AB") = AB,
str_glue("New_2{str_sub(data[i], 23, - 5)}_AC") = AC) %>%
mutate_if(is.numeric, round, digits = 2))
}
}
>Solution :
It is better to keep the datasets in a list and rename them – get the files in the folder with list.files, then extract the digits (\\d+ – one or more digits) before the .txt from the files (‘nm1’), loop over the files and the names extracted in Map, read the data and modify the column names by pasteing the ‘New_’, corresponding digits (‘nm’) and the original column names
files <- list.files(path = 'path/to/your/folder', pattern = "\\.txt$",
full.names = TRUE)
nm1 <- sub(".*_(\\d+)\\.txt", "\\1", basename(files))
lst1 <- Map(\(x, nm) {
tmp <- read.table(x)
num_cols <- sapply(tmp, is.numeric)
tmp[num_cols] <- lapply(tmp[num_cols], round, digits = 2)
cols_to_rename <- names(tmp) != "Participants"
names(tmp)[cols_to_rename] <- paste0("New_", nm, "_",
names(tmp)[cols_to_rename])
names(tmp)[!cols_to_rename] <- "ID"
tmp
}, files, nm1)
Or using tidyverse
library(dplyr)
library(readr)
library(purrr)
library(stringr)
lst2 <- imap(setNames(files, nm1), ~ {
nm <- .y
read_table(.x) %>%
rename_with(~ str_c("New_", nm, "_", .x), -Participants) %>%
mutate(across(where(is.numeric), round, digits = 2)) %>%
rename(ID = Participants)
})
or in a for loop
# for storing the output from the `for` loop
lst3 <- vector('list', length(files))
# loop over the sequence of files
for(i in seq_along(files)) {
tmp <- read.table(files[i])
cols_to_rename <- names(tmp) != "Participants"
names(tmp)[cols_to_rename] <- paste0("New_", nm1[i], "_",
names(tmp)[cols_to_rename])
names(tmp)[!cols_to_rename] <- "ID"
num_cols <- sapply(tmp, is.numeric)
tmp[num_cols] <- lapply(tmp[num_cols], round, digits = 2)
lst3[[i]] <- tmp
}