いつdata.frame
を使用する必要があり、いつmatrix
を使用した方がよいでしょうか?
どちらもデータを長方形形式で保持するため、不明確な場合があります。
どのデータ型をいつ使用するかについての一般的な経験則はありますか?
回答の一部はすでに質問に含まれています。列(変数)が異なるタイプ(数値/文字/論理など)であると予想される場合は、データフレームを使用します。行列は、同じタイプのデータ用です。
したがって、選択マトリックス/data.frameは、同じタイプのデータがある場合にのみ問題になります。
答えは、data.frame/matrixのデータをどうするかによって異なります。他の関数に渡される場合、これらの関数の引数の予想されるタイプが選択を決定します。
また:
行列はよりメモリ効率が良いです:
m = matrix(1:4, 2, 2)
d = as.data.frame(m)
object.size(m)
# 216 bytes
object.size(d)
# 792 bytes
線形代数型の演算を行う場合は、行列が必要です。
(コンパクトな$演算子を使用して)名前で列を頻繁に参照する場合、データフレームはより便利です。
データフレームは、書式設定を各列に個別に適用できるため、表形式の情報のレポート(印刷)にも適しています。
@Michalで言及されていないことは、マトリックスが同等のデータフレームよりも小さいだけでなく、マトリックスを使用するとコードがデータフレームを使用するよりもはるかに効率的になることです。これが、内部的に、多くのR関数がデータフレーム内の行列データを強制する理由の1つです。
多くの場合、データフレームの方がはるかに便利です。常にアトミックなデータチャンクだけが存在するわけではありません。
文字マトリックスを使用できることに注意してください。 Rで行列を作成するために数値データを持っているだけではありません。
データフレームをマトリックスに変換する場合、data.matrix()
関数があることに注意してください。この関数は、内部レベルに基づいて係数を数値に変換することにより、係数を適切に処理します。因子ラベルのいずれかが数値でない場合、as.matrix()
を介して強制すると文字行列になります。比較する:
> head(as.matrix(data.frame(a = factor(letters), B = factor(LETTERS))))
a B
[1,] "a" "A"
[2,] "b" "B"
[3,] "c" "C"
[4,] "d" "D"
[5,] "e" "E"
[6,] "f" "F"
> head(data.matrix(data.frame(a = factor(letters), B = factor(LETTERS))))
a B
[1,] 1 1
[2,] 2 2
[3,] 3 3
[4,] 4 4
[5,] 5 5
[6,] 6 6
多くの場合、数値変数以上のものがあるため、データ分析タスクにはほとんど常にデータフレームを使用します。パッケージの関数をコーディングするとき、ほとんどの場合、マトリックスに強制し、結果をデータフレームとしてフォーマットします。これは、データフレームが便利だからです。
@Michal:マトリックスのメモリ効率はそれほど高くありません:
m <- matrix(1:400000, 200000, 2)
d <- data.frame(m)
object.size(m)
# 1600200 bytes
object.size(d)
# 1600776 bytes
...多数の列がない限り:
m <- matrix(1:400000, 2, 200000)
d <- data.frame(m)
object.size(m)
# 1600200 bytes
object.size(d)
# 22400568 bytes
マトリックスは、実際には追加のメソッドを持つベクトルです。一方、data.frameはリストです。違いはベクターとリストにあります。計算効率のために、マトリックスに固執します。必要に応じてdata.frameを使用します。
行列とデータフレームは長方形の2D配列であり、行と列が不均一になります。それらはいくつかのメソッドとプロパティを共有しますが、すべてではありません。
例:
M <- list(3.14,TRUE,5L,c(2,3,5),"dog",1i) # a list
dim(M) <- c(2,3) # set dimensions
print(M) # print result
# [,1] [,2] [,3]
# [1,] 3.14 5 "dog"
# [2,] TRUE Numeric,3 0+1i
DF <- data.frame(M) # a data frame
print(DF) # print result
# X1 X2 X3
# 1 3.14 5 dog
# 2 TRUE 2, 3, 5 0+1i
M <- matrix(c(1,1,1,1,2,3,1,3,6),3) # a numeric matrix
DF <- data.frame(M) # a all numeric data frame
solve(M) # obtains inverse matrix
solve(DF) # obtains inverse matrix
det(M) # obtains determinant
det(DF) # error
この2つの効率の違いを強調することはできません! DFは、特にデータ分析の場合には便利ですが、異種データも許可し、一部のライブラリはそれらのみを受け入れますが、特定のタスク用の1回限りのコードを記述しない限り、これらはすべて二次的です。
例を挙げましょう。 MCMCメソッドの2Dパスを計算する関数がありました。基本的に、これは初期ポイント(x、y)を取得し、特定のアルゴリズムを反復して各ステップで新しいポイント(x、y)を見つけ、この方法でパス全体を構築することを意味します。アルゴリズムには、非常に複雑な関数の計算と各反復でのランダム変数の生成が含まれているため、12秒間実行すると、各ステップでどれだけ処理が行われるかを考えると問題ないと思いました。そうは言っても、関数は、3列のdata.frameの目的関数の値とともに、構築されたパス内のすべてのポイントを収集しました。したがって、3列はそれほど大きくなく、ステップ数も妥当な10,000を超えていました(この種の問題では、長さが1,000,000のパスが一般的であるため、10,000は何もありません)。したがって、DF 10,000x3は間違いなく問題ではないと思いました。 DFが使用された理由は簡単です。関数を呼び出した後、ggplot()が呼び出され、結果の(x、y)パスを描画しました。また、ggplot()は行列を受け入れません。
それから、好奇心から離れたある時点で、関数を変更してマトリックス内のパスを収集することにしました。嬉しいことに、DFとマトリックスの構文は似ていますが、data.frameとしてdfを指定する行を、マトリックスとして初期化する行に変更するだけでした。ここで、最初のコードではDFが最終サイズに初期化されたため、関数のコードでは新しい値のみが既に割り当てられたスペースに記録され、オーバーヘッドはなかったことにも言及する必要がありますDFに新しい行を追加する。これにより、比較がさらに公平になり、関数内でこれ以上何も書き換える必要がなくなったため、仕事が簡単になりました。必要なサイズのdata.frameの最初の割り当てから同じサイズのマトリックスに1行変更するだけです。関数の新しいバージョンをggplot()に適合させるために、今返された行列をggplot()で使用するdata.frameに変換しました。
コードを再実行した後、結果が信じられませんでした。コードはほんの数秒で実行されます!約12秒の代わりに。繰り返しになりますが、10,000回の反復中の関数は、DF(およびマトリックス内)で既に割り当てられているスペースに対してのみ値を読み書きします。また、この違いは、妥当な(または小さい)サイズ10000x3にも当てはまります。
したがって、DFを使用する唯一の理由がggplot()などのライブラリ関数との互換性を確保することである場合は、最後にいつでもDFに変換できます- -便利である限り、マトリックスを使用します。一方、DFを使用するより実質的な理由がある場合、たとえばマトリックスからDFへの一定の変換を必要とするデータ分析パッケージを使用する場合、または集中的な計算を行わずに標準のみを使用する場合などパッケージ(それらの多くは実際にDFをマトリックスに内部的に変換し、ジョブを実行してから結果を元に戻すため、すべての効率化作業を行います)、または1回限りのジョブを実行しますDFを気にせず、より快適に感じるのであれば、効率を心配する必要はありません。
または、より実用的な別のルール:OPなどの質問がある場合は、マトリックスを使用します。そのため、DFを使用する必要があることを既に知っているため、またはコードは1回限りですので、あまり気にしません)。
しかし、一般に、この効率性のポイントを常に優先事項として念頭に置いてください。