Подтвердить что ты не робот

Как создать список фреймов данных?

Как создать список фреймов данных и как я могу получить доступ к каждому из этих фреймов данных из списка?

Например, как я могу поместить эти фреймы данных в список?

d1 <- data.frame(y1 = c(1, 2, 3),
                 y2 = c(4, 5, 6))
d2 <- data.frame(y1 = c(3, 2, 1),
                 y2 = c(6, 5, 4))
4b9b3361

Ответ 1

Это не связано с вашим вопросом, но вы хотите использовать =, а не <- в вызове функции. Если вы используете <-, вы создадите переменные y1 и y2 в любой среде, в которой вы работаете:

d1 <- data.frame(y1 <- c(1, 2, 3), y2 <- c(4, 5, 6))
y1
# [1] 1 2 3
y2
# [1] 4 5 6

Это не будет иметь желаемого эффекта создания имен столбцов в кадре данных:

d1
#   y1....c.1..2..3. y2....c.4..5..6.
# 1                1                4
# 2                2                5
# 3                3                6

Оператор =, с другой стороны, свяжет ваши векторы с аргументами с data.frame.

Что касается вашего вопроса, то сделать список кадров данных легко:

d1 <- data.frame(y1 = c(1, 2, 3), y2 = c(4, 5, 6))
d2 <- data.frame(y1 = c(3, 2, 1), y2 = c(6, 5, 4))
my.list <- list(d1, d2)

Вы получаете доступ к кадрам данных так же, как к любому другому элементу списка:

my.list[[1]]
#   y1 y2
# 1  1  4
# 2  2  5
# 3  3  6

Ответ 2

Другие ответы показывают, как составить список 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") это с помощью команды paste (например, 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 with merge (или какую-либо другую функцию соединения), чтобы собрать их вместе.

Зачем помещать данные в список?

Поместите аналогичные данные в списки, потому что вы хотите делать похожие вещи для каждого фрейма данных, и такие функции, как lapply, sapply do.call, пакет purrr и старые функции plyr l*ply plyr позволяют легко это сделать. Примеры людей, легко делающих вещи со списками, повсюду.

Даже если вы используете простой цикл for, гораздо проще зацикливать элементы списка, чем создавать имена переменных с помощью paste и обращаться к объектам с помощью метода get. Проще отлаживать тоже.

Подумайте о масштабируемости. Если вам действительно нужны только три переменные, то лучше использовать d1, d2, d3. Но тогда, если окажется, что вам действительно нужно 6, это намного больше печатать. И в следующий раз, когда вам понадобится 10 или 20, вы обнаружите, что копируете и вставляете строки кода, возможно, используя find/replace, чтобы изменить d14 на d15, и вы думаете, что программирование не должно быть таким. Если вы используете список, разница между 3 случаями, 30 случаями и 300 случаями составляет не более одной строки кода - никаких изменений, если ваше число случаев автоматически определяется, например, тем, сколько файлов .csv в вашем каталоге.

Вы можете назвать элементы списка, если вы хотите использовать что-то кроме числовых индексов для доступа к вашим фреймам данных (и вы можете использовать оба, это не выбор XOR).

В целом, использование списков приведет к написанию более чистого и удобного для чтения кода, что приведет к уменьшению количества ошибок и путанице.

Ответ 3

Вы также можете получить доступ к определенным столбцам и значениям в каждом элементе списка с помощью [ и [[. Вот несколько примеров. Во-первых, мы можем получить доступ только к первому столбцу каждого кадра данных в списке с помощью lapply(ldf, "[", 1), где 1 обозначает номер столбца.

ldf <- list(d1 = d1, d2 = d2)  ## create a named list of your data frames
lapply(ldf, "[", 1)
# $d1
#   y1
# 1  1
# 2  2
# 3  3
#
# $d2
#   y1
# 1  3
# 2  2
# 3  1

Аналогично, мы можем получить доступ к первому значению во втором столбце с помощью

lapply(ldf, "[", 1, 2)
# $d1
# [1] 4
# 
# $d2
# [1] 6

Затем мы также можем получить доступ к значениям столбца напрямую, как вектор, с помощью [[

lapply(ldf, "[[", 1)
# $d1
# [1] 1 2 3
#
# $d2
# [1] 3 2 1

Ответ 4

Если у вас есть большое количество последовательно названных фреймов данных, вы можете создать список нужного подмножества данных, например:

d1 <- data.frame(y1=c(1,2,3), y2=c(4,5,6))
d2 <- data.frame(y1=c(3,2,1), y2=c(6,5,4))
d3 <- data.frame(y1=c(6,5,4), y2=c(3,2,1))
d4 <- data.frame(y1=c(9,9,9), y2=c(8,8,8))

my.list <- list(d1, d2, d3, d4)
my.list

my.list2 <- lapply(paste('d', seq(2,4,1), sep=''), get)
my.list2

где my.list2 возвращает список, содержащий 2-й, 3-й и 4-й кадры данных.

[[1]]
  y1 y2
1  3  6
2  2  5
3  1  4

[[2]]
  y1 y2
1  6  3
2  5  2
3  4  1

[[3]]
  y1 y2
1  9  8
2  9  8
3  9  8

Обратите внимание, однако, что кадры данных в приведенном выше списке больше не называются. Если вы хотите создать список, содержащий подмножество кадров данных и хотите сохранить их имена, вы можете попробовать следующее:

list.function <-  function() { 

     d1 <- data.frame(y1=c(1,2,3), y2=c(4,5,6))
     d2 <- data.frame(y1=c(3,2,1), y2=c(6,5,4))
     d3 <- data.frame(y1=c(6,5,4), y2=c(3,2,1))
     d4 <- data.frame(y1=c(9,9,9), y2=c(8,8,8))

     sapply(paste('d', seq(2,4,1), sep=''), get, environment(), simplify = FALSE) 
} 

my.list3 <- list.function()
my.list3

который возвращает:

> my.list3
$d2
  y1 y2
1  3  6
2  2  5
3  1  4

$d3
  y1 y2
1  6  3
2  5  2
3  4  1

$d4
  y1 y2
1  9  8
2  9  8
3  9  8

> str(my.list3)
List of 3
 $ d2:'data.frame':     3 obs. of  2 variables:
  ..$ y1: num [1:3] 3 2 1
  ..$ y2: num [1:3] 6 5 4
 $ d3:'data.frame':     3 obs. of  2 variables:
  ..$ y1: num [1:3] 6 5 4
  ..$ y2: num [1:3] 3 2 1
 $ d4:'data.frame':     3 obs. of  2 variables:
  ..$ y1: num [1:3] 9 9 9
  ..$ y2: num [1:3] 8 8 8

> my.list3[[1]]
  y1 y2
1  3  6
2  2  5
3  1  4

> my.list3$d4
  y1 y2
1  9  8
2  9  8
3  9  8

Ответ 5

Принимая в качестве заданного, у вас есть "большое" количество data.frames с похожими именами (здесь d #, где # - некоторое положительное целое число), следующее небольшое улучшение метода @mark-miller. Это более краткий и возвращает именованный список data.frames, где каждое имя в списке является именем соответствующего исходного data.frame.

Ключ использует mget вместе с ls. Если кадры данных d1 и d2, заданные в вопросе, были единственными объектами с именами d # в среде, то

my.list <- mget(ls(pattern="^d[0-9]+"))

который вернется

my.list
$d1
  y1 y2
1  1  4
2  2  5
3  3  6

$d2
  y1 y2
1  3  6
2  2  5
3  1  4

Этот метод использует аргумент шаблона в ls, что позволяет использовать регулярные выражения для более точного анализа имен объектов в среде. Альтернативой регулярному выражению "^d[0-9]+$" является "^d\\d+$".

Как указывает @gregor, лучше всего настроить процесс построения данных, чтобы вначале кадры data.frames были помещены в именованные списки.

данные

d1 <- data.frame(y1 = c(1,2,3),y2 = c(4,5,6))
d2 <- data.frame(y1 = c(3,2,1),y2 = c(6,5,4))

Ответ 6

Это может быть немного поздно, но, возвращаясь к вашему примеру, я думал, что продюсирую ответ чуть-чуть.

 D1 <- data.frame(Y1=c(1,2,3), Y2=c(4,5,6))
 D2 <- data.frame(Y1=c(3,2,1), Y2=c(6,5,4))
 D3 <- data.frame(Y1=c(6,5,4), Y2=c(3,2,1))
 D4 <- data.frame(Y1=c(9,9,9), Y2=c(8,8,8))

Затем вы легко можете сделать свой список:

mylist <- list(D1,D2,D3,D4)

Теперь у вас есть список, но вместо доступа к списку используется старый способ, например

mylist[[1]] # to access 'd1'

эту функцию можно использовать для получения и назначения фрейма данных по вашему выбору.

GETDF_FROMLIST <- function(DF_LIST, ITEM_LOC){
   DF_SELECTED <- DF_LIST[[ITEM_LOC]]
   return(DF_SELECTED)
}

Теперь получите тот, который вы хотите.

D1 <- GETDF_FROMLIST(mylist, 1)
D2 <- GETDF_FROMLIST(mylist, 2)
D3 <- GETDF_FROMLIST(mylist, 3)
D4 <- GETDF_FROMLIST(mylist, 4)

Надеюсь, что дополнительный бит поможет.

Ура!

Ответ 7

Очень просто ! Вот мое предложение:

Если вы хотите выбрать dataframes в своей рабочей области, попробуйте следующее:

Filter(function(x) is.data.frame(get(x)) , ls())

или

ls()[sapply(ls(), function(x) is.data.frame(get(x)))]

все это даст тот же результат.

Вы можете изменить is.data.frame для проверки других типов переменных, таких как is.function