Skip to content

Instantly share code, notes, and snippets.

@kozo2
Created December 24, 2019 08:53
Show Gist options
  • Save kozo2/a0855ab01a3088bc0b4802ba4f24de0a to your computer and use it in GitHub Desktop.
Save kozo2/a0855ab01a3088bc0b4802ba4f24de0a to your computer and use it in GitHub Desktop.

logo

Exercise1: Rの基本操作

このノートブックでは、Rの基本的な使い方について説明します

データ型


あらゆるプログラミング言語において、データには型があります

例えば、Rのコンソール画面で1と打つと1と出力されますが

1

1

isという関数を使うと、これは"numeric"という型を持ち、また長さ1のvector(後述)でもあることがわかります

is(1)
  1. 'numeric'
  2. 'vector'

整数ではなく、小数点以下の数字も含んだ値(不動小数点数)もnumericです

is(2.1)
  1. 'numeric'
  2. 'vector'

ただし1Lと打つと、これはinteger(整数)としての1を定義したことになります

is(1L)
  1. 'integer'
  2. 'double'
  3. 'numeric'
  4. 'vector'
  5. 'data.frameRowLabels'

数値データは様々な計算ができます

1 + 1 # 足し算

2

3 - 1 # 引き算

2

6 * 2 # 掛け算

12

4 / 2 # 割り算

2

2^5 # 2の5乗

32

log10(5) # 5の常用対数値

0.698970004336019

ダブルクオーテーション"で文字列をくくると、これはcharacterというデータ型になります

"SAKIGAKE"

'SAKIGAKE'

is("SAKIGAKE")
  1. 'character'
  2. 'vector'
  3. 'data.frameRowLabels'
  4. 'SuperClassMethod'
is(1) # 1は数値
  1. 'numeric'
  2. 'vector'
is("1") # ""で囲むと文字列
  1. 'character'
  2. 'vector'
  3. 'data.frameRowLabels'
  4. 'SuperClassMethod'

numericとcharacter同士は計算することができません

ただし例外的に、paste関数では文字列も数値も扱えます

このようにデータの型の違いによって、関数の挙動が異なるので、注意が必要です

try(1 + "1") # 数値と文字列を足すことはできない
Error in 1 + "1" :  二項演算子の引数が数値ではありません 
paste0("SAKIGAKE", "5") # 文字列同士を連結することはできる

'SAKIGAKE5'

paste0("SAKIGAKE", 5) # paste0関数の仕様で、文字列と数値を連結することはできる

'SAKIGAKE5'

論理値TRUE/FALSEはlogicalというデータ型になります

TRUE

TRUE

is(TRUE)
  1. 'logical'
  2. 'vector'
FALSE

FALSE

is(FALSE)
  1. 'logical'
  2. 'vector'

数値や文字列が等しい(==)場合、TRUEを返します

1 == 1 # これはTRUE(==は同じという意味)

TRUE

逆に等しくない場合はFALSEを返します

1 == 2 # これはFALSE

FALSE

"SAKIGAKE" == "SAKIGAKE" # これはTRUE

TRUE

"SAKIGAKE" == "CREST" # これはFALSE

FALSE

!=(等しく無い)と書く事でTRUE/FALSEを反転させた結果を得ることができます

"SAKIGAKE" != "CREST" # これはTRUE(!=は違うという意味)

TRUE

最後に、factor(因子)というデータ型を説明します

これは、以下のように同じ値が複数回出てくるベクトル(後述)の表現としてよく使われます

JST <- factor(c("SAKIGAKE", "SAKIGAKE",
	"CREST", "CREST", "CREST",
	"ACT-X", "ACT-X", "ACT-X"))

nlevels関数で、3種類の値が含まれていることがわかります

nlevels(JST) # 3つある

3

その三種類の値は具体的に以下のようなものだとわかります

levels(JST) # SAKIGAKE, CREST, ACT-Xがある
  1. 'ACT-X'
  2. 'CREST'
  3. 'SAKIGAKE'

因子を使う上で注意する必要がある点は、as.numericで数値になってしまう点です

文字列が数値化された場合と異なり、ただの通し番号1,2,3...として数値化されるので注意したいです

as.numeric("123456")

123456

as.character(JST) # 因子を文字列に変換する
  1. 'SAKIGAKE'
  2. 'SAKIGAKE'
  3. 'CREST'
  4. 'CREST'
  5. 'CREST'
  6. 'ACT-X'
  7. 'ACT-X'
  8. 'ACT-X'
as.numeric(JST) # 因子が数値になる?(よくバグの原因になる)
  1. 3
  2. 3
  3. 2
  4. 2
  5. 2
  6. 1
  7. 1
  8. 1

データ構造


ベクトル

データには構造があります

例えば、Rでは1は長さ1のベクトルとして表現されます

# スカラは長さ1のベクトル
is(1)
  1. 'numeric'
  2. 'vector'

ベクトルを定義して、値を後で参照することができます

# c()でベクトルを作成
A <- c(2, 3, 1)
B <- c(-2, 1, -2)
# 各要素へのアクセス, Rは1-origin
A[1]

2

A[2]

3

A[3]

1

A[4] # 要素にないとNAになる

<NA>

ベクトルに対して、以下のように各種関数が既に用意されています

# 最大値、最小値、平均値、中央値
max(A)
min(A)
mean(B)
median(B)

3

1

-1

-2

# 要素ごとの掛け算(他の言語と違うところ)
A * B
  1. -4
  2. 3
  3. -2
# ベクトル同士の内積
A %*% B
A matrix: 1 × 1 of type dbl
-3

文字列でもベクトルを作れます

# 文字例でもベクトル
C <- c("A", "B", "C", "A", "AA")
# Aがどこの場所にあるか
which(C == "A")
  1. 1
  2. 4
# lengthと組み合わせて使うことが多い
length(which(C == "A"))

2

行列

同じ型のデータが二次元に配置された行列というデータ構造もあります

# matrix()で行列を作成
E <- matrix(runif(6), nrow=2, ncol=3)
E[1,]
  1. 0.260141981765628
  2. 0.988072237931192
  3. 0.0720403743907809
E[,2]
  1. 0.988072237931192
  2. 0.34279353893362

行列独自の関数が各種用意されています

# 行数、列数
nrow(E)
ncol(E)
dim(E)

2

3

  1. 2
  2. 3
# cbind、rbind
cbind(A, B)
rbind(E, A, B)
A matrix: 3 × 2 of type dbl
AB
2-2
3 1
1-2
A matrix: 4 × 3 of type dbl
0.26014200.9880722 0.07204037
0.76059770.3427935 0.62231624
A 2.00000003.0000000 1.00000000
B-2.00000001.0000000-2.00000000
# 行レベルでの和、列レベルでの和・平均値
rowSums(E)
colSums(E)
rowMeans(E)
colMeans(E)
  1. 1.3202545940876
  2. 1.72570745740086
  1. 1.02073965547606
  2. 1.33086577686481
  3. 0.694356619147584
  1. 0.440084864695867
  2. 0.575235819133619
  1. 0.510369827738032
  2. 0.665432888432406
  3. 0.347178309573792

データフレーム

matrixは同じ型のデータだけが含まれている必要がありますが、データフレームを使えば、列ごとに違うデータ型を扱うことができます

例えば、irisデータでは、1-4列目はnumeric、5列目はcharacterのデータを含んでいます

# 行列は一つの型しか扱えない
# 複数の型(数値、文字、TRUE/FALSE、因子など)を扱いたいときはデータフレーム
data(iris)
head(iris)
A data.frame: 6 × 5
Sepal.LengthSepal.WidthPetal.LengthPetal.WidthSpecies
<dbl><dbl><dbl><dbl><fct>
5.13.51.40.2setosa
4.93.01.40.2setosa
4.73.21.30.2setosa
4.63.11.50.2setosa
5.03.61.40.2setosa
5.43.91.70.4setosa
iris$Petal.Length # $で各列にアクセスできる
  1. 1.4
  2. 1.4
  3. 1.3
  4. 1.5
  5. 1.4
  6. 1.7
  7. 1.4
  8. 1.5
  9. 1.4
  10. 1.5
  11. 1.5
  12. 1.6
  13. 1.4
  14. 1.1
  15. 1.2
  16. 1.5
  17. 1.3
  18. 1.4
  19. 1.7
  20. 1.5
  21. 1.7
  22. 1.5
  23. 1
  24. 1.7
  25. 1.9
  26. 1.6
  27. 1.6
  28. 1.5
  29. 1.4
  30. 1.6
  31. 1.6
  32. 1.5
  33. 1.5
  34. 1.4
  35. 1.5
  36. 1.2
  37. 1.3
  38. 1.4
  39. 1.3
  40. 1.5
  41. 1.3
  42. 1.3
  43. 1.3
  44. 1.6
  45. 1.9
  46. 1.4
  47. 1.6
  48. 1.4
  49. 1.5
  50. 1.4
  51. 4.7
  52. 4.5
  53. 4.9
  54. 4
  55. 4.6
  56. 4.5
  57. 4.7
  58. 3.3
  59. 4.6
  60. 3.9
  61. 3.5
  62. 4.2
  63. 4
  64. 4.7
  65. 3.6
  66. 4.4
  67. 4.5
  68. 4.1
  69. 4.5
  70. 3.9
  71. 4.8
  72. 4
  73. 4.9
  74. 4.7
  75. 4.3
  76. 4.4
  77. 4.8
  78. 5
  79. 4.5
  80. 3.5
  81. 3.8
  82. 3.7
  83. 3.9
  84. 5.1
  85. 4.5
  86. 4.5
  87. 4.7
  88. 4.4
  89. 4.1
  90. 4
  91. 4.4
  92. 4.6
  93. 4
  94. 3.3
  95. 4.2
  96. 4.2
  97. 4.2
  98. 4.3
  99. 3
  100. 4.1
  101. 6
  102. 5.1
  103. 5.9
  104. 5.6
  105. 5.8
  106. 6.6
  107. 4.5
  108. 6.3
  109. 5.8
  110. 6.1
  111. 5.1
  112. 5.3
  113. 5.5
  114. 5
  115. 5.1
  116. 5.3
  117. 5.5
  118. 6.7
  119. 6.9
  120. 5
  121. 5.7
  122. 4.9
  123. 6.7
  124. 4.9
  125. 5.7
  126. 6
  127. 4.8
  128. 4.9
  129. 5.6
  130. 5.8
  131. 6.1
  132. 6.4
  133. 5.6
  134. 5.1
  135. 5.6
  136. 6.1
  137. 5.6
  138. 5.5
  139. 4.8
  140. 5.4
  141. 5.6
  142. 5.1
  143. 5.1
  144. 5.9
  145. 5.7
  146. 5.2
  147. 5
  148. 5.2
  149. 5.4
  150. 5.1

リスト

データフレームでは、長さがそろった異なるデータ型を列で連結しているイメージですが、型だけでなく長さもばらばらのようなデータに対してはリストを使います

# 行列で表現できないようなデータもリストで表現できる
G <- list(X = c(1,2,3),
    Y = matrix(runif(9), nrow=3),
    Z = TRUE)
G$X # $で各要素にアクセスできる
  1. 1
  2. 2
  3. 3
G$Y
A matrix: 3 × 3 of type dbl
0.151336650.27817740.5372107
0.763819420.46726210.2771339
0.073073190.27498060.1801808
G$Z

TRUE

配列

3次元以上の配列はarrayという関数で扱うことができます

# 普段はあまり使わないが、3次元以上の行列(例: テンソル)を表現する時などに
H <- array(1:10, dim=c(1,2,3))
H[1,1,3]

5

その他

複雑なデータ構造はstr関数で見るとわかりやすいです

str(G)
str(iris)
List of 3
 $ X: num [1:3] 1 2 3
 $ Y: num [1:3, 1:3] 0.1513 0.7638 0.0731 0.2782 0.4673 ...
 $ Z: logi TRUE
'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 ...

Rの各種関数が返す値は、実は上記のようなこれ以上分解できない(Atomicな)データ型を組み合わせただけにすぎません

x <- runif(10)
y <- runif(10)
lr <- lm(y ~ x)
str(lr)
List of 12
 $ coefficients : Named num [1:2] 1.265 -0.971
  ..- attr(*, "names")= chr [1:2] "(Intercept)" "x"
 $ residuals    : Named num [1:10] 0.09016 0.05118 -0.36323 0.00554 0.12556 ...
  ..- attr(*, "names")= chr [1:10] "1" "2" "3" "4" ...
 $ effects      : Named num [1:10] -2.02479 0.58034 -0.37784 -0.00696 0.11571 ...
  ..- attr(*, "names")= chr [1:10] "(Intercept)" "x" "" "" ...
 $ rank         : int 2
 $ fitted.values: Named num [1:10] 0.475 0.591 0.741 0.784 0.837 ...
  ..- attr(*, "names")= chr [1:10] "1" "2" "3" "4" ...
 $ assign       : int [1:2] 0 1
 $ qr           :List of 5
  ..$ qr   : num [1:10, 1:2] -3.162 0.316 0.316 0.316 0.316 ...
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : chr [1:10] "1" "2" "3" "4" ...
  .. .. ..$ : chr [1:2] "(Intercept)" "x"
  .. ..- attr(*, "assign")= int [1:2] 0 1
  ..$ qraux: num [1:2] 1.32 1.02
  ..$ pivot: int [1:2] 1 2
  ..$ tol  : num 1e-07
  ..$ rank : int 2
  ..- attr(*, "class")= chr "qr"
 $ df.residual  : int 8
 $ xlevels      : Named list()
 $ call         : language lm(formula = y ~ x)
 $ terms        :Classes 'terms', 'formula'  language y ~ x
  .. ..- attr(*, "variables")= language list(y, x)
  .. ..- attr(*, "factors")= int [1:2, 1] 0 1
  .. .. ..- attr(*, "dimnames")=List of 2
  .. .. .. ..$ : chr [1:2] "y" "x"
  .. .. .. ..$ : chr "x"
  .. ..- attr(*, "term.labels")= chr "x"
  .. ..- attr(*, "order")= int 1
  .. ..- attr(*, "intercept")= int 1
  .. ..- attr(*, "response")= int 1
  .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
  .. ..- attr(*, "predvars")= language list(y, x)
  .. ..- attr(*, "dataClasses")= Named chr [1:2] "numeric" "numeric"
  .. .. ..- attr(*, "names")= chr [1:2] "y" "x"
 $ model        :'data.frame':	10 obs. of  2 variables:
  ..$ y: num [1:10] 0.565 0.642 0.378 0.789 0.962 ...
  ..$ x: num [1:10] 0.813 0.694 0.539 0.496 0.441 ...
  ..- attr(*, "terms")=Classes 'terms', 'formula'  language y ~ x
  .. .. ..- attr(*, "variables")= language list(y, x)
  .. .. ..- attr(*, "factors")= int [1:2, 1] 0 1
  .. .. .. ..- attr(*, "dimnames")=List of 2
  .. .. .. .. ..$ : chr [1:2] "y" "x"
  .. .. .. .. ..$ : chr "x"
  .. .. ..- attr(*, "term.labels")= chr "x"
  .. .. ..- attr(*, "order")= int 1
  .. .. ..- attr(*, "intercept")= int 1
  .. .. ..- attr(*, "response")= int 1
  .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
  .. .. ..- attr(*, "predvars")= language list(y, x)
  .. .. ..- attr(*, "dataClasses")= Named chr [1:2] "numeric" "numeric"
  .. .. .. ..- attr(*, "names")= chr [1:2] "y" "x"
 - attr(*, "class")= chr "lm"
lr$coefficients
(Intercept)
1.26530432769542
x
-0.971465044455202

基本文法


条件分岐

if-else構文で値によって、実行を切り替えることができます

SAKIGAKE <- "SAKIGAKE"
CREST <- "CREST"
if(SAKIGAKE == CREST){
    print("Same!!!")
}else{
    print("Different...")
}
[1] "Different..."

繰り返し

forやwhile構文で、設定した回数だけ繰り返し処理を行うことができます

I <- 1:20
for(i in 1:length(I)){
    print(I[i])
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20
j <- 1
while(j <= 20){
    print(I[j])
    j <- j + 1
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20

関数定義

何度も使う機能は関数として定義しておくと、再利用しやすくなります

jijou <- function(x){
    if(is.numeric(x)){
        x^2
    }else{
        stop("x is not numeric!!!")
    }
}
jijou(3)

9

try(jijou("3"))
Error in jijou("3") : x is not numeric!!!

apply

forやwhileよりも、より抽象的な書き方でapplyファミリー関数があります

apply(matrix(1:12, nrow=3), 1, mean)
  1. 5.5
  2. 6.5
  3. 7.5
apply(matrix(1:12, nrow=3), 2, var)
  1. 1
  2. 1
  3. 1
  4. 1
sapply(-3:3, abs)
  1. 3
  2. 2
  3. 1
  4. 0
  5. 1
  6. 2
  7. 3
lapply(list(A=1:3, B=matrix(1:12, nrow=3)), print)
[1] 1 2 3
     [,1] [,2] [,3] [,4]
[1,]    1    4    7   10
[2,]    2    5    8   11
[3,]    3    6    9   12
$A
  1. 1
  2. 2
  3. 3
$B
A matrix: 3 × 4 of type int
14710
25811
36912

applyに2つのパラメーターを指定したい

y <- "SAKIGAKE"
sapply(1:5, function(x, y){
    cat(paste0(y, x, "\n"))
}, y=y)
SAKIGAKE1
SAKIGAKE2
SAKIGAKE3
SAKIGAKE4
SAKIGAKE5
  1. NULL
  2. NULL
  3. NULL
  4. NULL
  5. NULL

ディレクトリ操作

(d <- getwd()) # ()内の実行と、結果の出力を同時に行う
setwd("../") # 一つ上のディレクトリに移動
getwd()

'/Users/tsuyusakikouki/Desktop/elwood/Dev/SakigakeMTG2019/exercise1'

'/Users/tsuyusakikouki/Desktop/elwood/Dev/SakigakeMTG2019'

setwd(d) # 元いたところに戻る
getwd()

'/Users/tsuyusakikouki/Desktop/elwood/Dev/SakigakeMTG2019/exercise1'

ファイル操作

# TSVのI/O
write.table(iris, "iris.txt")
iris.tsv <- read.table("iris.txt")
# CSVのI/O
write.csv(iris, "iris.csv")
iris.csv <- read.csv("iris.csv")
# バイナリデータのI/O
save(iris, file="iris.RData")
load("iris.RData")
# 全オブジェクトのI/O
save.image("20160806_SAKIGAKE.RData")
load("20160806_SAKIGAKE.RData")

システム関数

system("ls", intern=TRUE)  # UNIXコマンドをRから呼び出す
  1. '20160806_SAKIGAKE.RData'
  2. 'exercise1_Rintro.R'
  3. 'exercise1_Rintro.ipynb'
  4. 'iris.RData'
  5. 'iris.csv'
  6. 'iris.txt'
system("whoami", intern=TRUE)  # ユーザー名

'tsuyusakikouki'

system("pwd", intern=TRUE)  # getwd()と同じ

'/Users/tsuyusakikouki/Desktop/elwood/Dev/SakigakeMTG2019/exercise1'

system("Rscript --version", intern=TRUE)  # Rscriptのバージョン
system("rm -rf iris*", intern=TRUE)  # irisから始めるファイルは削除
sessionInfo()
R version 3.6.1 (2019-07-05)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS Catalina 10.15.1

Matrix products: default
BLAS:   /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRblas.0.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRlapack.dylib

locale:
[1] C/UTF-8/C/C/C/C

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.3      digest_0.6.23   zeallot_0.1.0   crayon_1.3.4   
 [5] IRdisplay_0.7.0 repr_1.0.1      backports_1.1.5 jsonlite_1.6   
 [9] evaluate_0.14   pillar_1.4.2    rlang_0.4.2     uuid_0.1-2     
[13] vctrs_0.2.0     IRkernel_1.0.2  tools_3.6.1     compiler_3.6.1 
[17] pkgconfig_2.0.3 base64enc_0.1-3 htmltools_0.4.0 pbdZMQ_0.3-3   
[21] tibble_2.1.3   

Colaboratory ノートブックの操作について詳しくは、Colaboratory の概要をご覧ください。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment