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


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

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

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))
7 131

7 ответов:

это не связано с вашим вопросом, но вы хотите использовать =, а не <- внутри вызова функции. Если вы используете <-, вы будете в конечном итоге создание переменных 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

The = оператор, с другой стороны, будет связывать ваши векторы с аргументами 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

другие ответы показывают вам как чтобы составить список данных.кадры, когда вы уже есть куча данных.кадры, например,d1,d2, .... Наличие последовательно именованных фреймов данных является проблемой, и их размещение в списке является хорошим решением, но рекомендуется избегайте иметь кучу данных.кадры не в списке в первую очередь.

другие ответы дают много подробностей о том, как назначить фреймы данных для элементов списка, доступ к ним и т. д. Мы рассмотрим это немного здесь тоже, но Главное сказать не ждите, пока у вас есть куча data.frames, чтобы добавить их в список. Начните со списка.

если они странный ассортимент (что необычно), вы можете просто присвоить им:

mylist <- list()
mylist[[1]] <- mtcars
mylist[[2]] <- data.frame(a = rnorm(50), b = runif(50))
...

остальная часть этого ответа будет охватывать некоторые распространенные случаи, когда у вас может возникнуть соблазн создать последовательные переменные и показать вам, как перейти прямо к спискам. Если вы новичок в списках в R, вы можете также прочитать какая разница между [[ и [ при доступе к элементам списка?.


списки с самого начала

никогда не создать d1d2d3, ... во-первых. Создать список d С 3 элементами.

чтение нескольких файлов в список фреймов данных

это делается довольно легко при чтении файлов. Может быть, у вас есть файлы data1.csv, data2.csv, ... в каталоге. Ваша цель-это список данных.кадры под названием mydata. Первое, что вам нужно-это вектор со всеми именами файлов. Вы можете построить это с помощью вставки (например,my_files = paste0("data", 1:5, ".csv")), но это, вероятно, проще в использовании list.files чтобы захватить все соответствующие файлы: my_files <- list.files(pattern = "\.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)

в любом случае, это удобно, чтобы назвать элементы списка, чтобы соответствовать файлы

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 это довольно легко сделать вещи "по группе" для фрейма данных.

я не помещал свои данные в список :( я буду в следующий раз, но что я могу сделать сейчас?

если у вас есть фреймы данных, названные в шаблоне, например,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
# they will be faster and can also add id columns to identify
# which list item they came from. They can also fill in
# missing values if some data frames have more columns than others
big_data = data.table::rbindlist(df_list)
big_data = dplyr::bind_rows(df_list)

(аналогично, используя cbind или dplyr::bind_cols для столбцов.)

чтобы объединить (объединить) список фреймов данных, вы можете увидеть ответы. Часто, идея состоит в том, чтобы использовать Reduce С merge (или некоторая другая соединяя функция) для того чтобы получить их совместно.

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

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

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

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

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

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

вы также можете получить доступ к определенным столбцам и значения в каждом элементе списка с [ и [[. Вот несколько примеров. Во-первых, мы можем получить доступ только к первому столбцу каждого фрейма данных в списке с 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

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

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

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

ключ, используя 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

этот метод использует аргумент pattern в ls, что позволяет нам использовать регулярные выражения для более тонкого разбора имен объектов в среде.

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

сведения

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))

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

 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)

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

Ура!

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

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

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

или

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

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

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