Pozostałe odpowiedzi pokazać wam jak zrobić listę data.frames kiedy już kilka data.frames, np d1
, d2
.... Mając nazwanych kolejno ramek danych jest problemem, a umieszczenie ich w wykazie jest to dobra poprawka, ale najlepszą praktyką jest unikanie posiadania wiązki danych. ramek nie ma na liście .
Inne odpowiedzi podają wiele szczegółów na temat przypisywania ramek danych elementom listy, uzyskiwania do nich dostępu itp. Omówimy to trochę tutaj, ale głównym punktem jest to, że nie czekaj, aż będziesz miał sporo data.frames
aby dodać je do listy. Zacznij od listy.
Pozostała część tej odpowiedzi obejmie niektóre typowe przypadki, w których możesz ulec pokusie, aby utworzyć sekwencyjne zmienne i pokazać, jak przejść bezpośrednio do list. Jeśli dopiero zaczynasz korzystać z list w R, możesz także przeczytać Jaka jest różnica między dostępem do elementów listy [[
a [
dostępem do nich? .
Listy od początku
Nigdy nie twórz d1
d2
d3
... ... dn
w pierwszej kolejności. Utwórz listę d
z n
elementami.
Odczytywanie wielu plików do listy ramek danych
Odbywa się to dość łatwo podczas wczytywania plików. Może masz pliki data1.csv, data2.csv, ...
w katalogu. Twoim celem jest lista nazwanych data.frames mydata
. Pierwszą rzeczą, której potrzebujesz, jest wektor ze wszystkimi nazwami plików. Można skonstruować ten pastą (np my_files = paste0("data", 1:5, ".csv")
), ale to chyba łatwiejsze w użyciu list.files
, aby pobrać wszystkie odpowiednie pliki: my_files <- list.files(pattern = "\\.csv$")
. Możesz użyć wyrażeń regularnych, aby dopasować pliki, przeczytaj więcej o wyrażeniach regularnych w innych pytaniach, jeśli potrzebujesz pomocy. W ten sposób możesz pobrać wszystkie pliki CSV, nawet jeśli nie są zgodne z dobrym schematem nazewnictwa. Lub możesz użyć bardziej wyszukanego wzorca wyrażenia regularnego, jeśli chcesz wybrać niektóre pliki CSV z kilku z nich.
W tym momencie większość początkujących R używa for
pętli i nie ma w tym nic złego, działa dobrze.
my_data <- list()
for (i in seq_along(my_files)) {
my_data[[i]] <- read.csv(file = my_files[i])
}
Bardziej podobny do R sposób to zrobić lapply
, co jest skrótem do powyższego
my_data <- lapply(my_files, read.csv)
Oczywiście zastąp odpowiednio inną funkcję importu danych read.csv
. readr::read_csv
lub data.table::fread
będzie szybszy, lub możesz potrzebować innej funkcji dla innego typu pliku.
Tak czy inaczej, warto nazwać elementy listy, aby pasowały do plików
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 = "")
Dzielenie ramki danych na listę ramek danych
Jest to bardzo łatwe, funkcja podstawowa split()
robi to za Ciebie. Możesz dzielić według kolumny (lub kolumn) danych lub według dowolnej innej opcji
mt_list = split(mtcars, f = mtcars$cyl)
# This gives a list of three data frames, one for each value of cyl
Jest to również dobry sposób na rozbicie ramki danych na części w celu weryfikacji krzyżowej. Może chcesz podzielić się mtcars
na części szkoleniowe, testowe i weryfikacyjne.
groups = sample(c("train", "test", "validate"),
size = nrow(mtcars), replace = TRUE)
mt_split = split(mtcars, f = groups)
# and mt_split has appropriate names already!
Symulowanie listy ramek danych
Może symulujesz dane, coś takiego:
my_sim_data = data.frame(x = rnorm(50), y = rnorm(50))
Ale kto wykonuje tylko jedną symulację? Chcesz to zrobić 100 razy, 1000 razy, więcej! Ale nie chcesz 10 000 ramek danych w swoim obszarze roboczym. Użyj replicate
i umieść je na liście:
sim_list = replicate(n = 10,
expr = {data.frame(x = rnorm(50), y = rnorm(50))},
simplify = F)
W tym przypadku szczególnie powinieneś rozważyć, czy naprawdę potrzebujesz osobnych ramek danych, czy też pojedyncza ramka danych z kolumną „grupową” równie dobrze by działała? Używanie data.table
lub dplyr
dość łatwo jest robić rzeczy „grupowo” w ramce danych.
Nie umieściłem moich danych na liście :( Będę następnym razem, ale co mogę teraz zrobić?
Jeśli są dziwnym asortymentem (co jest niezwykłe), możesz po prostu przypisać im:
mylist <- list()
mylist[[1]] <- mtcars
mylist[[2]] <- data.frame(a = rnorm(50), b = runif(50))
...
Jeśli masz ramek danych nazwanych we wzór, na przykład df1
, df2
, df3
, i chcesz je na liście, można get
je, jeśli możesz napisać wyrażenie regularne pasujące nazwy. Coś jak
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.
Zasadniczo mget
służy do pobierania wielu obiektów i zwracania ich na nazwaną listę. Jego odpowiednik get
służy do pobrania pojedynczego obiektu i zwrócenia go (nie na liście).
Łączenie listy ramek danych w jedną ramkę danych
Częstym zadaniem jest łączenie listy ramek danych w jedną dużą ramkę danych. Jeśli chcesz je ułożyć jeden na drugim, użyj ich rbind
dla pary, ale dla listy ramek danych są trzy dobre opcje:
# 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)
(Podobnie przy użyciu cbind
lub dplyr::bind_cols
dla kolumn.)
Aby scalić (dołączyć) listę ramek danych, możesz zobaczyć te odpowiedzi . Często chodzi o to, aby korzystać Reduce
z merge
(lub innej funkcji łączącej), aby je ze sobą.
Po co umieszczać dane na liście?
Umieścić podobne dane w listach, bo chcesz robić podobne rzeczy do każdej ramki danych, a funkcje takie jak lapply
, sapply
do.call
, opakowanie , a stare funkcje sprawiają, że łatwo to zrobić. Przykłady osób, które łatwo robią rzeczy z listami, są na SO.purrr
plyr
l*ply
Nawet jeśli używasz mało używanej pętli for, o wiele łatwiej jest zapętlać elementy listy niż konstruować nazwy zmiennych paste
i uzyskiwać do nich dostęp get
. Łatwiej też debugować.
Pomyśl o skalowalności . Jeśli naprawdę potrzebujesz tylko trzy zmienne, w porządku do użytku d1
, d2
, d3
. Ale jeśli okaże się, że naprawdę potrzebujesz 6, to dużo więcej pisania. Następnym razem, gdy będziesz potrzebować 10 lub 20, przekonasz się, że kopiujesz i wklejasz linie kodu, być może używasz funkcji znajdź / zamień, aby zmienić d14
na d15
, i myślisz, że nie tak powinno być programowanie . Jeśli używasz listy, różnica między 3 przypadkami, 30 przypadkami i 300 przypadkami wynosi co najwyżej jeden wiersz kodu --- bez zmian, jeśli liczba spraw jest automatycznie wykrywana np. Przez liczbę .csv
plików w twoim informator.
Możesz nazwać elementy listy, na wypadek gdybyś chciał użyć czegoś innego niż indeksy numeryczne, aby uzyskać dostęp do swoich ramek danych (i możesz użyć obu, nie jest to wybór XOR).
Ogólnie rzecz biorąc, używanie list doprowadzi Cię do napisania czystszego, łatwiejszego do odczytania kodu, co spowoduje mniej błędów i mniej zamieszania.
=
nie używaj w<-
środkudata.frame()
. Używając<-
tworzeniay1
iy2
w swoim globalnym środowisku, twoja ramka danych nie jest taka, jak chcesz.