length()関数は、Rを勉強すると比較的始めの方に出会う関数だと思います。長さを返す関数であるということは想像できるのですが、その挙動をきちんと理解していないと、引数の型によっては期待しているものと違う答えが返ってきます。そして、誤った評価をしてしまう…。簡単な関数ですから、そんなことにならないように、きちんと理解しておきましょう。
length()関数が返すもの
Rのlength() 関数は、vector, list, matrix, data.frameなどの長さを返す関数ですが、引数の型によっては混乱しがちな結果を返してくるので、整理します。
- vector : 要素数を返す
- list : 要素数 ( = 項目数) を返す
- matrix : (2次元要素の)全要素数を返す
- data.frame : 列数( = 項目数) を返す
- array : (n次元要素の)全要素数を返す
v1 <- 1:24
v2 <- "this is test case"
l <- list(x = 1, y = 1.5, z = "c")
m <- matrix(1:24, nrow = 6)
df <- data.frame(x = c(1:5), y = rep(NA, 5), z = letters[1:5])
a <- array(1:24, dim = c(2, 3, 4))
length(v)
length(l)
length(m)
length(df)
length(a)
> length(v1)
[1] 24 # vector 要素数
> length(v2)
[1] 1 # vector v2は1要素の文字列ベクトルなので、1が返ってくる
> length(l)
[1] 3 # list 要素数 ( = 項目数)
> length(m)
[1] 24 # matrix 全要素数
> length(df)
[1] 3 # data.frame 列数( = 項目数)
> length(a)
[1] 24 # array 全要素数
1次元データ構造であるvectorやlistではlength()関数はその要素数を返します(逆にそれ以外にlengthらしきものがない。ただし、文字列の場合は注意)。また、2次元構造をもつmatrixとdata.frameでは返ってくる中身が異なります。
間違いがちなケース(文字列とdata.frameとmatrix)
間違いがちなのが、lengthに「文字列」を渡したときと、data.frame, matrixを渡したとき。
文字列
Rにおけるcharacterは、文字列のベクトルで、文字のベクトルではないので、ただの文字列(=1要素の文字列ベクトル)をlengthに渡した場合、返ってくる答えは1になります。文字列の長さが知りたい場合は、nchar()を使います。
また、文字列操作用のパッケージであるstringrパッケージを使えばstr_length()関数でも文字列の長さを得ることができます。文字列の「長さ」を「length」というキーワードがついた関数で取得できると言う意味で、感覚的にもマッチします。あまり多くのパッケージを導入したくないという方もいるかと思いますが、stringrパッケージはRで最もポピュラーとも言えるtidyverseにも含まれているパケージなので、導入しておいて損はないと思います。というか、導入しないと損だと思います。
v2 <- "this is test case"
> length(v2)
[1] 1 # v2は1要素の文字列ベクトルなので、1が返ってくる
> nchar(v2)
[1] 17 # 文字列の長さを知りたい場合はnchar()を使う
> stringr::str_length(v2)
[1] 17 # str_length()関数でも文字列の長さを取得できる
stringrパッケージについてはこちらから
matrixとdata.frame
行数、列数が知りたい場合
matrixやdata.frameにlength()関数を適用したい場合って、行数や列数を知りたい場合ではないでしょうか?後述するようにmatrixやdata.frameにlength()を適用した場合、両者の振る舞いが異なってわかりにくいので、行数や列数を知りたい場合にはlength()関数は使うべきではないと思います。行数や列数を知りたいのであれば、nrow()関数やncol()関数、もしくは、dim()関数を使うべきです。
以下のような2次元構造をもつmatrixを考えます。
m <- matrix(1:8, ncol = 2)
m
[,1] [,2]
[1,] 1 5
[2,] 2 6
[3,] 3 7
[4,] 4 8
また、このmatrix mをdata.frameに変換した変数をdfとします。
df <- data.frame(m)
df
X1 X2
1 1 5
2 2 6
3 3 7
4 4 8
表示のされ方は若干異なりますが、保持しているデータは同じものです(当たり前ですね)。これに対して、nrow(), ncol(), dim()を適用するとmatrix, data.frameのどちらの場合も行数、列数、行数&列数を取得することができます。
matrixに適用した場合
> nrow(m) # 行数
[1] 4
> ncol(m) # 列数
[1] 2
> dim(m) # 行数 & 列数
[1] 4 2
data.frameに適用した場合
> nrow(df) # 行数
[1] 4
> ncol(df) # 列数
[1] 2
> dim(df) # 行数 & 列数
[1] 4 2
length()関数を適用した場合
両者に対してlength()関数を適用すると
> length(m) [1] 8 # 総要素数
> length(df) [1] 2 # 列数
matrixに適用した場合は総データ数、data.frameに適用した場合は列数が返ってきます。matrixは本質的にはベクトルであり、data.frameは本質的にはリストであるため、length()に適用するとこのような振る舞いをします。
matrixとdata.frameは似て非なるもの。両者の違いはこちらから
まとめ
Rは文法に少し癖があると言われますが、慣れてくるととても便利なツールです。でも、きちんと理解していないと落とし穴(Rの癖)にはまる可能性があります。matrixとdata.frameは似て非なるもの。
ベクトル化されているがゆえの癖としては、こんなものがあります。Rを覚えはじめの頃は「 警告メッセージ: if (x >= 0) { で: 条件が長さが 2 以上なので、最初の 1 つだけが使われます 」なんてメッセージが出て、何のことかさっぱりわからず、結構戸惑いました
Rでどんなことができるかについては、一例をこちらにまとめています。
こんなこともできたりします(笑)