この vignette は、 tibble のサブセットとサブセット割り当ての不変量を定義し、その動作がデータフレームと異なる点を説明します。 目標は、動作がどのように相互作用するかを一貫して定義する小さな不変量のセットを定義することです。 いくつかのビヘイビアは,vctrsパッケージの関数,例えば,vec_slice()
, vec_recycle()
, vec_as_index()
を用いて定義されています. それらが従う不変量の詳細については,それぞれのドキュメントを参照してください.
データフレームと tibble のサブセットとサブアサインメント演算子は特に厄介です。というのも、これらの演算子は行インデックスと列インデックスの両方をサポートしており、その両方がオプションで欠落しているからです。 これを解決するには、まず列へのアクセスを [[
と $
で定義し、次に列単位のサブセットを [
で定義し、次に行単位のサブセットを定義し、さらに両者の合成を定義します。
この記事では、1つのデータフレームとそれに相当する tibble を例にして、すべての動作を説明します。:
library(tibble)
suppressWarnings(library(vctrs))
#>
#> Attaching package: 'vctrs'
#> The following object is masked from 'package:tibble':
#>
#> data_frame
new_df <- function() {
df <- data.frame(n = c(1L, NA, 3L, NA))
df$c <- letters[5:8]
df$li <- list(9, 10:11, 12:14, "text")
df
}
new_tbl <- function() {
as_tibble(new_df())
}
データフレームと tibble に対する同じコードの結果を並べて表示しています。:
結果が同一の場合(必要に応じてデータフレームに変換した後)、tibble の結果のみが表示されます。
サブセットの操作は読み取り専用です。 すべての例で同じオブジェクトが再利用されています。
また、必要に応じて、データフレームや行列を含む階層的なカラムの例も示します。:
new_tbl2 <- function() {
tibble(
tb = tbl,
m = diag(4)
)
}
new_df2 <- function() {
df2 <- new_tbl2()
class(df2) <- "data.frame"
class(df2$tb) <- "data.frame"
df2
}
df2 <- new_df2()
tbl2 <- new_tbl2()
サブセット割り当て(略してサブアサイン)のためには,テストごとにデータの新しいコピーが必要です. with_*()
関数(簡潔にするためにここでは省略します)を使用すると、より簡潔な表記が可能になります。 これらの関数は、代入式を受け取り、それを新しいデータのコピーで実行し、印刷用のデータを返します。 最初の例では,実際に実行された内容が印刷され,以降の例ではこの出力は省略されています。
x[[j]]
x[[j]]
is equal to .subset2(x, j)
.
注:x[[j]]
は、列が存在する場合、常にサイズnrow(x)
のオブジェクトを返します。
j
は、.subset2(x, j)
で強制されるように、1つの数値または文字列でなければなりません。
|
|
|
|
|
|
|
|
NA
インデックス、数値の境界外(OOB)値、非整数はエラーになります。
|
|
|
|
|
|
|
|
|
|
|
|
|
文字のOOBアクセスは、パッケージの一般的な慣例として、列がないかどうかを is.null(df[[var]])
でチェックすることがあるため silent になっています。
x$name
x$name
とx$"name"
は x[["name"]]
と同一です。
データフレームとは異なり、tibble は名前を部分的にマッチさせません。 df$x
はパッケージではほとんど使われないので、警告を出すことができます。
|
|
|
x[j]
の定義j
は vec_as_index(j, ncol(x), names = names(x))
によって整数のベクトルに変換されます。 すると,x[c(j_1, j_2, ..., j_n)]
は,対応する列名を保ったまま,tibble(x[[j_1]], x[[j_2]], ..., x[[j_3]])
と等価になります. このことから,j
は,数値または文字のベクトル,または長さ1の論理ベクトル,またはncol(x)
でなければならないことになります.
繰り返されるインデックスをサブセットすると、結果として得られる列名は未定義であるため、これに依存しないでください。
カラム名が繰り返される tibble では、名前によるサブセットは最初にマッチするカラムを使用します。
nrow(df[j])は
nrow(df)` と同じです。
tibble は、論理行列によるインデックスをサポートしていますが、返されるベクトルのすべての値に互換性がある場合に限られます。
|
x[, j]
の定義x[, j]
は x[j]
と等しい。 tibble では、x[j]
で1列になる場合は、列抽出を行いません。
x[, j, drop = TRUE]
の定義後方互換性のために、x[, j, drop = TRUE]
は列の 抽出 を行い、ncol(x[j])
が1のとき、x[j][[1]]
を返します。
x[i, ]
の定義x[i, ]は、
tibble(vec_slice(x[[1]], i), vec_slice(x[[2]], i), …)`と同じです。
つまり,i
は,数値ベクトルか,長さ nrow(x)
または 1 の論理ベクトルでなければなりません。 互換性のために、i
は正の数を含む文字ベクトルにすることもできます。
|
|
|
|
例外: OOB値は、エラーではなく警告を生成します。
|
|
|
データフレームとは異なり、長さ1の論理ベクターのみがリサイクルされます。
|
注意:スカラー論理はリサイクルされますが、スカラー数値はリサイクルされません。 そのため、x[NA, ]
と x[NA_integer_, ]
は異なる結果を返します。
x[i, , drop = TRUE]
の定義drop = TRUE
は、一つの行を選択しない場合には効果がありません。
x[]
とx[,]
の定義x[]と
x[,]は
x`と等価である。1.
x[i, j]
の定義x[i, j]
はx[i, ][j]
と等しい。2.
x[[i, j]]
の定義i
は長さ1の数値ベクトルでなければならない。 x[[i, j]]
は x[i, ][[j]]
または vctrs::vec_slice(x[[j]], i)
と同じです。
これはj
が長さ1の数値または文字のベクトルでなければならないことを意味します。
注意: vec_size(x[[i, j]])
は常に1になります。 x[i, ]
と異なり、x[[i, ]]
は有効ではありません。
x[[j]] <- a
の定義a
をベクトルとすると、x[[j]] <- a
は j
番目の列を値 a
で置き換えます。
a
は x
と同じサイズにリサイクルされるので、サイズは nrow(x)
か 1 でなければなりません。 (唯一の例外は、後述するように a
が NULL
の場合です)。 リサイクルは,リスト,データフレーム,および行列の列に対しても機能します。
|
|
|
j
はスカラーの数値または文字列でなければならず、NA
にはできません。 j
が OOB の場合は、右側に新しい列が追加され、必要に応じて名前が修正されます。
|
|
df[[j]] <- a
は、完全な列を置き換えるので、タイプを変更することができます。
[[<-
]は、NULL
を割り当てて列を削除することをサポートしています。
存在しない列を削除することはできません。
x[j] <- a
.j
が見つからない場合は、seq_along(x)
で置き換えられます。j
が論理ベクトルの場合は、seq_along(x)[j]
で数値に変換されます。a
はリストまたはデータフレームです。inherits(a, “list”)または
inherits(a, “data.frame”)が
TRUEならば、
x[j] <- aは
x[[j[[1]]] <- a[[1]]と等価である。<- a[[1]],
x[[j[[2]]]] <- a[[2]]`, …
length(a)
が 1 のとき、j
と同じ長さにリサイクルされます。
|
|
|
同じ列を2回更新しようとすると、エラーが発生します。
|
|
a
にNULL
の値が含まれている場合、対応するカラムは更新後*に削除されます(つまり、位置インデックスは変更前のカラムを参照します)。
NA
のインデックスはサポートされていません。
カラムの更新と同様に、[<-
は既存のカラムのタイプ変更をサポートしています。
列を最後に(ギャップなしで)追加することがサポートされています。 新しい列の名前は、LHS、RHS、または名前の修復によって決定されます(優先順位はこの順です)。
|
|
tibble は、論理行列によるインデックスをサポートしていますが、スカラーのRHSの場合のみで、更新されるすべての列が割り当てられた値と互換性がある場合のみです。
|
|
|
a
は行列または配列です。is.matrix(a)
とすると、a
は代入前に as.data.frame()
でデータフレームに変換されます。 行が代入される場合,その行列型はすべての列と互換性がなければなりません. もし is.array(a)
と any(dim(a)[-1:-2] != 1)
の組み合わせであれば、エラーが発生します。
|
|
|
|
|
a
は別のタイプのベクトルです。vec_is(a)
とすると、x[j] <- a
は x[j] <- list(a)
と同等です。 これは主に後方互換性のために提供されています。
行列の列を作るためには,代入前に行列をlist()
でラップしなければなりません。
a
は NULL
です。カラム全体を削除することができます。 i
を指定するとエラーになります。
|
|
a
はベクトルではありません。a
に他の型を指定するとエラーになります。 なお、is.list(a)
が TRUE
で、inherits(a, "list")
が FALSE
の場合は、a
はスカラーとみなされます。 詳細は ?vec_is
と ?vec_proxy
を参照してください。
|
|
|
|
x[i, ] <- list(...)
x[i, ] <- a
は,vec_slice(x[[j_1]], i) <- a[[1]]
, vec_slice(x[[j_2]], i) <- a[[2]]
, … .4 と同じです.
リサイクルできるのはサイズ1の値だけです。
|
|
互換性のため、行数を超えてインデックスを作成する場合は警告のみが表示されます。 既存のデータの最後に行を追加することは、警告なしでサポートされています。
|
|
|
|
|
|
|
互換性のために、i
は正の数を含む文字ベクトルにすることもできます。
x[i, j] <- a
の定義x[i, j] <- a
は x[i, ][j] <- a
と同等である。5: x[i, j]
はサブセットに対して対称であり、列のサブアサインに対して対称である。
x[i, j]
へのサブアサインは、データフレームよりもTibblesの方が厳しい。 x[i, j] <- a
は、既存のカラムのデータタイプを変更することはできません。
|
|
|
|
|
|
|
|
つまり、NA
(これは論理)で初期化されたカラムには、後から別の型の値を入れることはできません。 カラムの初期化には正しい型の NA
を使用してください。
|
|
新しい列に対しては、x[i, j] <- a
で、割り当てられていない行を NA
で埋めます。
|
|
同様に、新しい行に対しては、x[i, j] <- a
とすることで、割り当てられていない列をNA
で埋めることができます。
x[[i, j]] <- a
の定義i
は長さ1の数値ベクトルでなければならない。 x[[i, j]] <- a
は x[i, ][[j]] と同じです。<- a
.6.
注: vec_size(a)
は 1 にしてください。 x[i, ] <-
とは異なり、x[[i, ]] <-
は有効ではありません。
x[,j]
はx[j]
と同じなので、x[,]
はx[,j]
と同じです。↩
x[i, j]のより効率的な実装は、
x[j][i, ]`にフォワードします。↩
$
はサブセットとサブアサインを比較するときに [[
とほぼ完全に対称的な動作をします。↩
x[i, ]
はサブセットとサブアサインに対して対称性があります。↩
x[i, j]
はサブセットとサブアサインに対して対称的です。 x[i, j] <- a
のより効率的な実装では、x[j][i, ] <- a
に進みます。↩
x[[i, j]]
はサブセットとサブアサインに対して対称性があります。 効率的な実装では、i
と j
がスカラーであることをチェックして、x[i, j][[1]] <- a
に進みます。↩