【R】 知らず知らず使っている関数『c()』再入門

# 趣旨
普段ベクトルを作成したりするときに使う`c()`。


```R
c("a", "b", "c")
[1] "a" "b" "c"
```

しかし「ベクトル作る関数だな」程度の認識だった私、`apply()`や`mapply()`で躓きました。
というわけで **『Rユーザーが最も使う関数`c()`を改めて見てみましょう。』** という企画。

# `c()`とは？

まずは名前から行きましょう。公式ヘルプを呼び出します。

```R
help(c)
```

こちらでも同じものが読めます。
[R: Combine Values into a Vector or List](http://search.r-project.org/R/library/base/html/c.html)

タイトルは ***『Combine Values into a Vector or List』*** です。つまり`c()`の「c」は***Combine***に由来するものなんですね。

さらに説明を読むと以下の記述があります。

>This is a generic function which combines its arguments.
>
>The default method combines its arguments to form a vector. All arguments are coerced to a common type which is the type of the returned value, and all attributes except names are removed.

まあ要するに、**『引数に渡したオブジェクトをベクトルかリストの形式で結合してくれる関数』**ということですね。
ここで注目しておきたいのは **引き渡すオブジェクトの種類（データ型・構造）に制約を設けていない** 点です。つまり、あらゆるオブジェクトを最大公約数的なカタチで結合してくれるようですね。

```R
# install.packages("Hmisc")

char <- "moji"
df <- data.frame(d = 888, 999)

# c() による結合
cmb1 <- c(char, df)

# 結合データの構造を確認
Hmisc::list.tree(cmb1) 
```
```:データ構造
 cmb1 = list 2 (528 bytes)
.  [[1]] = character 1= moji 
.  d = double 2= 888 999
```
このように異なるデータ型(`character`を格納した`vector` + `numeric`を格納した`data.frame`)であっても問題なくリスト型データに結合してくれます。

そう、**意外と『万能』なんです。**


# 二種類の返り値
`c()`の返り値は、`vector型`または`list型`の2種類があります。それによって挙動が微妙に違うようです。

## リストによる返り値

こっちのほうが簡単なので先に見ていきましょう。

```R
env <- new.env()
char <- "moji"
num <- 1
int <- as.integer(0)
vec <- c("p", "q")
fct <- factor(c("Z", "Y", "X"), levels = c("X", "Y", "Z"))
mtr <- matrix(3330:3335, 2,3)
lst <- list(l1 = 111, l2 = "LIST")
df <- data.frame(d = c(888, 999))
fun <- function(x, y) x + y

# c() による結合
cmb2 <- c(env, char, num, int, vec, fct, mtr, lst, df, fun)

# 結合データの構造を確認
Hmisc::list.tree(cmb2, maxcomp = length(cmb2))
```
```:データ構造
 cmb2 = list 19 (3584 bytes)
.  [[1]] = environment 0
.  [[2]] = character 1= moji 
.  [[3]] = double 1= 1
.  [[4]] = integer 1= 0
.  [[5]] = character 1= p 
.  [[6]] = character 1= q 
.  [[7]] = integer 1= 3
.  [[8]] = integer 1= 2
.  [[9]] = integer 1= 1
.  [[10]] = integer 1= 1
.  [[11]] = integer 1= 2
.  [[12]] = integer 1= 3
.  [[13]] = integer 1= 4
.  [[14]] = integer 1= 5
.  [[15]] = integer 1= 6
.  l1 = double 1= 111
.  l2 = character 1= LIST 
.  d = double 2= 888 999
.  [[19]] = function 1
. A  srcref = integer 8( srcref )= 1 8 1 27 8 27 1 ...
. A A  srcfile = environment 2( srcfilecopy srcfile )
```

**「単一のベクトルで表現されないデータ構造」**を格納したオブジェクトを1つ以上含めて結合しようとすると`list型`データが返却されます。その際、`character`、`numeric`といった、結合するオブジェクトのデータ型（データ「構造」ではない。）は返却後も保持されています。
上の例では、`list型`・`data.frame型`・`environment型`・`funcion型`が「単一のベクトルで表現されないデータ構造」に該当します。

## ベクトルによる返り値
**「単一のベクトルで表現できるデータ構造」**のみを結合するとvector型データが返却されます。
上の例では、`list型`・`data.frame型`・`environment型`・`funcion型`が「単一のベクトルで表現されないデータ構造」に該当します。

# 属性について
注意したいのが、`c()`による結合は、**`$names`属性以外のデータを保持しない** ということです。
よく分からないかもしれませんが、要はオブジェクトのメインコンテンツ以外は切り捨てられるということです。これは冒頭で引用したヘルプにも書いてあることです。

> (中略) all attributes except names are removed.

これがどのように影響するのか、具体的には例えば以下のようなことが挙げられます。

|結合するデータ型|症状|回避策|
|---|---|---|
|`data.frame型`|`data.frame`属性が失われるため、`list型`に変換されてから結合されてしまう。|`list()`による結合|
|`matrix型` |`dim`属性が失われるため、一行のベクトルに変換されてしまう。|一旦`data.frame型`へ変換させる。<BR><BR>その上でさらに`list型`を回避したい場合は上記を参考。|
|`factor型`|`levels`・`ordered`等の属性情報が失われるため、そのまま結合させると`integer型`のベクトルに変換されてしまう。|ラベルを保持したい場合は、`as.vector()`等で変換してから結合を行う。<BR><BR>属性全体を保持したい場合は、`list()`による結合が有効。|



## list()による結合
以上に関連して、`c()`を使った結合と`list()`による結合には多少の差があります。

```R:c()&nbsp;による結合
> c(df)
$d
[1] 888 999
```

```R:list()&nbsp;による結合
> list(df)
[[1]]
    d
1 888
2 999
```
```R:データ構造の比較
# c() による結合
# data.frameがlist型に強制変換されている
> c(df)[[1]]
[1] 888 999
> is.data.frame(c(df)[[1]])
[1] FALSE


# list()&nbsp;による結合
# data.frameが保持されている
> list(df)[[1]]
    d
1 888
2 999

> is.data.frame(list(df)[[1]])
[1] TRUE

```
このように、`c()`の場合はデータ構造は一律で`vector型`または`list型`に変換されますが、`list()`の場合は元のデータ構造が保持されることになります。
また、`matrix型`の場合も示していきます。

```R:c()&nbsp;による結合
> c(mtr)
[1] 3330 3331 3332 3333 3334 3335
```
```R:list()&nbsp;による結合
> list(mtr)
[[1]]
     [,1] [,2] [,3]
[1,] 3330 3332 3334
[2,] 3331 3333 3335
```

## factor型データの結合
もう一つ、factor型を結合したときの挙動を記しておきます。

```R
> c(fct)
[1] 3 2 1
```

このように順序データとして結合されます。これが望ましいケースもあるので、回避策をするか否かはケースバイケースでご判断ください。

```R:回避策1
# ラベルのほうが残るが、Levels等の属性情報は失われるため、
# 結合後は単なる文字列ベクトルとして扱いたい場合に有効。

> c(as.vector(fct))
[1] "Z" "Y" "X"

```
```R:回避策2
# すべての属性情報を保持できるため、
# 結合後もfactorとして扱いたい場合には有効。

> list(fct)
[[1]]
[1] Z Y X
Levels: X Y Z
```

## names属性について
ここまでは属性情報は切り捨てられるというお話で進めてきましたが、例外的に`names`属性については維持されるようです。

```R
> vec2 <- vec
> names(vec2) <- c("P", "Q")
> c(vec, vec2)
          P   Q 
"p" "q" "p" "q" 
```



# ベクトル結合の注意点
ベクトルを結合する際に、返り値がリストの場合、ベクトルの各要素がリストの各要素に変換されてしまいます。

```R
> c(vec, df)
[[1]]
[1] "p"

[[2]]
[1] "q"

$d
[1] 888 999
```

これを回避したい場合は、`list()`による結合か、一度ベクトルを`list型`データに格納することをおすすめします。

```R:list()&nbsp;による変換
> list(vec, df)
[[1]]
[1] "p" "q"

[[2]]
    d
1 888
2 999
```
```R:list()&nbsp;を噛ませた&nbsp;c()&nbsp;による変換
> c(list(vec), df)
[[1]]
[1] "p" "q"

$d
[1] 888 999


# data.frameも保持したい場合は以下のようにする
> c(list(vec), list(df))
[[1]]
[1] "p" "q"

[[2]]
    d
1 888
2 999

```

# オプションについて
`c()`にはいくつかのオプションが引数で設定できます。

|引数|説明|規定値|
|---|---|---|
|`recursive`|`vector型`に強制変換するか|`FALSE`|
|`use.names`|`names`属性を保持するか|`TRUE`|

## recursive
`data.frame型`との結合のように返り値が通常`list型`になる場合に、強制的に`vector型`に変換するかどうかを設定できます。

```R:recursive&nbsp;=&nbsp;F&nbsp;(規定値)
# 
c(df, char)
> c(df, char)
$d
[1] 888 999

[[2]]
[1] "moji"
```
```R:recursive&nbsp;=&nbsp;T
> c(df, char, recursive = T)
    d1     d2        
 "888"  "999" "moji" 
```

## use.names
名前の通り、names属性を保持するか否かを選択できます。

```R:names&nbsp;=&nbsp;T&nbsp;(規定値)
> c(vec, vec2)
          P   Q 
"p" "q" "p" "q"
```
```R:names&nbsp;=&nbsp;F
> c(vec, vec2, use.names = F)
[1] "p" "q" "p" "q"
```

# おわりに
基本的な関数ながら意外と万能で奥深い？`c()`でした。

とはいえ普段はそんなに気にせず使ってもいいと思いますが、たまにトラブルが起きるかもしれませんので、その時はまた見返してもらえたら嬉しいですね。

Enjoy!

おしまい。

# 参考

- [R: Combine Values into a Vector or List](http://search.r-project.org/R/library/base/html/c.html)