Mukku John Blog

取り組んでいること を つらつら と

Rプログラミング入門 10回目

この記事で、保存したcards.csvファイルをdeckオブジェクトに読み込んで
deckオブジェクトを操作する方法を学んでいきます。
mukkujohn.hatenablog.com

下準備

cards.csvファイルをロードしておきます

> deck <- read.csv("cards.csv")
> head(deck)
   face   suit value
1  king spades    13
2 queen spades    12
3  jack spades    11
4   ten spades    10
5  nine spades     9
6 eight spades     8

data.frameオブジェクトの要素の指定方法

data.frameから、要素を取得するには、deck[ , ]の様に記載します。
deckオブジェクトの1行、1列目の要素を取得しています。

> deck[1,1]
[1] "king"

[]の添え字には、下記の6種類があります。

  1. 正の整数
  2. 負の整数
  3. ゼロ
  4. スペース
  5. 論理値
  6. 名前

1.正の整数

これはC#でいうところの配列の指定と同じですね。
ただ、Rはベクトルで指定できるところが違うため、その挙動も独特な印象です。

1行目、1列目を指しています。

> deck[1,1]
[1] "king"

3行目、1列目から3列目を指しています。

> deck[3,c(1,2,3)]
  face   suit value
3 jack spades    11

同じ次元(この例では行)に対して、同じ添え字(この例では"1")を指定すると
指定された次元を、指定された添え字分繰り返します。

> deck[c(1,1,1),c(1,2,3)]
    face   suit value
1   king spades    13
1.1 king spades    13
1.2 king spades    13

2.負の整数

添え字に負の整数が指定できるなんて…。
負の整数を指定すると、その負の整数が指していない要素が返されます。

1行目以外全部を指しています。

> deck[-1,1:3]
    face     suit value
2  queen   spades    12
3   jack   spades    11
4    ten   spades    10
5   nine   spades     950 three   hearts     3
51   two   hearts     2
52   ace   hearts     1

逆に2行目から52行目以外全部 => 1行目のみ

> deck[-(2:52),1:3]
  face   suit value
1 king spades    13

同じ次元に対して、正負混在の整数を指定するとエラーです。

> deck[c(-1,1),1]
Error in xj[i] : only 0's may be mixed with negative subscripts

3.ZERO

添え字に0が利用できます。
Rでは、インデックスが1始まりなので、0が指定された際に特別な挙動をします。

C#は、インデックスは0始まりなのですが、Rを利用して統計している人には
リストのインデックスが0始まりなのは、気持ち悪いんでしょうね。

0を指定すると、指定された次元は何も返却しません。

> deck[0,0]
 00 行のデータフレーム 
> deck[1,0]
 01 行のデータフレーム 
> deck[0,1:3]
[1] face  suit  value
 <0> (または長さ 0 の row.names) 

どんな時に有効活用されるのか、今は分からないのですが、
いずれ指定する日が来るのでしょう。

4.スペース

スペースを指定すると、その次元の要素が全て返却されます。
つまるところ、記載する事を省略できますね。

列の指定を省略しています。2行目と全ての列の要素が返されます。

> deck[2, ]
   face   suit value
2 queen spades    12

行の指定を省略しています。全ての行と1列目の要素が返されます。

> deck[ , 1]
 [1] "king"  "queen" "jack"  "ten"   "nine"  "eight" "seven" "six"   "five"  "four" 
[11] "three" "two"   "ace"   "king"  "queen" "jack"  "ten"   "nine"  "eight" "seven"
[21] "six"   "five"  "four"  "three" "two"   "ace"   "king"  "queen" "jack"  "ten"  
[31] "nine"  "eight" "seven" "six"   "five"  "four"  "three" "two"   "ace"   "king" 
[41] "queen" "jack"  "ten"   "nine"  "eight" "seven" "six"   "five"  "four"  "three"
[51] "two"   "ace"  

5.論理値

TRUEが指定された行、または、列が返されます。

1行目から2行目で、1列目と3列目の要素が返されます。

> deck[1:2, c(TRUE,FALSE,TRUE)]
   face value
1  king    13
2 queen    12

当然、省略記法も使えます。
1行目で、2列目の要素が返されます。

> deck[1,c(F,T,F)]
[1] "spades"

6.名前

オブジェクトが名前属性を持っている場合は、名前で抽出する事もできます。

1行目の、face列、suit列、value列が返されます。

> deck[1,c("face","suit","value")]
  face   suit value
1 king spades    13

全ての行の、value列が返されます。

> deck[ ,c("value")]
 [1] 13 12 11 10  9  8  7  6  5  4  3  2  1 13 12 11 10  9  8  7  6  5  4  3  2  1
[27] 13 12 11 10  9  8  7  6  5  4  3  2  1 13 12 11 10  9  8  7  6  5  4  3  2  1

deckオブジェクトから、ランダムに、1個オブジェクトを取得する方法

deckオブジェクトには、52枚のカードの情報が割り当てられています。

> head(deck)
   face   suit value
1  king spades    13
2 queen spades    12
3  jack spades    11
4   ten spades    10
5  nine spades     9
6 eight spades     8
> tail(deck)
    face   suit value
47   six hearts     6
48  five hearts     5
49  four hearts     4
50 three hearts     3
51   two hearts     2
52   ace hearts     1

この52行ある要素の中から、1行ランダムに取得するには?
今まで行ってきた事から、sample()関数を利用すればできそうです。

52行をランダムに並び替えるshuffle関数です。

shuffle <- function(cards){
  random <- sample(1:52, size = 52)
  cards[random, ]
}

1行目の要素を返すdeal関数です。

deal <- function(cards){
  cards[1, ]
}

このshuffle関数とdeal関数を利用すると、
ランダムに並び替えられた52行あるdata.frame要素から
最初の1行の要素を返すことができます。

> deck2 <- shuffle(deck)
> deal(deck2)
  face   suit value
9 five spades     5
> deck2 <- shuffle(deck)
> deal(deck2)
    face   suit value
41 queen hearts    12

$記法と[[]]記法

$記法について

data.frameとlistのオブジェクトは、$を使う事で要素を取得できます。
コマンドは、data.frame$列名です。

deckオブジェクトのvalue列の取得

> deck$value
 [1] 13 12 11 10  9  8  7  6  5  4  3  2  1 13 12 11 10  9  8  7  6  5  4  3  2  1
[27] 13 12 11 10  9  8  7  6  5  4  3  2  1 13 12 11 10  9  8  7  6  5  4  3  2  1

deckオブジェクトのface列の取得

> deck$face
 [1] "king"  "queen" "jack"  "ten"   "nine"  "eight" "seven" "six"   "five"  "four" 
[11] "three" "two"   "ace"   "king"  "queen" "jack"  "ten"   "nine"  "eight" "seven"
[21] "six"   "five"  "four"  "three" "two"   "ace"   "king"  "queen" "jack"  "ten"  
[31] "nine"  "eight" "seven" "six"   "five"  "four"  "three" "two"   "ace"   "king" 
[41] "queen" "jack"  "ten"   "nine"  "eight" "seven" "six"   "five"  "four"  "three"
[51] "two"   "ace"

listオブジェクトにも試してみます。

> lst <- list(numbers = c(1,2), logical = TRUE, strings = c("a","b","c"))
> lst
$numbers
[1] 1 2

$logical
[1] TRUE

$strings
[1] "a" "b" "c"

> lst$numbers
[1] 1 2

ここで、ひとつ注意点があります。
lst[1]とlst$numbersでは、返されるオブジェクトのclassが異なります。

> class(lst[1])
[1] "list"
> class(lst$numbers)
[1] "numeric"

lst[1]はlistクラス、lst$numbersはnumericクラスです。
なので、こんな記載をするとエラーになります。

> sum(lst[1])
Error in sum(lst[1]) : invalid 'type' (list) of argument
> sum(lst$numbers)
[1] 3

そのため、要素の指定は、添え字なのか名前なのか意識して使い分けが必要です。

[[]]記法について

名前が分からない場合は[[]]が利用できます。

> lst[[1]]
[1] 1 2

lstオブジェクトの1番目のオブジェクトに含まれる要素を取得しています。
(lst[1]と記載すると、lstオブジェクトの1番目のオブジェクトを取得します。)

これは、名前を指定して返却された要素と同じclassです。

> class(lst[[1]])
[1] "numeric"
> class(lst$numbers)
[1] "numeric"

[]内は文字列を利用する事もできます。

> lst[["numbers"]]
[1] 1 2

ややこしいのが、lst[""]とlst[[""]]が異なる点ですね。

> lst["numbers"]
$numbers
[1] 1 2

> lst[["numbers"]]
[1] 1 2

なんとなしに想像はつきますが、一応classを確認してみます。

> class(lst["numbers"])
[1] "list"
> class(lst[["numbers"]])
[1] "numeric"

添え字や名前を指定するlistクラスのオブジェクトが返されて
$記法や、[[]]記法で指定するlistクラスの中の要素オブジェクトが返される事に
注意が必要ですね。


今日はここまで。