回答:
回答の一部はすでに質問に含まれています:列(変数)が異なるタイプ(数値/文字/論理など)であることが期待できる場合は、データフレームを使用します。行列は、同じタイプのデータ用です。
したがって、同じタイプのデータがある場合にのみ、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()
因子ラベルのいずれかが数値でない場合、via を強制すると文字マトリックスになります。比較:
> 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.frames
列型よりも柔軟性を提供することです。タイプの強制型変換のためdata.frame(a = rnorm(1e6), b = sample(letters, 1e6, TRUE))
、matrix
バージョンはメモリよりもはるかに小さくなります(私の迅速な計算では6倍)。
行列は、実際には追加のメソッドを持つベクトルです。一方、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
両者の効率の違いについてもう強調できません!特にデータ分析の場合にはDFの方が便利なのは事実ですが、DFは異種のデータも許可し、一部のライブラリはそれらを受け入れるだけですが、特定のタスクに対して1回限りのコードを記述しない限り、これらはすべて二次的なものです。
例を挙げましょう。MCMCメソッドの2Dパスを計算する関数がありました。基本的に、これは、初期点(x、y)を取得し、特定のアルゴリズムを反復して各ステップで新しい点(x、y)を見つけ、このようにしてパス全体を構築することを意味します。アルゴリズムには、非常に複雑な関数の計算と各反復でのランダム変数の生成が含まれるため、12秒間実行すると、各ステップでどれだけの処理が行われるかを考えれば問題ないと思いました。つまり、関数は、構築されたパスのすべてのポイントを3列のdata.frameの目的関数の値と一緒に収集しました。したがって、3列はそれほど大きくなく、ステップ数も妥当な10,000を超えていました(この種の問題では、長さが1,000,000のパスが一般的であるため、10,000は何もありません)。だから、私はDF 10だと思った 000x3は問題ではありません。DFが使用された理由は簡単です。関数を呼び出した後、結果の(x、y)パスを描画するためにggplot()が呼び出されました。また、ggplot()は行列を受け入れません。
次に、好奇心から外れたある時点で、マトリックスにパスを収集するように関数を変更することにしました。嬉しいことに、DFと行列の構文は似ていますが、dfをdata.frameとして指定する行を行列として初期化する行に変更するだけで済みました。ここで、最初のコードでDFが最終サイズになるように初期化されたため、後で関数のコードで新しい値のみが既に割り当てられているスペースに記録され、新しい行をDF。これにより、比較がさらに公平になり、関数をさらに書き直す必要がなくなったため、私の仕事も簡単になりました。必要なサイズのdata.frameの最初の割り当てから、同じサイズのマトリックスに1行変更するだけです。関数の新しいバージョンをggplot()に適合させるために、返された行列をデータに変換しました。
コードを再実行した後、結果は信じられませんでした。コードはほんの一瞬で実行されます!約12秒ではなく。また、10,000回の反復中の関数は、DF内(および現在は行列内)に既に割り当てられているスペースに対してのみ値の読み取りと書き込みを行います。この違いは、妥当な(またはかなり小さい)サイズ10000x3の場合にも当てはまります。
したがって、DFを使用する唯一の理由がggplot()などのライブラリ関数との互換性を確保することである場合は、いつでもそれをDFに変換できます-都合のよい範囲で行列を操作します。一方、マトリックスからDFへの変換とその逆の定数変換を必要とするデータ分析パッケージを使用するなど、DFを使用するより実質的な理由がある場合、または自分で集中的な計算を行わず、標準のみを使用する場合パッケージ(実際には、多くの場合、内部的にDFをマトリックスに変換し、ジョブを実行してから、結果を元に戻します-すべての効率的な作業を実行します)、または1回限りのジョブを実行して気にしないでくださいDFの方が快適であれば、効率について心配する必要はありません。
または、より実用的な別のルール:OPのような質問がある場合は、行列を使用します。そのため、そのような質問がない場合にのみDFを使用します(DFを使用する必要があることがすでにわかっているため、またはコードは1回限りなので、特に気にする必要はありません。
ただし、一般的には、この効率ポイントを常に優先事項として覚えておいてください。