データフレームのリストを作成するにはどうすればよいですか?


186

データフレームのリストを作成する方法と、リストからそれらの各データフレームにアクセスする方法を教えてください。

たとえば、これらのデータフレームをリストに配置するにはどうすればよいですか?

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
これは、カップルの答えであるが、ここにも見えるコメントを持つことの価値は:使用し=ない<-内部data.frame()<-あなたが作成y1y2、あなたのグローバル環境で使用することによって、あなたのデータフレームはあなたがそれが望んでいるものではありません。
グレゴールトーマス

37
<-data.frame()内にスペースとs がないコードの混乱を見てください。なんて新人だった。
Ben

5
もう違います。コードのフォーマットを修正するために質問を編集しました。懐かしさを感じたら元に戻してください。
クラウスウィルク2017

回答:


133

これはあなたの質問とは関係=ありません<-が、関数呼び出し内ではなく使用したいと思います。を使用すると<-、変数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

=オペレータは、他の一方で、引数を使用してベクトルを関連付けます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

344

他の回答にはお見せする方法あなたはときdata.framesのリストを作るためにすでに例えば、data.framesの束をd1d2順次指定されたデータフレームを持つことは問題であり、リストでそれらを置くことはaは、...良い修正ですが、最初のリストない一連のdata.framesがリストないようにすることをお勧めします。

他の回答は、データフレームをリスト要素に割り当て、それらにアクセスする方法など、多くの詳細を提供します。ここでも少し説明しますが、主要なポイント、たくさんのデータが得られるまで待たないことです。data.framesそれらをリストに追加します。リストから始めます。

この回答の残りの部分では、シーケンシャル変数を作成したくなるいくつかの一般的なケースを取り上げ、リストに直接進む方法を示します。Rのリストを初めて使用する場合は、リストの要素へのアクセスアクセスの違いは何ですか?[[[もご覧ください


最初からリスト

そもそもd1 d2 d3、...を作成しないでくださいdn。要素dn含むリストを作成します。

複数のファイルをデータフレームのリストに読み込む

これは、ファイルを読み込むときに簡単に実行できます。多分あなたはdata1.csv, data2.csv, ...ディレクトリにファイルを持っています。あなたの目標はと呼ばれるdata.framesのリストですmydata。最初に必要なのは、すべてのファイル名を持つベクターです。これは貼り付け(例:)で作成できますが、適切なファイルをすべて取得my_files = paste0("data", 1:5, ".csv")する方がおそらく簡単list.filesですmy_files <- list.files(pattern = "\\.csv$")。正規表現を使用してファイルを照合できます。ヘルプが必要な場合は、他の質問で正規表現の詳細をご覧ください。このようにすれば、CSVファイルが適切な命名規則に従っていない場合でも、すべてのCSVファイルを取得できます。また、特定の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)

もちろん、read.csv必要に応じて他のデータインポート機能を代用してください。readr::read_csvまたはdata.table::fread、より高速になります。または、ファイルタイプごとに異なる機能が必要になる場合もあります。

どちらの方法でも、ファイルと一致するようにリスト要素に名前を付けると便利です

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()はあなたのためにそれを行います。データの1つまたは複数の列、またはその他の必要なもので分割できます。

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

しかし、誰が1つのシミュレーションしかしませんか?あなたはこれを100回、1000回、もっとやりたいです!しかし、ワークスペースに10,000データフレームが必要ではありません。replicateそれらを使用してリストに入れます:

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

この場合は特に、本当に個別のデータフレームが必要かどうか、または「グループ」列を持つ単一のデータフレームも同様に機能するかどうかを検討する必要があります。data.tableまたはを使用dplyrすると、データフレームに対して「グループごと」に処理を行うのが非常に簡単になります。

データをリストに入れませんでした:(次回は行いますが、今何ができますか?

それらが奇妙な品揃えである場合(これは珍しいことです)、単純にそれらを割り当てることができます。

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

あなたは、パターンで指定されたデータフレームを使用している場合、例えばdf1df2df3、とあなたがリストでそれらをしたい、あなたのことができ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は、単一のオブジェクトを取得してそれを返すために使用されます(リストではありません)。

データフレームのリストを単一のデータフレームに結合する

一般的なタスクは、データフレームのリストを1つのビッグデータフレームに結合することです。それらを互いの上にスタックしたい場合はrbind、それらのペアに使用しますが、データフレームのリストには、次の3つの適切な選択肢があります。

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

(同様に、列に対してcbindまたはdplyr::bind_colsを使用します。)

データフレームのリストをマージ(結合)するには、これらの回答を確認できます。多くの場合、アイデアをReduce一緒にmerge(または他の結合関数)を使用してまとめます。

なぜデータをリストに入れるのですか?

あなたは、各データフレームに似たものをやりたいので、リストに類似したデータを入れ、などの機能lapplysapply do.callパッケージ、および古い機能はそれを行うことは容易にそれを作ります。リストを使って簡単に物事を行う人々の例は、至る所にあります。purrrplyr l*ply

低いforループを使用する場合でも、で変数名を作成pasteし、でオブジェクトにアクセスするよりも、リストの要素をループする方がはるかに簡単getです。デバッグも簡単です。

スケーラビリティについて考えてください。あなたが本当に唯一の3つの変数が必要な場合、それは使用に罰金ですd1d2d3。しかし、実際に6が必要であることが判明した場合、それはより多くのタイピングです。そして次に、10または20が必要になったときに、コードの行をコピーして貼り付けることに気づき、おそらくfind / replaceをに変更d14してd15これがプログラミングの本来の姿ではないと考えています。あなたがリストを使用する場合は、3例、30例、および300例との違いは、コードのほとんどの1行である---全く変更しない例あなたの番号が自動的例えば、によって検出された場合、どのように多くの.csvあなたのファイルですディレクトリ。

数値インデックス以外のものを使用してデータフレームにアクセスする場合は、リストの要素に名前を付けることができます(両方を使用できますが、これはXORの選択ではありません)。

全体として、リストを使用すると、よりクリーンで読みやすいコードを作成できるようになり、バグが減り、混乱が減ります。


2
リストの操作について説明しているのはどの本ですか。
2016年

15
との両方rでタグ付けされたStack Overflowの質問と回答を読むことをお勧めしlistます。
グレゴールトーマス

2
@Gregor my_data <- NULL`my_data <-list() 'ではなくを割り当てるだけで、ファイルに一致するようにリスト要素に名前を付けないようにできることを追加したいと思います。:)
ダニエル

6
それは可能my_data <- list()ですが、リストを作成していることを明確にします。これは良いことです!明確なコードは良いことです。my_data <- NULL代わりに使用する利点はないと思います。
グレゴールトーマス

3
私はあなたが言ったことについて同意しますが、私が言ったようにそうすることで、ファイルに名前を付ける段階を逃れることができます。names(my_data) <- gsub("\\.csv$", "", my_files) ;)<br>しかし、私は初心者として彼らから多くを学んでいるのであなたのアドバイスを尊重します、そして私はそれを本当に感謝します:)
Daniel

21

あなたはまたして各リスト要素に特定の列や値にアクセスすることができます [し、[[。次に例をいくつか示します。まず、リストの各データフレームの最初の列にのみアクセスできます。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

同様に、2番目の列の最初の値にアクセスできます。

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

次に、列の値にベクトルとして直接アクセスすることもできます。 [[

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

13

連続して名前が付けられたデータフレームが多数ある場合は、次のように、データフレームの必要なサブセットのリストを作成できます。

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

where 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

2
の代わりにlapply(foo, get)、単に使用してくださいmget(foo)
グレゴールトーマス

9

与えられたものとして、同じような名前(ここではd#で、#は正の整数)の「多数」のdata.frameがあるとすると、@ mark-millerの方法が少し改善されています。より簡潔で、data.framesの名前付きリストを返します。リスト内の各名前は、対応する元のdata.frameの名前です。

キーはと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

このメソッドは、のパターン引数lsを利用します。これにより、正規表現を使用して、環境内のオブジェクトの名前をより詳細に解析できます。正規表現に代わるものです"^d[0-9]+$""^d\\d+$"です。

@gregorが指摘するように、data.framesが最初に名前付きリストに配置されるようにデータ構築プロセスを設定する方が全体的には優れています。

データ

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

これは少し遅いかもしれませんが、あなたの例に戻って、私は答えを少しだけ拡張すると思いました。

 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)

その余分なビットが役立つことを願っています。

乾杯!


2
はい私は知っていますが、何らかの理由でコピーして貼り付けたとき、すべてが大文字になりました。:(小文字の動作中の任意のイベントのコード。
ML_for_now

4
あなたが好む、なぜ私が興味GETDF_FROMLIST(mylist, 1)mylist[[1]]?関数構文を使用する場合は"[["(mylist, 1)、カスタム関数を定義せずに行うこともできます。
グレゴールトーマス

4
関数の定義を単純化することもできます。関数の本体全体return(DF_LIST[[ITEM_LOC]])は、中間変数を割り当てる必要なしに、単ににすることができます。
Gregor Thomas

1

とてもシンプル!これが私の提案です:

ワークスペースでデータフレームを選択したい場合は、これを試してください:

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

または

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

これらはすべて同じ結果になります。

次のis.data.frameような他のタイプの変数をチェックするように変更できますis.function


1

私は完全に初心者だと思いますが、ここで述べられていない元のサブ質問の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))

my.list <- list(d1, d2)

次に、いずれかのデータフレームの特定の値にアクセスする場合は、二重の角かっこを順番に使用してアクセスできます。最初のセットはデータフレームに移動し、2番目のセットは特定の座標に移動します。

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

[1] 6
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.