Những câu trả lời khác chỉ cho bạn cách để tạo ra một danh sách các data.frames khi bạn đã có một loạt các data.frames, ví dụ d1
, d2
, .... Có tuần tự đặt tên khung dữ liệu là một vấn đề, và đặt chúng trong một danh sách là một sửa chữa tốt, nhưng thực hành tốt nhất là tránh có một loạt data.frames không có trong danh sách ở vị trí đầu tiên.
Các câu trả lời khác cung cấp nhiều chi tiết về cách gán khung dữ liệu cho danh sách các phần tử, truy cập chúng, v.v. Chúng tôi cũng sẽ đề cập một chút ở đây, nhưng Điểm chính là nói đừng đợi cho đến khi bạn có một bó data.frames
để thêm chúng vào danh sách. Bắt đầu với danh sách.
Phần còn lại của câu trả lời này sẽ bao gồm một số trường hợp phổ biến mà bạn có thể bị cám dỗ để tạo các biến liên tiếp và chỉ cho bạn cách đi thẳng vào danh sách. Nếu bạn chưa quen với danh sách trong R, bạn cũng có thể muốn đọc Sự khác biệt giữa [[
và [
trong việc truy cập các yếu tố của danh sách là gì? .
Danh sách từ đầu
Đừng bao giờ tạo d1
d2
d3
, ..., dn
ở nơi đầu tiên. Tạo một danh sách d
với n
các yếu tố.
Đọc nhiều tệp vào danh sách các khung dữ liệu
Điều này được thực hiện khá dễ dàng khi đọc trong tập tin. Có lẽ bạn đã có tập tin data1.csv, data2.csv, ...
trong một thư mục. Mục tiêu của bạn là một danh sách data.frames được gọi mydata
. Điều đầu tiên bạn cần là một vectơ với tất cả các tên tệp. Bạn có thể tạo cấu trúc này bằng dán (ví dụ my_files = paste0("data", 1:5, ".csv")
:), nhưng có lẽ dễ sử dụng hơn list.files
để lấy tất cả các tệp thích hợp : my_files <- list.files(pattern = "\\.csv$")
. Bạn có thể sử dụng biểu thức chính quy để khớp với các tệp, đọc thêm về biểu thức chính quy trong các câu hỏi khác nếu bạn cần trợ giúp ở đó. Bằng cách này, bạn có thể lấy tất cả các tệp CSV ngay cả khi chúng không tuân theo sơ đồ đặt tên đẹp. Hoặc bạn có thể sử dụng mẫu regex fancier nếu bạn cần chọn một số tệp CSV nhất định từ một loạt chúng.
Tại thời điểm này, hầu hết những người mới bắt đầu R sẽ sử dụng một for
vòng lặp và không có gì sai với điều đó, nó hoạt động tốt.
my_data <- list()
for (i in seq_along(my_files)) {
my_data[[i]] <- read.csv(file = my_files[i])
}
Một cách giống như R hơn để làm điều đó với lapply
, đó là một phím tắt cho ở trên
my_data <- lapply(my_files, read.csv)
Tất nhiên, thay thế chức năng nhập dữ liệu khác cho read.csv
phù hợp. readr::read_csv
hoặc data.table::fread
sẽ nhanh hơn hoặc bạn cũng có thể cần một chức năng khác cho một loại tệp khác.
Dù bằng cách nào, thật tiện lợi khi đặt tên cho các thành phần danh sách để khớp với các tệp
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 = "")
Chia khung dữ liệu thành danh sách khung dữ liệu
Điều này là siêu dễ dàng, chức năng cơ bản split()
làm điều đó cho bạn. Bạn có thể phân chia theo một cột (hoặc cột) của dữ liệu hoặc bởi bất kỳ thứ gì khác bạn muốn
mt_list = split(mtcars, f = mtcars$cyl)
# This gives a list of three data frames, one for each value of cyl
Đây cũng là một cách hay để chia khung dữ liệu thành nhiều phần để xác thực chéo. Có lẽ bạn muốn chia mtcars
thành các phần đào tạo, kiểm tra và xác nhận.
groups = sample(c("train", "test", "validate"),
size = nrow(mtcars), replace = TRUE)
mt_split = split(mtcars, f = groups)
# and mt_split has appropriate names already!
Mô phỏng danh sách các khung dữ liệu
Có thể bạn đang mô phỏng dữ liệu, đại loại như thế này:
my_sim_data = data.frame(x = rnorm(50), y = rnorm(50))
Nhưng ai chỉ làm một mô phỏng? Bạn muốn làm điều này 100 lần, 1000 lần, hơn thế nữa! Nhưng bạn không muốn 10.000 khung dữ liệu trong không gian làm việc của mình. Sử dụng replicate
và đặt chúng trong một danh sách:
sim_list = replicate(n = 10,
expr = {data.frame(x = rnorm(50), y = rnorm(50))},
simplify = F)
Trong trường hợp này đặc biệt, bạn cũng nên xem xét liệu bạn có thực sự cần các khung dữ liệu riêng biệt hay một khung dữ liệu duy nhất có cột "nhóm" có hoạt động tốt không? Sử dụng data.table
hoặc dplyr
khá dễ dàng để thực hiện mọi việc "theo nhóm" vào khung dữ liệu.
Tôi đã không đưa dữ liệu của mình vào danh sách :( Tôi sẽ có lần sau, nhưng tôi có thể làm gì bây giờ?
Nếu chúng là một loại kỳ lạ (không bình thường), bạn chỉ cần gán chúng:
mylist <- list()
mylist[[1]] <- mtcars
mylist[[2]] <- data.frame(a = rnorm(50), b = runif(50))
...
Nếu bạn có khung dữ liệu có tên trong một mô hình, ví dụ như, df1
, df2
, df3
, và bạn muốn họ trong một danh sách, bạn có thể get
cho họ nếu bạn có thể viết một biểu thức chính quy để phù hợp với tên. Cái gì đó như
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.
Nói chung, mget
được sử dụng để có được nhiều đối tượng và trả về chúng trong một danh sách được đặt tên. Bản sao của nó get
được sử dụng để lấy một đối tượng và trả về nó (không có trong danh sách).
Kết hợp danh sách các khung dữ liệu thành một khung dữ liệu
Một tác vụ chung là kết hợp một danh sách các khung dữ liệu thành một khung dữ liệu lớn. Nếu bạn muốn xếp chồng chúng lên nhau, bạn sẽ sử dụng rbind
cho một cặp trong số chúng, nhưng đối với một danh sách các khung dữ liệu, đây là ba lựa chọn tốt:
# 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)
(Tương tự sử dụng cbind
hoặc dplyr::bind_cols
cho các cột.)
Để hợp nhất (tham gia) một danh sách các khung dữ liệu, bạn có thể xem các câu trả lời này . Thông thường, ý tưởng là sử dụng Reduce
với merge
(hoặc một số chức năng nối khác) để kết hợp chúng lại với nhau.
Tại sao phải đưa dữ liệu vào danh sách?
Đưa dữ liệu tương tự trong danh sách bởi vì bạn muốn làm điều tương tự cho mỗi khung dữ liệu, và các chức năng như lapply
, sapply
do.call
, các purrr
gói , và người già plyr
l*ply
chức năng làm cho nó dễ dàng để làm điều đó. Ví dụ về những người dễ dàng làm mọi thứ với danh sách đều trên SO.
Ngay cả khi bạn sử dụng vòng lặp thấp cho vòng lặp, việc lặp lại các phần tử của danh sách sẽ dễ dàng hơn nhiều so với việc xây dựng các tên biến với paste
và truy cập các đối tượng get
. Dễ dàng hơn để gỡ lỗi, quá.
Hãy nghĩ về khả năng mở rộng . Nếu bạn thực sự chỉ cần ba biến, đó là tốt để sử dụng d1
, d2
, d3
. Nhưng sau đó, nếu bạn thực sự cần 6, thì đó là cách gõ nhiều hơn. Và thời gian tiếp theo, khi bạn cần 10 hoặc 20, bạn thấy mình sao chép và dán dòng mã, có thể sử dụng tìm / thay thế để thay đổi d14
để d15
, và bạn đang nghĩ đây không phải là cách lập trình nên . Nếu bạn sử dụng một danh sách, sự khác biệt giữa 3 trường hợp, 30 trường hợp và 300 trường hợp nhiều nhất là một dòng mã --- không thay đổi gì nếu số trường hợp của bạn được tự động phát hiện bởi, ví dụ: có bao nhiêu .csv
tệp trong bạn danh mục.
Bạn có thể đặt tên cho các thành phần của danh sách, trong trường hợp bạn muốn sử dụng thứ gì đó ngoài chỉ số số để truy cập khung dữ liệu của mình (và bạn có thể sử dụng cả hai, đây không phải là lựa chọn XOR).
Nhìn chung, việc sử dụng danh sách sẽ dẫn bạn viết mã sạch hơn, dễ đọc hơn, điều này sẽ dẫn đến ít lỗi hơn và ít nhầm lẫn hơn.
=
không<-
bên trongdata.frame()
. Bằng cách sử dụng<-
bạn tạoy1
vày2
trong môi trường toàn cầu của bạn và khung dữ liệu của bạn không phải là những gì bạn muốn.