Jak zrobić listę ramek danych?

Jak zrobić listę ramek danych i jak uzyskać dostęp do każdej z tych ramek danych z listy?

Na przykład, jak Mogę umieścić te ramki danych na liście ?

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))
Author: Moody_Mudskipper, 2013-07-06

7 answers

Nie jest to związane z twoim pytaniem, ale chcesz użyć =, a nie <- wewnątrz wywołania funkcji. Jeśli użyjesz <-, W końcu stworzysz zmienne y1 i y2 w dowolnym środowisku, w którym pracujesz:

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

Nie będzie to miało pozornie pożądanego efektu tworzenia nazw kolumn w ramce danych:

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

Operator = z drugiej strony kojarzy Twoje wektory z argumentami do data.frame.

Jeśli chodzi o twoje pytanie, zrób listę ramki danych są proste:

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)

Uzyskujesz dostęp do ramek danych tak, jak uzyskasz dostęp do każdego innego elementu listy:

my.list[[1]]
#   y1 y2
# 1  1  4
# 2  2  5
# 3  3  6
 102
Author: Peyton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-11 01:30:56

Inne odpowiedzi pokazują Ci Jak zrobić listę danych.ramki, gdy masz już kilka danych.ramki, np., d1, d2, .... Posiadanie sekwencyjnie nazwanych ramek danych jest problemem, a umieszczenie ich na liście jest dobrym rozwiązaniem, ale najlepszą praktyką jest unikanie mnóstwa danych.ramki nie na liście w pierwszej kolejności.

Pozostałe odpowiedzi podają wiele szczegółów, jak przypisać ramki danych do elementów listy, uzyskać do nich dostęp itp. Zajmiemy się tym. to też trochę tutaj, ale głównym punktem jest powiedzieć nie czekaj, aż będziesz miał kilka data.frames, aby dodać je do listy. Zacznij od listy.

Jeśli są dziwnym asortymentem (co jest niezwykłe), możesz je po prostu przypisać:

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

Reszta tej odpowiedzi obejmie kilka typowych przypadków, w których możesz pokusić się o tworzenie zmiennych sekwencyjnych i pokazać, jak przejść od razu do list. Jeśli jesteś nowy w liście w R, Możesz również przeczytać Jaka jest różnica między [[ a [ w dostępie do elementów listy?.


Listy od początku

Nigdy nie twórz d1 d2 d3, ..., w pierwszej kolejności. Utwórz listę d z 3 elementami.

Odczyt wielu plików do listy ramek danych

Robi się to dość łatwo podczas czytania w plikach. Może masz pliki data1.csv, data2.csv, ... w katalogu. Twoim celem jest lista danych.ramki o nazwie mydata. Pierwsza rzecz, której potrzebujesz jest wektorem ze wszystkimi nazwami plików. Można to skonstruować za pomocą pasty (np. my_files = paste0("data", 1:5, ".csv")), ale prawdopodobnie łatwiej jest użyć list.files, aby pobrać wszystkie odpowiednie pliki: my_files <- list.files(pattern = "\\.csv$").

W tym momencie, większość początkujących R będzie używać for pętli, i nie ma w tym nic złego, to 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ć z lapply

my_data <- lapply(my_files, read.csv)

Tak czy inaczej, przydatne jest nazwanie elementów 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 lista ramek danych

To jest bardzo proste, funkcja podstawowa split() robi to za Ciebie. Można podzielić przez kolumnę (lub kolumny) danych lub przez cokolwiek innego, co chcesz
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 kawałki w celu weryfikacji krzyżowej. Może chcesz podzielić mtcars na części treningowe, testowe i walidacyjne.

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ś w tym stylu:

my_sim_data = data.frame(x = rnorm(50), y = rnorm(50))

Ale kto czy tylko jedna symulacja? Chcesz to zrobić 100 razy, 1000 razy, więcej! Ale ty nie chcesz 10 000 ramek danych w swojej przestrzeni roboczej. 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 należy również rozważyć, czy naprawdę potrzebujesz oddzielnych ramek danych, czy też pojedyncza ramka z kolumną "grupową" będzie działać równie dobrze? Używając data.table lub dplyr bardzo łatwo jest robić rzeczy" grupowo " do ramki danych.

Nie umieściłem swoich danych na liście : (będę następnym razem, ale co mogę teraz zrobić?

Jeśli masz ramki danych nazwane wzorem, np., df1, df2, df3, jeśli chcesz je umieścić na liście, możesz uzyskać je, jeśli możesz napisać Wyrażenie regularne, aby pasowało do nazw. 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.

Ogólnie rzecz biorąc, mget jest używany do pobierania wielu obiektów i zwracania ich w nazwanej liście. Jego odpowiednik get jest używany do uzyskania pojedynczego obiektu i zwrócenia go nie na liście.

Łączenie listy ramek danych w jedną ramka danych

Powszechnym zadaniem jest połączenie listy ramek danych w jedną dużą ramkę danych. Jeśli chcesz umieścić je na sobie, użyj rbind dla pary z nich, ale dla listy ramek danych tutaj 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
# 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)

(podobnie używając cbind lub dplyr::bind_cols dla kolumn.)

Aby połączyć (połączyć) listę ramek danych, możesz zobaczyć te odpowiedzi . Często chodzi o to, aby użyć Reduce Z merge (lub innej funkcji łączącej), aby je uzyskać razem.

Po co umieszczać dane na liście?

Umieszczaj podobne dane na listach, ponieważ chcesz zrobić podobne rzeczy dla każdej ramki danych, a funkcje takie jak lapply, sapply do.call, purrr pakiet , a stary plyr l*ply funkcje ułatwiają to. Przykłady ludzi, którzy łatwo robią rzeczy z listami są wszędzie.

Nawet jeśli używasz pętli lowly for, o wiele łatwiej jest zapętlić elementy listy niż konstruować nazwy zmiennych z paste i uzyskać dostęp do obiektów za pomocą get. Łatwiej też debugować.

Pomyśl o skalowalności . Jeśli naprawdę potrzebujesz tylko trzech zmiennych, dobrze jest użyć d1, d2, d3. Ale jeśli okaże się, że naprawdę potrzebujesz 6, to dużo więcej pisania. Następnym razem, gdy potrzebujesz 10 lub 20, znajdziesz się w kopiowaniu i wklejaniu wierszy kodu, może używając find / replace, aby zmienić d14 na d15, i myślisz tak nie powinno być programowanie. Jeśli używasz listy, różnica między 3 przypadkami, 30 przypadkami i 300 przypadkami to co najwyżej jedna linia kodu - - - nie zmienia się w ogóle, jeśli liczba przypadków jest automatycznie wykrywana przez, np. ile plików .csv znajduje się w Twoim katalogu.

Możesz nazwać elementy listy, jeśli chcesz użyć czegoś innego niż indeksy numeryczne, aby uzyskać dostęp do ramek danych (i możesz użyć obu, nie jest to wybór XOR).

Ogólnie rzecz biorąc, korzystanie z list doprowadzi Cię do napisania czystszego, łatwiejszego do odczytania kodu, który powoduje mniej błędów i mniej zamieszania.

 258
Author: Gregor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-23 03:24:56

Możesz również uzyskać dostęp do określonych kolumn i wartości w każdym elemencie listy za pomocą [ i [[. Oto kilka przykładów. Po pierwsze, możemy uzyskać dostęp tylko do pierwszej kolumny każdej ramki danych na liście za pomocą lapply(ldf, "[", 1), Gdzie 1 oznacza numer kolumny.

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

Podobnie, możemy uzyskać dostęp do pierwszej wartości w drugiej kolumnie za pomocą

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

Wtedy możemy również uzyskać dostęp do wartości kolumn bezpośrednio, jako wektor, z [[

lapply(ldf, "[[", 1)
# $d1
# [1] 1 2 3
#
# $d2
# [1] 3 2 1
 16
Author: Rich Scriven,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-15 00:02:15

Jeśli masz dużą liczbę sekwencyjnie nazwanych ramek danych, możesz utworzyć listę pożądanych podzbiorów ramek danych, takich jak:

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

Gdzie my.list2 zwraca listę zawierającą 2., 3. i 4. ramki danych.

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

Należy jednak pamiętać, że ramki danych z powyższej listy nie są już nazwane. Jeśli chcesz utworzyć listę zawierającą podzbiór ramek danych i chcesz zachować ich nazwy, możesz spróbować tego:

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

Które zwraca:

> 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
 12
Author: Mark Miller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-06 04:17:14

Biorąc pod uwagę, że masz "dużą" liczbę danych.ramki o podobnych nazwach (tutaj d # gdzie # jest jakąś dodatnią liczbą całkowitą), poniżej znajduje się nieznaczna poprawa metody @ mark-miller, ponieważ automatycznie zwraca ona nazwaną listę danych.ramki i jest bardziej zwięzły.

Klucz używa mget razem z ls. Jeśli ramki danych d1 i d2 podane w pytaniu były jedynymi obiektami o nazwie d# w środowisku, to

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

Które return

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

Ta metoda wykorzystuje argument wzorca w ls, który pozwala nam używać wyrażeń regularnych do dokładniejszego parsowania nazw obiektów w środowisku.

Jak wskazuje @ gregor , lepiej jest ogólnie skonfigurować proces budowy danych tak, aby dane.ramki są umieszczane na nazwanych listach na początku.

Dane

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))
 8
Author: lmo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:03

To może być trochę za późno, ale wracając do twojego przykładu, pomyślałem, że trochę poszerzę odpowiedź.

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

Potem łatwo tworzysz swoją listę:

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

Teraz masz listę, ale zamiast uzyskać dostęp do listy w stary sposób, taki jak

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

Możesz użyć tej funkcji, aby uzyskać i przypisać wybraną ramkę danych.

GETDF_FROMLIST <- function(DF_LIST, ITEM_LOC){
   DF_SELECTED <- DF_LIST[[ITEM_LOC]]
   return(DF_SELECTED)
}
A teraz weź to, co chcesz.
D1 <- GETDF_FROMLIST(mylist, 1)
D2 <- GETDF_FROMLIST(mylist, 2)
D3 <- GETDF_FROMLIST(mylist, 3)
D4 <- GETDF_FROMLIST(mylist, 4)
Mam nadzieję, że ten dodatkowy kawałek pomoże. Zdrówko!
 2
Author: ML_for_now,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-23 19:45:42

Bardzo proste ! Oto moja propozycja:

Jeśli chcesz wybrać ramki danych w obszarze roboczym, spróbuj tego :

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

Lub

ls()[sapply(ls(), function(x) is.data.frame(get(x)))]
Wszystko to da ten sam rezultat.

Możesz zmienić is.data.frame, aby sprawdzić inne typy zmiennych, takie jak is.function

 0
Author: CHAMI Soufiane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-22 11:16:22