Новичок в использовании труб

Я новичок и пытаюсь найти наиболее эффективный способ изменить имя первого столбца для многих файлов CSV, которые я буду создавать. Создав файлы CSV, я загружаю их в R следующим образом:

data <- read.csv('filename.csv')

Я использовал функцию names() для изменения имени одного файла:

names(data)[1] <- 'Y'

Тем не менее, я хотел бы найти наиболее эффективный способ объединения/передачи этого изменения имени в read.csv, чтобы одно и то же изменение имени применялось ко всем файлам при их открытии. Я попытался написать «простую» функцию для этого:

addName <- function(data) {
  names(data)[1] <- 'Y'
  data
}

Однако я еще не до конца понимаю синтаксис написания функции и не могу заставить ее работать.


person Dodo    schedule 09.06.2021    source источник
comment
Попробуйте использовать функцию colnames, см. stackoverflow.com/questions/7531868/   -  person Peace Wang    schedule 09.06.2021
comment
Или функцию rename, см. stackoverflow.com/questions /35023375/   -  person Peace Wang    schedule 09.06.2021
comment
Вы разработали свою функцию addName, ожидая, что R будет передавать по ссылке? То есть вы ожидаете, что ваша функция будет мутировать существующий объект x, указанный в addName(x) в качестве аргумента для параметра data. Если это так, это не сработает: R передает по значению, а не по ссылке. Однако строка data <- addName(data) должна работать, как и data <- data %>% addName() с пакетом magrittr. Вы можете sapply использовать эту addName функцию в списке data.frame, подобно вашему объекту data, а затем сохранить список, который sapply вернет.   -  person Greg    schedule 09.06.2021


Ответы (2)


Примечание

Если вы ожидали, что ваша исходная функция addName изменит существующий объект следующим образом

x <- data.frame(Column_1 = c(1, 2, 3), Column_2 = c("a", "b", "c"))

# Try (unsuccessfully) to change title of "Column_1" to "Y" in x.
addName(x)

# Print x.
x

имейте в виду, что R передается по значению, а не по ссылке, поэтому сам x останется без изменений:

  Column_1 Column_2
1        1        a
2        2        b
3        3        c

Любая мутация будет достигнута путем перезаписи x возвращаемым значением функции.

x <- addName(x)

# Print x.
x

в этом случае само x было бы очевидно изменено:

  Y Column_2
1 1        a
2 2        b
3 3        c

Отвечать

Во всяком случае, вот решение, которое компактно включает каналы (%>% из magrittr пакет) и пользовательскую функцию. Обратите внимание, что без разрывов строк и комментариев, которые я добавил для ясности, это можно было бы сократить до всего нескольких строк кода.

# The dplyr package helps with easy renaming, and it includes the magrittr pipe.
library(dplyr)

# ...

filenames <- c("filename1.csv", "filename2.csv", "filename3.csv")

# A function to take a CSV filename and give back a renamed dataset taken from that file.
addName <- function(filename) {
  return(# Read in the named file as a data.frame.
         read.csv(file = filename) %>%
           # Take the resulting data.frame, and rename its first column as "Y";
           # quotes are optional, unless the name contains spaces: "My Column"
           # or `My Column` are needed then.
           dplyr::rename(Y = 1))
}

# Get a list of all the renamed datasets, as taken by addName() from each of the filenames.
all_files <- sapply(filenames, FUN = addName,
                    # Keep the list structure, in which each element is a
                    # data.frame.
                    simplify = FALSE,
                    # Name each list element by its filename, to help keep track.
                    USE.NAMES = TRUE)

На самом деле, вы можете легко rename указать любые нужные вам столбцы одним махом:

dplyr::rename(Y = 1, 'X' = 2, "Z" = 3, "Column 4" = 4, `Column 5` = 5)
person Greg    schedule 09.06.2021
comment
Грег, большое спасибо за помощь! То, что вы сначала описали о функции, не меняющей X, именно это и произошло. Спасибо также за ваши подробные и четкие комментарии, для новичка, такого как я, это оооочень полезно. Не могли бы вы уточнить, придется ли мне запускать функцию addName и sapply() каждый раз, когда я открываю один из 17 файлов, которые мне нужны, и что и как именно делает sapply()? В общем, у меня проблемы с пониманием того, как связать и организовать различные шаги, необходимые для получения желаемого результата. - person Dodo; 10.06.2021
comment
Привет @Додо! Вот что делает sapply. Предположим, у вас есть функция, которая принимает одиночное значение (my_fun <- function(x) {return(2*x)}) и возвращает (скажем) двойное значение этого значения. Предположим, у вас также есть вектор (my_vals <- c(1, 2, 3)) или список (my_vals <- list(1, 2, 3)) из нескольких значений. Вы можете легко выполнить my_fun(1), чтобы получить 2, my_fun(2), чтобы получить 4, и my_fun(3), чтобы получить 6. Но скажем, вам нужны все эти результаты одним махом! Затем sapply(my_vals, FUN = my_fun) применяет my_fun к каждому из этих значений в my_values, чтобы получить вектор (или список) результатов: 2 4 6. - person Greg; 10.06.2021
comment
Итак, в контексте моего ответа все, что вам нужно (@Dodo), — это вектор (или список) всех filenames, с которыми вы имеете дело. У вас есть функция addName, предназначенная для приема любого одного имени файла и возврата переименованного набора данных (data.frame), взятого из этого файла. Теперь все, что вам нужно сделать, это передать filenames и addName в одиночный оператор sapply, который перебирает все filenames, вызывает addName для каждого и помещает результаты (переименованный наборы данных) в общий список (в том же порядке, что и имена файлов). Мы сохраняем этот список (список data.frames) в переменной all_files. - person Greg; 10.06.2021

Это прочитает вектор имен файлов, изменит имя первого столбца каждого на Y и сохранит все файлы в списке.

filenames <- c("filename1.csv","filename2.csv")
addName <- function(filename) {
  data <- read.csv(filename)
  names(data)[1] <- 'Y'
  data
}
files <- list()
for (i in 1:length(filenames)) {
   files[[i]] <- addName(filenames[i])
}
person Baroque    schedule 09.06.2021
comment
Не могли бы вы заменить все после определения addName просто на files <- sapply(X = filenames, FUN = addName)? - person Greg; 09.06.2021
comment
Конечно, вы могли бы, это, вероятно, быстрее. Но я написал это так, так как OP упомянул, что они новички, и как новичок я нашел такой код более понятным. - person Baroque; 09.06.2021
comment
Спасибо за ваш ответ, Барокко, но мне довольно сложно следовать и понимать код с моими ограниченными навыками новичка. Я понимаю функциональную часть, но цикл for, с которым у меня раньше не было опыта, выходит за рамки моей головы. Я знаю, что цикл написан для циклического просмотра файлов, но я вообще не понимаю синтаксиса. Есть ли хороший источник обучения для начинающих, который вы могли бы порекомендовать для циклов? Кроме того, является ли цикл частью функции или отдельной? - person Dodo; 10.06.2021
comment
Привет @Додо! Определение функции заканчивается закрывающей фигурной скобкой addName <- function(filename) { ... }; поэтому addName() примет аргумент filename и вернет переименованный набор данных (data.frame), загруженный из этого файла. После этого все находится вне функции. Далее files <- list() создает список, который изначально пуст, но будет заполнен циклом. Цикл for проходит через каждое имя файла, от 1st до 2nd: на каждом шаге он добавляет текущий (ith) набор данных (полученный addName() из текущего ith имени файла) в качестве нового (ith) элемента в список. - person Greg; 10.06.2021