Veri çerçevelerinin listesini nasıl yapabilirim?


186

Veri çerçevelerinin listesini nasıl oluştururum ve bu veri çerçevelerinin her birine listeden nasıl erişirim?

Örneğin, bu veri çerçevelerini nasıl listeye ekleyebilirim?

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

13
Bu birkaç cevapta, ama burada da görünür bir yorum =yapmaya değer: <-içeride değil kullanın data.frame(). Kullanarak <-oluşturup y1ve y2global çevre ve veri çerçeve içinde siz olmak istediğini değil.
Gregor Thomas

37
<-Data.frame () içinde boşluk ve boşluk bulunmayan kod karmaşasına bakın . Ne kadar yeniydim.
Ben

5
Artık değil. Kod biçimlendirmesini düzeltmek için sorunuzu yeni düzenledim. Eğer nostaljik hissediyorsanız geri dönmekten çekinmeyin.
Claus Wilke

Yanıtlar:


133

Bu soruya ilişkin, ama kullanmak istediğiniz değildir =ve <-işlev çağrısı içinde. Kullanırsanız <-, değişkenler yaratırsınız y1ve y2hangi ortamda çalışıyorsanız kullanın:

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

Bu, veri çerçevesinde sütun adları oluşturma gibi istenen bir etkiye sahip olmayacaktır:

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

=Operatör, diğer taraftan, karşı argümanları ile vektörleri ilişkilendirir data.frame.

Sorunuza gelince, veri çerçevelerinin bir listesini yapmak kolaydır:

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)

Veri çerçevelerine, diğer liste öğelerine eriştiğiniz gibi erişirsiniz:

my.list[[1]]
#   y1 y2
# 1  1  4
# 2  2  5
# 3  3  6

344

Diğer cevaplar göstermek nasıl ne zaman data.frames bir listesini yapmak için zaten örneğin data.frames, bir demet d1, d2.... bir sorun sıralı olarak adlandırılır veri çerçeveleri edilir olması, ve bir listede koyarak bir olduğunu iyi bir düzeltme, ancak en iyi uygulama, bir grup veriye sahip olmaktan kaçınmaktır .

Diğer cevaplar, öğeleri listelemek, bunlara erişmek, vb. İçin veri çerçeveleri atama konusunda çok ayrıntılı bilgi verir. Bunu burada biraz ele alacağız, ancak Ana Nokta , bir demet elde edene kadar beklemeyin. data.framesbir listeye eklemek için. Listeden başlayın.

Bu yanıtın geri kalanı, sıralı değişkenler oluşturmak isteyebileceğiniz ve doğrudan listelere nasıl gideceğinizi gösterebileceğiniz bazı yaygın durumları kapsayacaktır. R'deki listelerde yeniyseniz , bir listenin öğeleri arasındaki [[ve bunlara [erişme arasındaki fark nedir ? .


En başından listeler

İlk etapta asla d1 d2 d3... yaratmayın dn. Öğeleri diçeren bir liste oluşturun n.

Birden çok dosyayı veri çerçeveleri listesine okuma

Bu, dosyaları okurken oldukça kolay bir şekilde yapılır. Belki data1.csv, data2.csv, ...bir dizinde dosyalar var . Amacınız çağrılan bir veri listesi mydata. İhtiyacınız olan ilk şey, tüm dosya adlarına sahip bir vektör. Sen macun ile bu inşa edebilir (örneğin my_files = paste0("data", 1:5, ".csv")), ama muhtemelen kullanımı daha kolay list.filestüm uygun dosyaları kapmak için: my_files <- list.files(pattern = "\\.csv$"). Dosyaları eşleştirmek için normal ifadeleri kullanabilir, yardıma ihtiyacınız varsa diğer sorulardaki normal ifadeler hakkında daha fazla bilgi edinebilirsiniz. Bu şekilde, güzel bir adlandırma şeması izlemeseler bile tüm CSV dosyalarını yakalayabilirsiniz. Veya belirli CSV dosyalarını bir gruptan seçmeniz gerekiyorsa daha zarif bir normal ifade deseni kullanabilirsiniz.

Bu noktada, çoğu R başlangıç ​​bir fordöngü kullanacak ve bununla ilgili yanlış bir şey yok, gayet iyi çalışıyor.

my_data <- list()
for (i in seq_along(my_files)) {
    my_data[[i]] <- read.csv(file = my_files[i])
}

Bunu yapmanın daha R benzeri bir yolu var lapply, bu da yukarıdakiler için bir kısayol

my_data <- lapply(my_files, read.csv)

Tabii ki, diğer veri içe aktarma işlevini read.csvuygun şekilde değiştirin. readr::read_csvveya data.table::freaddaha hızlı olacaktır veya farklı bir dosya türü için farklı bir işleve ihtiyacınız olabilir.

Her iki durumda da, liste öğelerini dosyalarla eşleşecek şekilde adlandırmak kullanışlı

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

Bir veri çerçevesini veri çerçeveleri listesine bölme

Bu çok kolay, temel işlev split()sizin için yapar. Verilerin bir sütununa (veya sütunlarına) veya istediğiniz başka bir şeye bölebilirsiniz.

mt_list = split(mtcars, f = mtcars$cyl)
# This gives a list of three data frames, one for each value of cyl

Bu aynı zamanda bir veri çerçevesini çapraz doğrulama için parçalara ayırmanın güzel bir yoludur. Belki mtcarseğitim, test ve doğrulama parçalarına bölünmek istersiniz .

groups = sample(c("train", "test", "validate"),
                size = nrow(mtcars), replace = TRUE)
mt_split = split(mtcars, f = groups)
# and mt_split has appropriate names already!

Veri çerçeveleri listesini simüle etme

Belki de verileri simüle ediyorsunuz, şöyle bir şey:

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

Ama kim sadece bir simülasyon yapar? Bunu 100 kez, 1000 kez ve daha fazlasını yapmak istiyorsun! Ama yok sizin çalışma alanında 10.000 veri çerçeveleri istiyorum. replicateBunları kullanın ve bir listeye yerleştirin:

sim_list = replicate(n = 10,
                     expr = {data.frame(x = rnorm(50), y = rnorm(50))},
                     simplify = F)

Bu durumda özellikle, ayrı veri çerçevelerine gerçekten ihtiyacınız mı yoksa “grup” sütununa sahip tek bir veri çerçevesinin de işe yarayıp yaramayacağını mı düşünmelisiniz? Bunu kullanmak data.tableveya dplyrbir veri çerçevesine "gruplama" yapmak oldukça kolaydır.

Verilerimi bir listeye koymadım :( Bir dahaki sefere yapacağım, ama şimdi ne yapabilirim?

Garip bir ürün grubuysa (olağandışı), bunları atayabilirsiniz:

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

Eğer bir desende adlandırılmış veri çerçeveleri varsa örneğin df1, df2, df3ve bir liste halinde istiyoruz yapabilirsiniz getisimlere maç için normal bir ifade yazabilirsiniz eğer onları. Gibi bir şey

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.

Genellikle, mgetbirden fazla nesne almak ve bunları adlandırılmış bir listeye döndürmek için kullanılır. Muadili get, tek bir nesne almak ve onu döndürmek için kullanılır (listede değil).

Veri çerçeveleri listesinin tek bir veri çerçevesine birleştirilmesi

Ortak bir görev, veri çerçeveleri listesini büyük bir veri çerçevesine birleştirmektir. Bunları üst üste yığmak istiyorsanız, rbindbir çift için kullanabilirsiniz , ancak veri çerçeveleri listesi için üç iyi seçenek vardır:

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

(Benzer şekilde cbindveya dplyr::bind_colssütunlar için.)

Veri çerçeveleri listesini birleştirmek (birleştirmek) için bu yanıtları görebilirsiniz . Çoğu zaman, bir fikir kullanmaktır Reduceile mergebirlikte onları almak için (veya başka bir birleştirme fonksiyonu).

Verileri neden bir listeye koymalıyım?

Her veri çerçevesine benzer şeyler yapmak istiyorum, ve işlevleri gibi çünkü listelerinde benzer verileri koyun lapply, sapply do.call, paket ve eski fonksiyonlar kolay bunu yapmak. Listelerle kolayca bir şeyler yapan insanların örnekleri SO'dur.purrrplyr l*ply

Düşük bir döngü için kullansanız bile, bir liste öğelerinde döngü yapmak, değişken adları oluşturmak pasteve nesnelere erişmekten çok daha kolaydır get. Hata ayıklamak daha kolaydır.

Ölçeklenebilirliği düşünün . Eğer gerçekten sadece üç değişken, kullanımına 's cezası gerekiyorsa d1, d2, d3. Ama sonra ortaya çıkıyorsa gerçekten 6'ya ihtiyacınız var, bu çok daha fazla yazım. Ve bir dahaki sefere, 10 veya 20 gerektiğinde, kendinizi belki değişikliği yerine / find kullanılarak, kopyalama ve kod satırları yapıştırarak bulmak d14için d15, ve düşündüğünü bu programlama nasıl olmalı değil . Bir liste kullanırsanız, 3 vaka, 30 vaka ve 300 vaka arasındaki fark en fazla bir kod satırıdır - vaka sayınız otomatik olarak, örneğin .csvdosyalarınızda kaç dosya bulunduğunda dizin.

Veri çerçevelerinize erişmek için sayısal dizinlerden başka bir şey kullanmak istemeniz durumunda (ve her ikisini de kullanabilirsiniz, bu bir XOR seçeneği değildir) listenin öğelerini adlandırabilirsiniz.

Genel olarak, listelerin kullanılması sizi daha temiz, okunması kolay bir kod yazmanıza yol açacaktır, bu da daha az hata ve daha az karışıklığa neden olacaktır.


2
Listelerle çalışmayı kapsayan hangi kitabı öneriyorsunuz?
Sahipsiz

15
Stack Overflow'da hem rve ile etiketlenmiş soruları ve cevapları okumanızı tavsiye ederim list.
Gregor Thomas

2
@Gregor Eklemek istiyorum, liste öğelerini sadece my_data <- NULL`` veri_ <- list () '' yerine atayarak dosyaları eşleştirmek için isimlerden kaçınabileceğimizi! :)
Daniel

6
Bu mümkün, ancak my_data <- list()bir liste oluşturduğunuzu açıkça ortaya koyuyor, ki bu iyi! Açık kod iyi bir şeydir. Bunun my_data <- NULLyerine kullanmanın bir avantajı görmüyorum .
Gregor Thomas

3
Söylediklerinizi kabul ediyorum, ama dediğim gibi, dosyaları adlandırma aşamasından kaçabilirsiniz. names(my_data) <- gsub("\\.csv$", "", my_files) ;) <br> Ama ben acemi olarak onlardan çok şey öğrendim gibi tavsiyelerinize saygı duyuyorum ve gerçekten takdir ediyorum :)
Daniel

21

Ayrıca her liste öğesinde belirli sütunları ve değerleri erişebilir [ve [[. Burada bir çift örnek var. İlk olarak, listedeki her veri çerçevesinin yalnızca ilk sütununa erişebiliriz lapply(ldf, "[", 1), burada 1sütun numarasını gösterir.

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

Benzer şekilde, ikinci sütundaki ilk değere şu şekilde erişebiliriz:

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

Ardından, sütun değerlerine doğrudan, vektör olarak, [[

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

13

Çok sayıda ardışık olarak adlandırılmış veri çerçeveniz varsa, aşağıdaki gibi veri çerçevelerinin alt kümelerinin bir listesini oluşturabilirsiniz:

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

burada my.list22., 3. ve 4. veri çerçevelerini içeren bir liste döndürür.

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

Ancak, yukarıdaki listedeki veri çerçevelerinin artık adlandırılmadığını unutmayın. Veri çerçevelerinin bir alt kümesini içeren bir liste oluşturmak ve adlarını korumak istiyorsanız bunu deneyebilirsiniz:

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

döndüren:

> 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

2
Bunun yerine lapply(foo, get), sadece kullanınmget(foo)
Gregor Thomas

9

Verilen bir şekilde çok sayıda veri var. Benzer adlara sahip çerçeveler (burada d # burada # bazı pozitif tamsayıdır), aşağıdaki @ mark-miller'in yönteminde hafif bir iyileşme. Daha kesiklidir ve listedeki her adın karşılık gelen orijinal veri çerçevesinin adı olduğu adlandırılmış bir data.frames listesi döndürür .

Anahtar ile mgetbirlikte kullanmaktır ls. Soruda sağlanan d1 ve d2 veri çerçeveleri, ortamdaki d # adlarına sahip tek nesneyse, o zaman

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

hangisi dönecekti

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

Bu yöntem ls, ortamdaki nesnelerin adlarının daha ince bir şekilde ayrıştırılması için düzenli ifadeler kullanmamızı sağlayan örüntü argümanından yararlanır . Düzenli ifade için alternatif "^d[0-9]+$"bir "^d\\d+$".

@Gregor'un işaret ettiği gibi, data.frames başlangıçta adlandırılmış listelere konacak şekilde veri oluşturma sürecinizi ayarlamak daha iyi bir geneldir .

veri

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

3

Bu biraz geç olabilir ama örneğinize geri dönerek cevabı biraz uzatacağımı düşündüm.

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

Sonra listenizi kolayca yapabilirsiniz:

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

Artık bir listeniz var, ancak listeye eski yoldan erişmek yerine

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

istediğiniz veri çerçevesini almak ve atamak için bu işlevi kullanabilirsiniz.

GETDF_FROMLIST <- function(DF_LIST, ITEM_LOC){
   DF_SELECTED <- DF_LIST[[ITEM_LOC]]
   return(DF_SELECTED)
}

Şimdi istediğini al.

D1 <- GETDF_FROMLIST(mylist, 1)
D2 <- GETDF_FROMLIST(mylist, 2)
D3 <- GETDF_FROMLIST(mylist, 3)
D4 <- GETDF_FROMLIST(mylist, 4)

Ekstra biraz yardımcı olur umarım.

Şerefe!


2
Evet biliyorum ama bir sebepten dolayı kopyalayıp yapıştırdığımda her şey kapaklara geçti. :( Her halükarda küçük harfli kod çalışır.
ML_for_now

4
Eğer tercih ediyorum neden merak ediyorum GETDF_FROMLIST(mylist, 1)için mylist[[1]]? İşlev sözdizimini tercih ederseniz, "[["(mylist, 1)özel bir işlev tanımlamadan da yapabilirsiniz .
Gregor Thomas

4
Ayrıca fonksiyon tanımınızı basitleştirebilirsiniz, fonksiyonun tüm gövdesi sadece return(DF_LIST[[ITEM_LOC]])bir ara değişken atamaya gerek olmayabilir .
Gregor Thomas

1

Çok basit ! İşte benim önerim:

Çalışma alanınızda veri çerçeveleri seçmek istiyorsanız şunu deneyin:

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

veya

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

tüm bunlar aynı sonucu verecektir.

Gibi is.data.framediğer değişken türlerini kontrol etmek için değiştirebilirsinizis.function


1

Kendimi tam bir acemi olarak görüyorum, ancak burada belirtilmeyen orijinal alt sorulardan birine son derece basit bir cevabım olduğunu düşünüyorum: veri çerçevelerine veya bölümlerine erişim.

Yukarıda belirtildiği gibi veri çerçeveleri içeren bir liste oluşturarak başlayalım:

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)

Ardından, veri çerçevelerinden birinde belirli bir değere erişmek istiyorsanız, bunu çift köşeli parantezleri sırayla kullanarak yapabilirsiniz. İlk küme sizi veri çerçevesine, ikinci küme de belirli koordinatlara götürür:

my.list[[1]][[3,2]]

[1] 6
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.