R - droplevels関数のexceptとexcludeの違い

R言語のdroplevels関数がわかりづらいと思ったので実際に動かしてみました。

## droplevelsの仕様
以下はdroplevelsの引数の説明です。処理対象データ(x)がベクトル(factor)の場合とデータフレーム(data.frame)の場合で処理が異なるため、2種類あります。(要はオーバーロードの状態になっている)
オプションにexceptとexcludeがありますが、どちらも「除外する」のような意味で違いがわからないので、これらを使用した場合の動作を確認しました。

```R
# droplevels.factor
droplevels(x, exclude = if(anyNA(levels(x))) NULL else NA, …)

# droplevels.data.frame
droplevels(x, except = NULL, exclude, …)
```

## 動作環境
R version 3.4.3

## テストデータ
まずはデータの元の状態を確認します。
テストデータにはirisを使います。
以下の通り、irisはdata.frame形式で、列が5種類あります。(Sepal.Length、Sepal.Width、Petal.Length、Petal.Width、Species)

```R
> str(iris)
'data.frame':   150 obs. of  5 variables:
 $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
 $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
 $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
 $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
 $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
```

irisのSpecies列にはレベル(取りうる値)が3種類あり、以下のように各レベルが50件ずつあります。(setosa, versicolor, virginica)

```R
> table(iris$Species)
    setosa versicolor  virginica 
        50         50         50 
```

irisはSpecies列でソートされているため、最初の100件にはvirginicaが使われていません(0件)。
しかしこの最初の100件を抽出して、virginicaが未使用(0件)の状態になっても、virginicaの存在は出力に残ります。

```R
> ir = iris[1:100,]
> table(ir$Species)
    setosa versicolor  virginica 
        50         50          0 
```

## droplevels関数：未使用レベルを削除する
未使用レベルが残っていると、後続の処理や表記で都合が悪い場合があるため、droplevelsで未使用レベルを削除する等の対処を施します。(たとえば未使用レベルを残してSMOTEを使うとエラーになります:punch_tone1:)
droplevels(x)でxにある未使用レベルを削除できます。以下の例ではvirginicaが消えています。

```R
> table(droplevels(ir$Species))
    setosa versicolor 
        50         50 

> table(droplevels(ir)$Species) #データフレームごと食わせても削除してくれる
    setosa versicolor 
        50         50 
```

## excludeオプション：指定したレベルを使用/未使用に関わらず削除する
excludeオプションでレベルを指定すると、未使用でない場合も削除します。
以下の例では、未使用レベルのvirginicaが消えるだけでなく、未使用ではないsetosaも消えます。
excludeはfactorとdata.frameの両方で使用できます。

```R
> table(droplevels(ir$Species, exclude = "setosa"))
versicolor 
        50 

> table(droplevels(ir, exclude = "setosa")$Species) #データフレームごと食わせても削除してくれる
versicolor 
        50 
```

## exceptオプション：指定した列ではレベルを削除しない
exceptオプションで列を指定すると、未使用レベルがある場合でも削除しなくなります。
以下の例ではSpecies列を指定することで、Speciesに未使用レベルがあっても消えなくなります。
exceptは処理対象データ(x)がdata.frameの場合に使用可能であり、factorの場合は一列しかないためか、当記事の冒頭の説明にもあるように、オプション自体が用意されていません。

```R
> table(droplevels(ir, except = 5)$Species) #何列目にあるかで指定する
    setosa versicolor  virginica 
        50         50          0 

> table(droplevels(ir, except = "Species")$Species) #列名でも良い
    setosa versicolor  virginica 
        50         50          0 

> table(droplevels(ir$Species, except = 1)) #factorでは用意されていない(使っても消える)
    setosa versicolor 
        50         50 

> table(droplevels(ir$Species, except = "Species")) #factorでは用意されていな(以下略
    setosa versicolor 
        50         50 
```

## まとめ
|-|exclude|except|
|:-:|:-:|:-:|
|動作の概要|指定したレベルを削除する|指定した列ではレベルを削除しない|
|factorで使えるか|使える|使えない|
|data.frameで使えるか|使える|使える|
|用例|exclude = "setosa"|except = 5（あるいは　except = "Species"）|

## 参考にしたページ
droplevels function | R Documentation
https://www.rdocumentation.org/packages/base/versions/3.4.3/topics/droplevels