Rのオブジェクトのattributes（属性）についてのメモ

# はじめに

機械学習の勉強を始めたVBAユーザです。
備忘録としてPython・Rの文法をVBAと比較しながらまとめています。
Rの属性（attributes）について気になったのでまとめてみました。

**目次**

- [属性について](#属性について)
   - [属性とは](#属性とは)
   - [属性の表示](#属性の表示)
   - [属性の付与](#属性の付与)
      - [attributes関数](#attributes関数)
      - [attr関数](#attr関数)
   - [属性の変更](#属性の変更)
   - [属性の例](#属性の例)
      - [comment属性](#comment属性)
      - [names属性](#names属性)
         - [ベクトルのnames属性](#ベクトルのnames属性)
         - [リストのnames属性](#リストのnames属性)
   - [主なデータ構造の属性](#主なデータ構造の属性)
      - [行列の属性](#行列の属性)
      - [配列の属性](#配列の属性)
      - [データフレームの属性](#データフレームの属性)
      - [因子の属性](#因子の属性)
      - [順序付き因子の属性](#順序付き因子の属性)
   - [属性の付与によるデータ構造の構成](#属性の付与によるデータ構造の構成)
      - [ベクトルから行列の構成](#ベクトルから行列の構成)
      - [ベクトルから配列の構成](#ベクトルから配列の構成)
      - [リストからデータフレームの構成](#リストからデータフレームの構成)
      - [整数ベクトルから因子ベクトルの構成](#整数ベクトルから因子ベクトルの構成)
      - [整数ベクトルから順序付き因子ベクトルの構成](#整数ベクトルから順序付き因子ベクトルの構成)


# 属性について

## 属性とは

Rではオブジェクト（データ）に属性（attribute）を付与できます。

例として数ベクトルにcomment属性を付与してみます。`comment()`関数を使います。オブジェクトにコメントを付けておくことができます。

```R:R
v <- 1:5
v
# [1] 1 2 3 4 5
comment(v) <- "numerical vector"
v
# [1] 1 2 3 4 5
comment(v)
# [1] "numerical vector"
str(v)
# Named int [1:5] 1 2 3 4 5
# - attr(*, "comment")= chr "numerical vector"
```
そのまま表示するだけでは何も変わっていないように見えますが、`comment()`関数や`str()`関数（オブジェクトの内容を情報付きで表示する関数）でコメントが付与されているのを確認できます。

別の例として、names属性を付与してみます。`names()`関数を使います。ベクトルの要素に名前を付けることができます。名前でアクセスもできるようになります。

```R:R
names(v) <- paste("v", 1:5, sep="")
v
# v1 v2 v3 v4 v5 
#  1  2  3  4  5 
names(v)
# [1] "v1" "v2" "v3" "v4" "v5"
str(v)
# Named int [1:5] 1 2 3 4 5
# - attr(*, "comment")= chr "numerical vector"
# - attr(*, "names")= chr [1:5] "v1" "v2" "v3" "v4" ...
v
v["v1"]
# v1 
#  1 
```

## 属性の表示
オブジェクトに付与されている属性を見るには、`str()`関数、`attributes()`関数、`attr()`関数などを使います。`str(オブジェクト)`、`attributes(オブジェクト)`、`attr(オブジェクト, "属性名")`の形で使用します。また、`comment()`、`names()`関数などの用意された関数がある場合はそれも使えます。

```R:R
str(v)
# Named int [1:5] 1 2 3 4 5
# - attr(*, "comment")= chr "numerical vector"
# - attr(*, "names")= chr [1:5] "v1" "v2" "v3" "v4" ...
attributes(v)
# $comment
# [1] "numerical vector"
# 
# $names
# [1] "v1" "v2" "v3" "v4" "v5"
# 
attr(v, "comment")
# [1] "numerical vector"
attr(v, "names")
# [1] "v1" "v2" "v3" "v4" "v5"
```

## 属性の付与
オブジェクトに属性を付与するのも`attributes()`関数、`attr()`関数を使います。`attributes(オブジェクト)<-属性のリスト`、`attr(オブジェクト, "属性名")<-属性`の形で使います。`comment()`、`names()`などの用意された関数がある場合はそれも使えます。

### attributes関数

```R:R
v <- 1:5
attributes(v)
# NULL
attributes(v) <- list(comment="numerical vector", names=paste("v", 1:5, sep=""))
attributes(v)
# $comment
# [1] "numerical vector"
# 
# $names
# [1] "v1" "v2" "v3" "v4" "v5"
# 
```

### attr関数

```R:R
v <- 1:5
attributes(v)
# NULL
attr(v, "comment") <- "numerical vector"
attributes(v)
# $comment
# [1] "numerical vector"
# 
attr(v, "names") <- paste("v", 1:5, sep="")
attributes(v)
# $comment
# [1] "numerical vector"
# 
# $names
# [1] "v1" "v2" "v3" "v4" "v5"
# 
attr(v, "komento") <- "bekutoru"
str(v)
# Named int [1:5] 1 2 3 4 5
# - attr(*, "comment")= chr "numerical vector"
# - attr(*, "names")= chr [1:5] "v1" "v2" "v3" "v4" ...
# - attr(*, "komento")= chr "bekutoru"
```

## 属性の変更
同じ関数で属性を変更できます。

```R:R
attr(v, "comment") <- "数ベクトル"
attributes(v)
# $comment
# [1] "数ベクトル"
# 
attr(v, "names") <- paste("要素", 1:5, sep="")
attributes(v)
# $comment
# [1] "数ベクトル"
# 
# $names
# [1] "要素1" "要素2" "要素3" "要素4" "要素5"
# 
v
# 要素1 要素2 要素3 要素4 要素5 
#     1     2     3     4     5
```

また、属性に`NULL`を代入することで属性を削除できます。

```R:R
attr(v, "names") <- NULL
attributes(v)
# $comment
# [1] "数ベクトル"
# 
attributes(v) <- NULL
attributes(v)
# NULL
str(v)
# int [1:5] 1 2 3 4 5
```

## 属性の例

### comment属性
オブジェクトにコメントを付けられます。

```R:R
v <- 1:6
comment(v) <- "vector"
str(v)
# int [1:6] 1 2 3 4 5 6
# - attr(*, "comment")= chr "vector"
```

### names属性
ベクトルやリストの要素に名前を付けられます。名前で要素にアクセスできるようになります。

#### ベクトルのnames属性
ベクトルの要素に名前を付けておくと、`ベクトル名["要素名"]`で要素にアクセスできます。

```R:R
v <- 1:6
names(v) <- LETTERS[1:6]
v
# A B C D E F 
# 1 2 3 4 5 6
str(v)
# Named int [1:6] 1 2 3 4 5 6
# - attr(*, "names")= chr [1:6] "A" "B" "C" "D" ...
v["C"]
# C 
# 3 
```

#### リストのnames属性
[リスト](http://cse.naro.affrc.go.jp/takezawa/r-tips/r/23.html)の要素に名前を付けておくと、`リスト名[["要素名"]]`または`リスト名$要素名`で要素にアクセスできます。

```R:R
L <- list(123, "abc", 1:3)
L
# [[1]]
# [1] 123
# 
# [[2]]
# [1] "abc"
# 
# [[3]]
# [1] 1 2 3
# 
L[[1]]
# [1] 123
names(L) <- c("x", "y", "z")
L
# $x
# [1] 123
# 
# $y
# [1] "abc"
# 
# $z
# [1] 1 2 3
# 
str(L)
# List of 3
#  $ x: num 123
#  $ y: chr "abc"
#  $ z: int [1:3] 1 2 3
L[["x"]]
# [1] 123
L$x
# [1] 123
```

リストを作成するときに最初から名前を付けておくこともできます。

```R:R
L <- list(x=123, y="abc", z=1:3)
L
# $x
# [1] 123
# 
# $y
# [1] "abc"
# 
# $z
# [1] 1 2 3
# 
```


## 主なデータ構造の属性
行列、配列、データフレーム、因子、順序付き因子の属性を見てみます。

### 行列の属性
行列（matrix）にはdim属性があります。

```R:R
m <- matrix(1:6, 2, 3)
m
#      [,1] [,2] [,3]
# [1,]    1    3    5
# [2,]    2    4    6
str(m)
# int [1:2, 1:3] 1 2 3 4 5 6
attributes(m)
# $dim
# [1] 2 3
# 
attr(m, "dim")
# [1] 2 3
```

また、dimnames属性で、行列の行・列に名前を付けることもできます。

```R:R
dimnames(m) <- list(c("r1","r2"), c("c1","c2","c3"))
m
#    c1 c2 c3
# r1  1  3  5
# r2  2  4  6
str(m)
# int [1:2, 1:3] 1 2 3 4 5 6
# - attr(*, "dimnames")=List of 2
# ..$ : chr [1:2] "r1" "r2"
# ..$ : chr [1:3] "c1" "c2" "c3"
attributes(m)
# $dim
# [1] 2 3
# 
# $dimnames
# $dimnames[[1]]
# [1] "r1" "r2"
# 
# $dimnames[[2]]
# [1] "c1" "c2" "c3"
# 
# 
```

行列については[こちら](https://qiita.com/swathci/items/715aba6db368f53b3a2e)も参照。

## 配列の属性
[配列](http://cse.naro.affrc.go.jp/takezawa/r-tips/r/23.html)（array）にはdim属性があります。また、行列と同様に、dimnames属性でを付けることもできます。

```R:R
a <- array(1:24, dim=c(3,4,2))
a
# , , 1
# 
#      [,1] [,2] [,3] [,4]
# [1,]    1    4    7   10
# [2,]    2    5    8   11
# [3,]    3    6    9   12
# 
# , , 2
# 
#      [,1] [,2] [,3] [,4]
# [1,]   13   16   19   22
# [2,]   14   17   20   23
# [3,]   15   18   21   24
# 
str(a)
# int [1:3, 1:4, 1:2] 1 2 3 4 5 6 7 8 9 10 ...
attributes(a)
# $dim
# [1] 3 4 2
# 
attr(a, "dim")
# [1] 3 4 2
```

## データフレームの属性
[データフレーム](http://cse.naro.affrc.go.jp/takezawa/r-tips/r/39.html)（data.frame）には、names属性、class属性、row.names属性があります。

```R:R
1:3*10
# [1] 10 20 30
2:4*100
# [1] 200 300 400
3:5*1000
# [1] 3000 4000 5000
df <- data.frame(x=1:3*10, y=2:4*100, z=3:5*1000)
df
#    x   y    z
# 1 10 200 3000
# 2 20 300 4000
# 3 30 400 5000
str(df)
# 'data.frame':	3 obs. of  3 variables:
#  $ x: num  10 20 30
#  $ y: num  200 300 400
#  $ z: num  3000 4000 5000
attributes(df)
# $names
# [1] "x" "y" "z"
# 
# $class
# [1] "data.frame"
# 
# $row.names
# [1] 1 2 3
# 
df$x
# [1] 10 20 30
df$y
# [1] 200 300 400
df$z
# [1] 3000 4000 5000
```

## 因子の属性
[因子ベクトル](http://cse.naro.affrc.go.jp/takezawa/r-tips/r/16.html)（factor）には、levels属性とclass属性があります。

```R:R
f <- factor(c("M", "M", "F", "M", "F", "F"))
f
# [1] M M F M F F
# Levels: F M
str(f)
# Factor w/ 2 levels "F","M": 2 2 1 2 1 1
attributes(f)
# $levels
# [1] "F" "M"
# 
# $class
# [1] "factor"
# 
levels(f)
# [1] "F" "M"
class(f)
# [1] "factor"
```

## 順序付き因子の属性
[順序付き因子ベクトル](http://cse.naro.affrc.go.jp/takezawa/r-tips/r/16.html)（ordered factor）には、levels属性とclass属性があります。

```R:R
of <- ordered(c("M", "M", "F", "M", "F", "F"))
of
# [1] M M F M F F
# Levels: F < M
str(of)
# Ord.factor w/ 2 levels "F"<"M": 2 2 1 2 1 1
attributes(of)
# $levels
# [1] "F" "M"
# 
# $class
# [1] "ordered" "factor" 
# 
levels(of)
# [1] "F" "M"
class(of)
# [1] "ordered" "factor"
```

## 属性の付与によるデータ構造の構成
Rの基本的なデータ型であるベクトル型とリスト型から、属性を付与することで、データ構造を構成できます。
既存のオブジェクトに`attributes()`や`attr()`、あるいは`dim()`などの関数を使って属性を付与できるほか、`structure()`関数を使って属性（構造）を付与したオブジェクトを返すこともできます。

### ベクトルから行列の構成
ベクトルに、行列の属性であるdim属性を付与することで、matrixを構成できます。

```R:R
v <- 1:6
v
# [1] 1 2 3 4 5 6
str(v)
# int [1:6] 1 2 3 4 5 6
attributes(v)
# NULL
attr(v, "dim")
# NULL
dim(v)
# NULL
dim(v) <- 2:3
v
#      [,1] [,2] [,3]
# [1,]    1    3    5
# [2,]    2    4    6

v <- 1:6
attr(v, "dim") <- 2:3
v
#      [,1] [,2] [,3]
# [1,]    1    3    5
# [2,]    2    4    6

v <- 1:6
attributes(v) <- list(dim=2:3)
v
#      [,1] [,2] [,3]
# [1,]    1    3    5
# [2,]    2    4    6

str(v)
# int [1:2, 1:3] 1 2 3 4 5 6
attributes(v)
# $dim
# [1] 2 3
attr(v, "dim")
# [1] 2 3
dim(v)
# [1] 2 3

m <- structure(1:6, dim=2:3)
m
#      [,1] [,2] [,3]
# [1,]    1    3    5
# [2,]    2    4    6
str(m)
# int [1:2, 1:3] 1 2 3 4 5 6
attributes(m)
# $dim
# [1] 2 3
attr(m, "dim")
# [1] 2 3
dim(m)
# [1] 2 3
```

逆に、行列からdim属性を削除するとベクトルに戻ります。

```R:R
m <- matrix(1:6, 2, 3)
m
str(m)
# int [1:2, 1:3] 1 2 3 4 5 6
attr(m, "dim")
# [1] 2 3
attr(m, "dim") <- NULL
m
# [1] 1 2 3 4 5 6

m <- matrix(1:6, 2, 3)
attributes(m) <- NULL
m
# [1] 1 2 3 4 5 6
```

### ベクトルから配列の構成
ベクトルに、配列の属性であるdim属性を付与することで、arrayを構成できます。
また逆に、配列から属性を削除することでベクトルに戻せます。

```R:R
v <- 1:12
dim(v) <- c(2,3,2)
v
attr(v, "dim") <- c(2,3,2)
v
attributes(v) <- list(dim=c(2,3,2))
v
# , , 1
# 
#      [,1] [,2] [,3]
# [1,]    1    3    5
# [2,]    2    4    6
# 
# , , 2
# 
#      [,1] [,2] [,3]
# [1,]    7    9   11
# [2,]    8   10   12
# 
attributes(v) <- NULL
v
# [1]  1  2  3  4  5  6  7  8  9 10 11 12
```

### リストからデータフレームの構成
同じ長さのベクトルを要素とするリストに、データフレームの属性を付与することで、データフレームを構成できます。
また逆に、データフレームから属性を削除することでリストに戻せます。

```R:R
L <- list(1:3*10, 2:4*100, 3:5*1000)
L
# [[1]]
# [1] 10 20 30
# 
# [[2]]
# [1] 200 300 400
# 
# [[3]]
# [1] 3000 4000 5000
# 
attr(L, "names") <- c("x","y","z")
attr(L, "class") <- "data.frame"
attr(L, "row.names") <- 1:3
L
#    x   y    z
# 1 10 200 3000
# 2 20 300 4000
# 3 30 400 5000

L <- list(1:3*10, 2:4*100, 3:5*1000)
attributes(L) <- list(names=c("x","y","z"),
                      class="data.frame",
                      row.names=1:3)
L
#    x   y    z
# 1 10 200 3000
# 2 20 300 4000
# 3 30 400 5000

L <- list(1:3*10, 2:4*100, 3:5*1000)
df <- structure(L, names=c("x","y","z"), row.names=1:3, class="data.frame")
df
#    x   y    z
# 1 10 200 3000
# 2 20 300 4000
# 3 30 400 5000

attributes(df) <- NULL
df
# [[1]]
# [1] 10 20 30
# 
# [[2]]
# [1] 200 300 400
# 
# [[3]]
# [1] 3000 4000 5000
# 
```
データフレームの列への[アクセス方法](http://cse.naro.affrc.go.jp/takezawa/r-tips/r/42.html)（`df$x`, `df[["x"]]`, `df[[1]]`）がリストと同じなのは、データフレームがもともとリストに構造を付与したものだからなのですね。


### 整数ベクトルから因子ベクトルの構成
整数ベクトルに、因子の属性を付与することで、因子ベクトルを構成できます。
また逆に、因子から属性を削除することで整数ベクトルに戻せます。

```R:R
v <- c(rep(1:2, 3))
v
# [1] 1 2 1 2 1 2
levels(v) <- c("M","F")
class(v) <- "factor"
v
# [1] M F M F M F
# Levels: M F

v <- c(rep(1:2, 3))
attr(v, "levels") <- c("M","F")
attr(v, "class") <- "factor"
v
# [1] M F M F M F
# Levels: M F

v <- c(rep(1:2, 3))
attributes(v) <- list(levels=c("M","F"),
                      class="factor")
v
# [1] M F M F M F
# Levels: M F

v <- c(rep(1:2, 3))
f <- structure(v, levels=c("M","F"), class="factor")
f
# [1] M F M F M F
# Levels: M F
attributes(f) <- NULL
f
# [1] 1 2 1 2 1 2
```

### 整数ベクトルから順序付き因子ベクトルの構成
整数ベクトルに、順序付き因子の属性を付与することで、順序付き因子ベクトルを構成できます。
また逆に、順序付き因子から属性を削除することで整数ベクトルに戻せます。

```R:R
v <- c(rep(1:2, 3))
v
# [1] 1 2 1 2 1 2
levels(v) <- c("M","F")
class(v) <- c("ordered", "factor")
v
# [1] M F M F M F
# Levels: M < F

v <- c(rep(1:2, 3))
attr(v, "levels") <- c("M","F")
attr(v, "class") <- c("ordered", "factor")
v
# [1] M F M F M F
# Levels: M < F

v <- c(rep(1:2, 3))
attributes(v) <- list(levels=c("M","F"),
                      class=c("ordered", "factor"))
v
# [1] M F M F M F
# Levels: M < F

v <- c(rep(1:2, 3))
of <- structure(v, levels=c("M","F"), class=c("ordered", "factor"))
of
# [1] M F M F M F
# Levels: M < F
attributes(of) <- NULL
of
# [1] 1 2 1 2 1 2
```



# 参考
- R Language Definition
   - [2.2 Attributes](https://cran.r-project.org/doc/manuals/r-release/R-lang.html#Attributes)
   - [2.3 Special compound objects](https://cran.r-project.org/doc/manuals/r-release/R-lang.html#Special-compound-objects)
      - 2.3.1 Factors
      - 2.3.2 Data frame objects
- R-Tips
   - [10. オブジェクトの表示](http://cse.naro.affrc.go.jp/takezawa/r-tips/r/10.html) `str()`, `comment()`
   - [26. names 属性と要素のラベル](http://cse.naro.affrc.go.jp/takezawa/r-tips/r/26.html) `names()`, `attributes()`, `attr()`
   - [09. データの型](http://cse.naro.affrc.go.jp/takezawa/r-tips/r/09.html) データ型
   - [16. 種々のベクトル](http://cse.naro.affrc.go.jp/takezawa/r-tips/r/16.html) `factor()`, `ordered()`