Другие ответы показать вам , как сделать список data.frames , когда вы уже имеете кучу data.frames, например, d1
, d2
, .... Имея последовательно именованные кадры данных является проблемой, и поместив их в список является Хорошее решение, но лучше всего избегать того, чтобы куча data.frames отсутствовала в списке .
Другие ответы дают много подробностей о том, как назначить фреймы данных элементам списка, получить к ним доступ и т. Д. Мы также рассмотрим это немного здесь, но главное - сказать , не ждите, пока у вас не появится куча data.frames
добавить их в список. Начните со списка.
В оставшейся части этого ответа будут рассмотрены некоторые распространенные случаи, когда у вас может возникнуть желание создать последовательные переменные, и будет показано, как переходить прямо к спискам. Если вы новичок в списках в R, вы можете также прочитать В чем разница между доступом к элементам списка [[
и [
доступом к ним? ,
Списки с самого начала
Никогда не создавай d1
d2
d3
... dn
во-первых. Создайте список d
с n
элементами.
Чтение нескольких файлов в список фреймов данных
Это делается довольно легко при чтении в файлах. Может быть, у вас есть файлы data1.csv, data2.csv, ...
в каталоге. Ваша цель - список вызываемых data.frames mydata
. Первое, что вам нужно, это вектор со всеми именами файлов. Вы можете построить это с пастой (например, my_files = paste0("data", 1:5, ".csv")
), но это, вероятно , проще в использовании , list.files
чтобы захватить все соответствующие файлы: my_files <- list.files(pattern = "\\.csv$")
. Вы можете использовать регулярные выражения для сопоставления файлов, узнайте больше о регулярных выражениях в других вопросах, если вам нужна помощь там. Таким образом, вы можете получить все файлы CSV, даже если они не следуют хорошей схеме именования. Или вы можете использовать более необычный шаблон регулярных выражений, если вам нужно выбрать определенные CSV-файлы из нескольких.
На этом этапе большинство начинающих R будут использовать for
цикл, и в этом нет ничего плохого, он работает просто отлично.
my_data <- list()
for (i in seq_along(my_files)) {
my_data[[i]] <- read.csv(file = my_files[i])
}
Более R-подобный способ сделать это с lapply
помощью ярлыка для выше
my_data <- lapply(my_files, read.csv)
Конечно, замените другую функцию импорта данных на read.csv
соответствующую. readr::read_csv
или data.table::fread
будет быстрее, или вам может потребоваться другая функция для файла другого типа.
В любом случае, удобно именовать элементы списка в соответствии с файлами
names(my_data) <- gsub("\\.csv$", "", my_files)
# or, if you prefer the consistent syntax of stringr
names(my_data) <- stringr::str_replace(my_files, pattern = ".csv", replacement = "")
Разделение фрейма данных на список фреймов данных
Это очень просто, базовая функция split()
делает это за вас. Вы можете разделить на столбец (или столбцы) данных, или на что угодно
mt_list = split(mtcars, f = mtcars$cyl)
# This gives a list of three data frames, one for each value of cyl
Это также хороший способ разбить фрейм данных на части для перекрестной проверки. Может быть, вы хотите разделить mtcars
на части обучения, тестирования и проверки.
groups = sample(c("train", "test", "validate"),
size = nrow(mtcars), replace = TRUE)
mt_split = split(mtcars, f = groups)
# and mt_split has appropriate names already!
Имитация списка фреймов данных
Может быть, вы имитируете данные, что-то вроде этого:
my_sim_data = data.frame(x = rnorm(50), y = rnorm(50))
Но кто делает только одну симуляцию? Вы хотите сделать это 100 раз, 1000 раз, больше! Но вам не нужно 10 000 фреймов данных в вашем рабочем пространстве. Используйте replicate
и поместите их в список:
sim_list = replicate(n = 10,
expr = {data.frame(x = rnorm(50), y = rnorm(50))},
simplify = F)
Особенно в этом случае вам следует также подумать, действительно ли вам нужны отдельные фреймы данных, или же сработал бы один фрейм данных со столбцом «группа»? Использование data.table
или dplyr
это довольно легко сделать "по группам" с фреймом данных.
Я не поместил свои данные в список :( Я сделаю это в следующий раз, но что мне теперь делать?
Если это нечетный ассортимент (что необычно), вы можете просто назначить их:
mylist <- list()
mylist[[1]] <- mtcars
mylist[[2]] <- data.frame(a = rnorm(50), b = runif(50))
...
Если у вас есть кадры данных с именем в виде рисунка, например, df1
, df2
, df3
и вы хотите их в списке, вы можете get
их , если вы можете написать регулярное выражение для имен. Что-то вроде
df_list = mget(ls(pattern = "df[0-9]"))
# this would match any object with "df" followed by a digit in its name
# you can test what objects will be got by just running the
ls(pattern = "df[0-9]")
# part and adjusting the pattern until it gets the right objects.
Обычно mget
используется для получения нескольких объектов и возврата их в именованный список. Его аналог get
используется для получения одного объекта и его возврата (не в списке).
Объединение списка фреймов данных в один фрейм данных
Обычной задачей является объединение списка фреймов данных в один большой фрейм данных. Если вы хотите разместить их друг над другом, вы должны использовать rbind
их пару, но для списка фреймов данных есть три хороших варианта:
# base option - slower but not extra dependencies
big_data = do.call(what = rbind, args = df_list)
# data table and dplyr have nice functions for this that
# - are much faster
# - add id columns to identify the source
# - fill in missing values if some data frames have more columns than others
# see their help pages for details
big_data = data.table::rbindlist(df_list)
big_data = dplyr::bind_rows(df_list)
(Аналогично, используя cbind
или dplyr::bind_cols
для столбцов.)
Чтобы объединить (объединить) список фреймов данных, вы можете увидеть эти ответы . Часто, идея заключается в том , чтобы использовать Reduce
с merge
(или какой - либо другой функцией соединения) , чтобы получить их вместе.
Зачем помещать данные в список?
Помещенный аналогичные данные в списках , потому что вы хотите делать подобные вещи для каждого кадра данных, а также функции , такие как lapply
, sapply
do.call
, пакет , и старые функции позволяют легко сделать это. Примеры людей, легко делающих вещи со списками, повсюду.purrr
plyr
l*ply
Даже если вы используете простой цикл for, гораздо проще зацикливать элементы списка, чем создавать имена переменных с помощью paste
и обращаться к объектам с помощью get
. Проще отлаживать тоже.
Подумайте о масштабируемости . Если вам действительно нужно только три переменные, это хорошо для использования d1
, d2
, d3
. Но тогда, если окажется, что вам действительно нужно 6, это намного больше печатать. И в следующий раз, когда вам понадобится 10 или 20, вы обнаружите, что копируете и вставляете строки кода, возможно, используете find / replace для перехода d14
на d15
, и вы думаете, что программирование не должно быть таким . Если вы используете список, разница между 3 случаями, 30 случаями и 300 случаями составляет не более одной строки кода - без изменений, если количество случаев автоматически определяется, например, по количеству .csv
файлов в вашем каталог.
Вы можете назвать элементы списка, если вы хотите использовать что-то кроме числовых индексов для доступа к вашим фреймам данных (и вы можете использовать оба, это не выбор XOR).
В целом, использование списков приведет к написанию более чистого и удобного для чтения кода, что приведет к уменьшению количества ошибок и путанице.
=
не<-
внутриdata.frame()
. При использовании<-
вы создаетеy1
иy2
в вашей глобальной среде, и ваш фрейм данных не то, что вы хотите, чтобы это было.