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))
}
}
CodePudding user response:
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 paste
ing 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
}