14

多くの R ユーザーは、最終的にデータから要素を削除する多くの方法を見つけ出します。1 つの方法は を使用するNULLことです。特に、 から列を削除しdata.frameたり、 から要素を削除したりする場合に使用しますlist

data.frame最終的に、ユーザーは一度に複数の列を削除したい状況に遭遇し<- list(NULL)、解決策として思いつきました (使用<- NULLするとエラーが発生するため)。

Adata.frame の特殊なタイプであるため、 から項目を削除する方法は、 から列を削除する方法と同じであるlistと想像するのは難しくありません。ただし、以下の例に示すように、異なる結果が生成されます。listdata.frame

## Make some small data--two data.frames and two lists
cars1 <- cars2 <- head(mtcars)[1:4]
cars3 <- cars4 <- as.list(cars2)

## Demonstration that the `list(NULL)` approach works
cars1[c("mpg", "cyl")] <- list(NULL)
cars1
#                   disp  hp
# Mazda RX4          160 110
# Mazda RX4 Wag      160 110
# Datsun 710         108  93
# Hornet 4 Drive     258 110
# Hornet Sportabout  360 175
# Valiant            225 105

## Demonstration that simply using `NULL` does not work
cars2[c("mpg", "cyl")] <- NULL
# Error in `[<-.data.frame`(`*tmp*`, c("mpg", "cyl"), value = NULL) : 
#   replacement has 0 items, need 12

同じ概念を に適用することに切り替えlist、動作の違いを比較します。

## Does not fully drop the items, but sets them to `NULL`
cars3[c("mpg", "cyl")] <- list(NULL)
# $mpg
# NULL
# 
# $cyl
# NULL
# 
# $disp
# [1] 160 160 108 258 360 225
# 
# $hp
# [1] 110 110  93 110 175 105

## *Does* drop the `list` items while this would
##   have produced an error with a `data.frame`
cars4[c("mpg", "cyl")] <- NULL
# $disp
# [1] 160 160 108 258 360 225
# 
# $hp
# [1] 110 110  93 110 175 105

私が持っている主な質問は、 adata.frameが a の場合list、なぜこのシナリオでこれほど異なる動作をするのかということです。要素がいつドロップされ、いつエラーが発生し、いつ単純にNULL値が与えられるかを知る簡単な方法はありますか? それとも試行錯誤に頼っているのでしょうか。

4

1 に答える 1

8

免責事項:これは比較的長い回答であり、あまり明確ではなく、あまり面白くないため、スキップするか、(一種の)結論のみを読んでください。

[<-.data.frameAri B. Friedman の提案に従って、 を少しトレースしてみました 。デバッグは、関数の 162 行目から開始されます。ここでは、value(置換値の引数) がリストではないかどうかを判断するテストがあります。

ケース 1 :valueリストではない

次に、ベクトルと見なされます。ヘルプ ページにあるように、行列と配列は 1 つのベクトルと見なされます。

置換値が配列 (行列を含む) の場合、一連の列として扱われ('data.frame' や 'as.data.frame' のように)、単一の列として挿入されることに注意してください。

データ フレームの 1 つの列のみが LHS で選択されている場合、唯一の制約は、置き換えられる行の数が と等しいか、の倍数でなければならないということですlength(value)。この場合、必要に応じてvalueリサイクルされ、リストに変換されます。repの場合length(value)==0、リサイクルは行われず (不可能なので)、valueリストに変換されるだけです。

LHS でデータ フレームの複数の列が選択されている場合、制約はもう少し複雑です。length(value)置き換えられる要素の総数と等しいか、その倍数である必要があります。つまり、行数 * 列数です。

正確なテストは次のとおりです。

(m < n * p && (m == 0L || (n * p)%%m))

は行n数、p列数、およびmの長さですvalue。条件が FALSE の場合、 は行列valueに変換されn x p(したがって、必要に応じて再利用されます)、行列は列ごとに分割されてリストになります。

valueが NULL の場合、条件は として TRUEm==0になり、関数は停止します。長さ 0ごとvalueに問題が発生することに注意してください。たとえば、

cars1[,c("mpg")] <- numeric(0)

動作しますが、次のようになります。

cars1[,c("mpg","disp")] <- numeric(0)

と同じように失敗するcars1[,c("mpg","disp")] <- NULL

ケース 2 :valueリストです

がリストの場合value、複数の列を同時に置換するために使用されます。例えば ​​:

cars1[,c("mpg","disp")] <- list(1,2)

cars1$mpg1 のベクトルと 2 のベクトルに置き換えられcars1$dispます。

ここで起こる一種の「二重リサイクル」があります。

  • まず、valueリストの長さは、置換する列の数以下でなければなりません。少ない場合は、従来のリサイクルが行われます。
  • 次に、リストの各要素のvalue長さは、置換する行数と同じか、それ以上か、その倍数でなければなりません。少ない場合は、行数に一致するように各リスト要素に対して別のリサイクルが行われます。それ以上の場合、警告が表示されます。

valueRHSの が の場合、リサイクルは不可能であるため (は常に) list(NULL)、実際には何も起こりません。しかし、コードは続き、最後に、置き換えられる各列が割り当てられます。つまり、削除されます。rep(NULL, 10)NULLNULL

まとめと(一種の)結論

data.framelist各要素が同じ長さでなければならないというデータフレームの特定の制約により、動作が異なります。割り当てによる複数の列の削除は、値自体が原因ではなく、長さが 0 であるNULLため失敗します。エラーは、割り当てられた値の長さが置換される要素の数の倍数であるかどうかを検証するテストから発生します (要素の数)行 * 列数)。NULLNULL

複数列の場合の処理​​はvalue=NULL難しくないように思えますが (約 4 行の単純なコードを追加することで)、NULL特殊なケースとして考慮する必要があります。関数実装のロジックを壊すため、または私が知らない副作用があるため、処理されないかどうかを判断できません。

于 2013-10-17T21:52:01.827 に答える