11 確認問題

11.1 概要

理解度を確認する問題です。

11.2 Rの文法に関する問題

11.2.1 問題

Rでc("apple", "banana", "cherry")というコードで作成されるデータ構造と変数の型は何か?

解答

データ構造はベクトル。変数の型は文字列型。

11.2.2 問題

Rのループ(forやwhile)内で、現在のループをスキップして次のループに進むために使用されるキーワードはどれか?

  • next
  • break
  • skip
  • continue
解答

正解は nextです。
break は、ループ自体を終了(中断)させるためのキーワードです。
skip や continue はRのループ制御キーワードではありません。

11.2.3 問題

以下のスクリプトを実行するとmean関数はNAを返す。
xの平均値を計算するにはどう対処すればいいか?

x = c(1, 2, 3, NA, 5)
mean(x)
## [1] NA
解答

mean(x, na.rm = TRUE)とすればよい。
na.rmはNAを無視するかどうかのオプション(デフォルトはFALSE)であり、これをTRUEにすると入力データに含まれるNAは無視して計算できる。mean関数だけでなく、標準偏差を計算するsd()関数など、他の多くの関数にも存在するオプションなので覚えておくとよい。

別の回答としては、mean(x[!is.na(x)])などもある。

11.2.4 問題

次のベクトル x に含まれる欠損値(NA)の数を数えるRコードを書け。

x = c(1, 5, NA, 8, NA, NA, 10)
解答
sum(is.na(x))

()内のis.na(x)は、ベクトル x の各要素が NA かどうかを判定し、TRUE(NA の場合)または FALSE(NA でない場合)の論理値ベクトルを返します。sum()関数は数値の合計値を計算する関数ですが、論理値に対しては FALSE を 0、TRUE を 1 として計算を行うので、TRUE の数を数えることができます。

11.2.5 問題

以下の内容を持つデータフレームを作成し、productsという名前の変数に代入せよ。

  • 1列目: 列名を name とし、“Apple”, “Banana”, “Cherry” という文字列を格納する。
  • 2列目: 列名を price とし、100, 80, 120 という数値を格納する。
  • 3列目: 列名を stock とし、TRUE, FALSE, TRUE という論理値を格納する。
解答
products = data.frame(
  name = c("Apple", "Banana", "Cherry"),
  price = c(100, 80, 120),
  stock = c(TRUE, FALSE, TRUE)
)

データフレームはdata.frame()関数を使って作成します。引数には列名 = ベクトルの形式で、各列のデータを指定します。各ベクトル(列)の長さはすべて同じである必要があります。この例では、文字型ベクトル、数値型ベクトル、論理型ベクトルを組み合わせて一つのデータフレームを作成しています。

11.2.6 問題

次のデータフレーム df がある。このデータフレームに、col1 と col2 の値を足し合わせた結果を col3 という新しい列として追加せよ。

df = data.frame(
  col1 = c(10, 20, 30),
  col2 = c(5, 10, 15)
)
解答
df$col3 <- df$col1 + df$col2

データフレームの特定の列にアクセスするには、データフレーム名$列名 という形式を使います。この形式は、列の値を抽出するだけでなく、新しい列を作成して値を代入するためにも使用できます。

このとき、df$col3という存在しない列に対して代入を行うと、Rは自動的に col3 という新しい列を作成し、右辺の計算結果(df$col1 + df$col2)を格納します。この操作はベクトル化されているため、各行について一度に計算が行われます。

11.2.7 問題

次のデータフレームdfからage列が30以上の行のみを抽出せよ。

df = data.frame(
  id = 1:4,
  age = c(19, 30, 25, 42)
)
解答
# 回答1
df[df$age >= 30, ]

# 回答2
subset(df, age >= 30)

# 回答3a
dplyr::filter(df, age >= 30)

# 回答3b
library(tidyverse)
df %>%
  dplyr::filter(age >= 30)

回答3bでパイプ演算子を使っている。この場合は事前にlibrary(tidyverse)などを実行してパイプ演算子を使えるようにしておく必要がある。

11.2.8 問題

1から12までの連続する整数を使って、3行4列の行列を作成せよ。ただし、要素は行方向に(左から右へ、そして上の行から下の行へ)格納されるようにする。作成した行列は mat_A という変数に格納する。

解答
mat_A = matrix(1:12, nrow = 3, ncol = 4, byrow = TRUE)

行列はmatrix()関数で作成します。第一引数に行列の要素となるベクトル、nrowで行数、ncolで列数を指定します。デフォルトでは、要素は列方向(上から下、左から右)に格納されますが、byrow = TRUEを指定することで、行方向に要素を格納できます。

11.2.9 問題

次のような機能を持つ関数を作成せよ。

  • 引数xが正の値なら"Positive"という文字列を返す。
  • 引数xが負の値なら"Negative"という文字列を返す。
  • 引数xが0なら"Zero"という文字列を返す。
解答
my_func = function(x) {
  if (x > 0) {
    return("Positive")
  } else if (x < 0) {
    return("Negative")
  } else {
    return("Zero")
  }
}

# 動作確認
my_func(10) # 正の値を引数にした場合
## [1] "Positive"
my_func(-2) # 負の値を引数にした場合
## [1] "Negative"
my_func(0) # 0を引数にした場合
## [1] "Zero"

まず、function()を使って新しい関数を定義し、my_func という名前を付けています。この関数は x という一つの引数を受け取ります。関数に渡された値は、{}の中で x という変数名で利用できます。次に、ifelseを使って条件分岐させています。return()を使って関数の返り値を定めます。

11.2.10 問題

以下の sales_data データフレームがある。dplyr パッケージとパイプ演算子 %>% を使って、category ごとの amount の合計値を計算せよ。

sales_data = data.frame(
  category = c("A", "B", "A", "C", "B", "A"),
  amount = c(100, 150, 200, 50, 250, 300)
)
解答
sales_summary = sales_data %>%
  dplyr::group_by(category) %>%
  dplyr::summarise(total_amount = sum(amount))

print(sales_summary)
## # A tibble: 3 × 2
##   category total_amount
##   <chr>           <dbl>
## 1 A                 600
## 2 B                 400
## 3 C                  50
  • group_by(category)で category 列の同じ値を持つ行をグループ化します。
  • summarise(total_amount = sum(amount))で、グループ化された各グループに対して集計処理を行います。ここでは sum(amount) で amount 列の合計を計算し、その結果を total_amount という新しい列に格納しています。

11.2.11 問題

データフレーム df1 と df2 を、共通のキー列 id を基準に結合(left join)せよ。

df1 = data.frame(
  id = c(1, 2, 3, 4),
  name = c("佐藤", "鈴木", "高橋", "田中")
)
df2 = data.frame(
  id = c(1, 3, 4),
  age = c(20, 22, 28)
)
解答
df = dplyr::left_join(df1, df2, by = "id")
print(df)
##   id name age
## 1  1 佐藤  20
## 2  2 鈴木  NA
## 3  3 高橋  22
## 4  4 田中  28

dplyrパッケージのleft_join()関数では、1つ目のデータフレーム(左側)を基準に、2つ目のデータフレーム(右側)を結合します。

11.2.12 問題

以下のデータフレームには、「Tシャツ」(Tは全角)と「Tシャツ」(Tは半角)という表記揺れが存在します。半角のTに表記を統一せよ。

df <- data.frame(
  id = c(101, 102, 103, 104, 105),
  name = c("Tシャツ", "スウェット", "Tシャツ", "パーカー", "Tシャツ"),
  price = c(2500, 4000, 2800, 5000, 2600),
  stringsAsFactors = FALSE  # 文字列をファクターにしないお約束
)
解答
# stringrパッケージの関数を使う場合
df$name = stringr::str_replace_all(df$name, "Tシャツ", "Tシャツ")

# Rの基本関数gsubを使う場合
df$name = gsub("Tシャツ", "Tシャツ", df$name)

11.2.13 問題

ifelse関数を使って、ある変数xの値が正ならyに1を代入し、xの値が負ならyに-1を代入せよ。

解答
x = 1
y = ifelse(x > 0, 1, -1)

# xがベクトルの場合も同様に処理できる
x = c(-10, 5, 0, 20, -8)
y = ifelse(x > 0, 1, -1)

この関数は以下の3つの引数を取ります。
ifelse(条件式, 条件が真の場合の値, 条件が偽の場合の値)

11.2.14 問題

1から20までの整数を順番にチェックする for ループを作成せよ。ループの中で、数値が15に達したらループを中断(break)し、「15が見つかったのでループを終了します。」と表示する。15に達するまでの数値は、ループの各反復で画面に出力する。

解答
for (i in 1:20) {
  if (i == 15) {
    print("15が見つかったのでループを終了します。")
    break
  }
  print(i)
}

上記のfor (i in 1:20)で変数 i に1から20までの数値が順番に代入され、ループが実行されます。ループ内のif (i == 15)という条件文で i が15かどうかをチェックします。条件が TRUE になると、メッセージを表示した後に break 文が実行されます。break は、それが含まれるループ(この場合は for ループ)を即座に中断する働きをします。そのため、i が15になった時点でループが終了し、16以降の数値は処理されません。

11.3 グラフ作成に関する問題

wip

11.4 統計処理に関する問題

wip