【R】data.frameで文字列型をfactor型にさせない

`as.data.frame()`でも`stringsAsFactors`の引数が使えること今更ながら知りまして、これを機にちょっとまとめてみました。

# 場面別にまとめました
## データフレーム生成時
「引数に`stringsAsFactors = F`を指定する」で解決します。
### ファイルから読み込み時
下記データをただ読み込みと、3列目がfactor化してしまいます。

| yes | no | churn |
|:-----------------|:------------------|:------------------|
| 0.13717622958469677 | 0.8628237704153032 | no |
| 0.053731282512169964 | 0.94626871748783 | no |
| 0.12273577469177754 | 0.8772642253082225 | no |
| 0.1780542822350093 | 0.8219457177649907 | yes |
| 0.028350089708717996 | 0.971649910291282 | no |

```R
> data.factor <- read.delim("pred.txt", header = T, sep = "\t", quote = "")
> str(data.factor)
# 'data.frame':	3326 obs. of  3 variables:
#  $ yes  : num  0.1372 0.0537 0.1227 0.1781 0.0284 ...
#  $ no   : num  0.863 0.946 0.877 0.822 0.972 ...
#  $ churn: Factor w/ 2 levels "no","yes": 1 1 1 2 1 1 1 1 2 1 ...
```
引数に`stringsAsFactors = F`を指定して、因子型化を防ぎます。

```R
> data.nofactor <- read.delim("pred.txt", header = T, sep = "\t", quote = "", stringsAsFactors = F)
> str(data.nofactor)
# 'data.frame':	3326 obs. of  3 variables:
#  $ yes  : num  0.1372 0.0537 0.1227 0.1781 0.0284 ...
#  $ no   : num  0.863 0.946 0.877 0.822 0.972 ...
#  $ churn : chr  "no" "no" "no" "yes" ...
```
ちなみに、`readr::read_delim()`等なら、読み込み時の型を指定できます。
ただ、データフレームではなくtibbleになります。

```R
> tibble.data <- readr::read_delim("pred.txt", delim = "\t", quote = "", col_names = T, col_types = "nnc")
> str(tibble.data)
# Classes ‘spec_tbl_df’, ‘tbl_df’, ‘tbl’ and 'data.frame':	3326 obs. of  3 variables:
#  $ yes  : num  0.1372 0.0537 0.1227 0.1781 0.0284 ...
#  $ no   : num  0.863 0.946 0.877 0.822 0.972 ...
#  $ churn : chr  "no" "no" "no" "yes" ...
#  - attr(*, "spec")=
#   .. cols(
#   ..   yes = col_number(),
#   ..   no = col_number(),
#   ..   churn = col_character(),
#   .. )
```
### 別のベクトルから生成するとき
同様に、引数に`stringsAsFactors = F`を指定して、因子型化を防ぎます。

```R
> data.factor <- data.frame(a = c(1,2,3), b = c(0.1,0.2,0.3), c = c("one","two","three"))
> str(data.factor)
# 'data.frame':	3 obs. of  3 variables:
#  $ a: num  1 2 3
#  $ b: num  0.1 0.2 0.3
#  $ c: Factor w/ 3 levels "one","three",..: 1 3 2
> data.nofactor <- data.frame(a = c(1,2,3), b = c(0.1,0.2,0.3), c = c("one","two","three"), stringsAsFactors = F)
> str(data.nofactor)
# 'data.frame':	3 obs. of  3 variables:
#  $ a: num  1 2 3
#  $ b: num  0.1 0.2 0.3
#  $ c: chr  "one" "two" "three"
```

### as.data.frame()
`as.data.frame()`でデータフレームに変換するときでも、`stringsAsFactors = F`です。
apply系でmatrixを出力した後にまたデータフレームに戻すときなどで使えるかと思います。

```R
> data.matrix <- matrix(c("1","2","3","0.1","0.2","0.3","one","two","three"), 3, 3)
> data.matrix
#      [,1] [,2]  [,3]   
# [1,] "1"  "0.1" "one"  
# [2,] "2"  "0.2" "two"  
# [3,] "3"  "0.3" "three"
> data.factor <- as.data.frame(data.matrix)
> str(data.factor)
# 'data.frame':	3 obs. of  3 variables:
#  $ V1: Factor w/ 3 levels "1","2","3": 1 2 3
#  $ V2: Factor w/ 3 levels "0.1","0.2","0.3": 1 2 3
#  $ V3: Factor w/ 3 levels "one","three",..: 1 3 2
> data.nofactor <- as.data.frame(data.matrix, stringsAsFactors = F)
> str(data.nofactor)
# 'data.frame':	3 obs. of  3 variables:
#  $ V1: chr  "1" "2" "3"
#  $ V2: chr  "0.1" "0.2" "0.3"
#  $ V3: chr  "one" "two" "three"
```

## カラムごとに変換
データフレーム生成後でも、factor型→charactor型に変換可能です。
### as.character()
```R
> str(data.factor)
# 'data.frame':	3326 obs. of  3 variables:
#  $ yes  : num  0.1372 0.0537 0.1227 0.1781 0.0284 ...
#  $ no   : num  0.863 0.946 0.877 0.822 0.972 ...
#  $ churn: Factor w/ 2 levels "no","yes": 1 1 1 2 1 1 1 1 2 1 ...
> data.nofactor <- data.factor
> data.nofactor$churn <- as.character(data.nofactor$churn)
> str(data.nofactor)
# 'data.frame':	3326 obs. of  3 variables:
#  $ yes  : num  0.1372 0.0537 0.1227 0.1781 0.0284 ...
#  $ no   : num  0.863 0.946 0.877 0.822 0.972 ...
#  $ churn : chr  "no" "no" "no" "yes" ...
```
### levels()
"no"と"yes"の二つの因子としてラベル付けされているので、そのラベル名を返す処理を使えば、文字列型に変換できます。

```R
> str(data.factor)
# 'data.frame':	3326 obs. of  3 variables:
#  $ yes  : num  0.1372 0.0537 0.1227 0.1781 0.0284 ...
#  $ no   : num  0.863 0.946 0.877 0.822 0.972 ...
#  $ churn: Factor w/ 2 levels "no","yes": 1 1 1 2 1 1 1 1 2 1 ...
> levels(data.factor$churn)  # levels()の挙動確認
# [1] "no"  "yes"
> head(levels(data.factor$churn)[data.factor$churn], 5)  # levels()の挙動確認
# [1] "no" "no" "no" "yes" "no"
> data.nofactor <- data.factor
> data.nofactor$churn <- levels(data.nofactor$churn)[data.nofactor$churn]
> str(data.nofactor)
# 'data.frame':	3326 obs. of  3 variables:
#  $ yes  : num  0.1372 0.0537 0.1227 0.1781 0.0284 ...
#  $ no   : num  0.863 0.946 0.877 0.822 0.972 ...
#  $ churn : chr  "no" "no" "no" "yes" ...
```

### transform()
引数を増やしていけば、複数カラムの文字列型への変換が一行で書けます。
カラム名だけで書けるのでややすっきりします。

```R
> str(data.factor)
# 'data.frame':	3326 obs. of  3 variables:
#  $ yes  : num  0.1372 0.0537 0.1227 0.1781 0.0284 ...
#  $ no   : num  0.863 0.946 0.877 0.822 0.972 ...
#  $ churn: Factor w/ 2 levels "no","yes": 1 1 1 2 1 1 1 1 2 1 ...
> data.nofactor <- transform(data.factor, churn = levels(churn)[churn])
> str(data.nofactor)
# 'data.frame':	3326 obs. of  3 variables:
#  $ yes  : num  0.1372 0.0537 0.1227 0.1781 0.0284 ...
#  $ no   : num  0.863 0.946 0.877 0.822 0.972 ...
#  $ churn : chr  "no" "no" "no" "yes" ...
```

# おわり
（こんなこと書くと元も子もないですが）`as.data.frame()`で非因子化の引数が使えることを知ったのは、公式のドキュメンテーションでした。
公式を参照するのは大事だなと思いつつ、小さなソリューションが見つかりやすくなればと思い、この記事を書いた次第です。