Как составить список фреймов данных?
Как составить список фреймов данных и как получить доступ к каждому из этих фреймов данных из списка?
например, как я могу поместить эти фреймы данных в список ?
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 ответов:
это не связано с вашим вопросом, но вы хотите использовать
=
, а не<-
внутри вызова функции. Если вы используете<-
, вы будете в конечном итоге создание переменных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, вы можете также прочитать какая разница между
[[
и[
при доступе к элементам списка?.
списки с самого начала
никогда не создать
d1
d2
d3
, ... во-первых. Создать список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
,sapply
do.call
,thepurrr
пакета, и старыйplyr
l*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