Rの制御構造:if/for/while—条件文とループ
前回のレッスンでは演算子について学び、Rプログラムで「何かが真か偽かを判断する」ことができるようになりました。しかし、単に真偽を判定できるだけでは不十分です。プログラムには、タスクを繰り返し実行する(ループ)ことや、分岐処理を行う(条件分岐)ことも求められます。このレッスンでは、Rにおける「制御フロー」について学びます。具体的には、if/else条件分岐、for/whileループ、およびrepeat文について解説します。
Rにおける制御フローはPythonとは少し異なります。Rでは、コードブロックを{}で囲みます(インデントは使用しません)。また、if/else文全体が単一の式となります。このレッスンでは、これらの違いについて学びます。
1. 学習内容
- if / else / else if による条件分岐
- forループを使用して、ベクトルやリストを反復処理する
- whileループ
- repeat:無限ループ(終了するには break を使用してください)
- ifelse() による条件式のベクトル化評価
- next:このラウンドをスキップする;break:ループを終了する
- RとPythonにおける制御フローの主な違い
2. データフィルタリングに関する話
(1) 課題:手作業による分類
シャオ・ジャオはデータアナリストです。上司から、100人の顧客を年齢別に分類するよう依頼されました。
- 18歳未満:未成年者
- 18~30歳:若年成人
- 31~50歳:中年
- 51歳以上:高齢者
Excelを使う場合、4つのネストしたIF関数を書く必要があります。Pythonを使う場合は、ループやif-else文を書く必要があります。しかし、Rにはベクトル専用に設計されたifelse()があり――
(2) Rを用いた解決策
# 5 The age of each customer
ages <- c(15, 22, 35, 50, 65)
# Done in one line of code 4 File Categories(Vectorization ifelse)
labels <- ifelse(ages < 18, "Minor",
ifelse(ages < 31, "Youth",
ifelse(ages < 51, "Middle Age", "Old Age")))
cat("Customer Segmentation:\n")
print(data.frame(Age = ages, Category = labels))
たった3行のコードで4クラス分類問題を解く。これがRの制御フローが持つ「ベクトル化」の利点であり、要するに、1つの文が1つの決定ベクトルとなるのです。
3. if/else:条件分岐
(1) if ステートメントの基本構文
# R uses { } to enclose a code block (Python uses indentation)
if (Conditions) {
Execute when the condition is true
}
age <- 18
if (age >= 18) {
cat("You're an adult now.\n")
}
# Output:You're an adult now.
(2) if-else:二者択一
if (Conditions) {
Execute when the condition is true
} else {
Execute when the condition is false
}
score <- 45
if (score >= 60) {
cat("Passed!\n")
} else {
cat("Fail,Need to take a makeup exam\n")
}
# Output:Fail,Need to take a makeup exam
(3) if-else if-else:多岐分岐
if (Conditions1) {
Branch1
} else if (Conditions2) {
Branch2
} else {
Other
}
score <- 85
if (score >= 90) {
cat("Excellent\n")
} else if (score >= 80) {
cat("Good\n")
} else if (score >= 60) {
cat("Passing Grade\n")
} else {
cat("Fail\n")
}
# Output:Good
(4) RとPythonの主な違い
| 特集 | R | Python |
|---|---|---|
| コードブロック | {} 中括弧 |
インデント(4スペース) |
| if 構文 | if (x > 0) { ... } |
if x > 0: |
| 全体としての表現 | if/else が 式 である場合(代入可能) | if/else が 文 である場合(代入不可) |
| 三項演算 | ifelse() 特殊関数 |
x if x > 0 else -x |
# R Special Usage of:ifelse It is an expression
result <- if (score >= 60) "Passing Grade" else "Fail"
result
# [1] "Passing Grade"
elseを含める必要があります。2行に分けて記述すると、Rは構文エラーを報告します。
4. ifelse(): ベクトル化された意思決定
(1) なぜ ifelse() が必要なのでしょうか?
標準の if は 単一の値 しか評価できませんが、R では ベクトル全体 を評価する必要がある場合がよくあります。その場合は、ifelse() を使用してください:
graph LR
A["x = 1, 2, 3, 4, 5"] --> B["ifelse x > 3 yes no"]
B --> C["no no no yes yes"]
style A fill:#cce5ff
style C fill:#d4edda
# Regular if It will throw an error(Only accept lengths 1)
x <- c(1, 2, 3, 4, 5)
if (x > 3) "L" else "S" # Error: condition has length > 1
# Use ifelse() to resolve
ifelse(x > 3, "L", "S")
# [1] "S" "S" "S" "L" "L"
(2) ifelse() の構文
ifelse(Conditions, The value when the condition is true, Value when the condition is false)
(3) ネストされたifelse():多段階分類
ages <- c(15, 22, 35, 50, 65)
# 4 File Categories
labels <- ifelse(ages < 18, "Minor",
ifelse(ages < 31, "Youth",
ifelse(ages < 51, "Middle Age", "Old Age")))
print(data.frame(Age = ages, Category = labels))
出力:
Age Category
1 15 Minor
2 22 Youth
3 35 Middle Age
4 50 Middle Age
5 65 Old Age
ifelse() ネストが3階層以上ある場合は、よりわかりやすくするために dplyr::case_when()(第10課で解説)の使用をお勧めします。
5. forループ:要素を順に処理する
(1) 「for」ループの基本構文
for (Variable in Vector) {
Code executed in each iteration
}
(2) ベクトルを反復処理する
# Iteration 1:5
for (i in 1:5) {
cat("Iteration", i, "of the loop\n")
}
# Output:
# Iteration 1 of the loop
# Iteration 2 of the loop
# Iteration 3 of the loop
# Iteration 4 of the loop
# Iteration 5 of the loop
# Iterating Through a Character Vector
fruits <- c("Apple", "Banana", "Cherries")
for (fruit in fruits) {
cat("I like to eat", fruit, "\n")
}
(3) 累積和(典型的な例)
# 1+2+3+...+100
total <- 0
for (i in 1:100) {
total <- total + i
}
total
# [1] 5050
(4) ⚠️ Rはループ処理のパフォーマンスが低い
Rのforループは、Pythonのループに比べて10~100倍も遅い。Rでは、ループの代わりにベクトル化された演算の使用が推奨されている:
# Slow (Loop)
system.time({
total <- 0
for (i in 1:1e6) {
total <- total + i
}
})
# User System Passing
# 0.40 0.00 0.40 ← 0.4 s
# Fast (Vectorization)
system.time({
total <- sum(1:1e6)
})
# User System Passing
# 0.01 0.00 0.01 <- 0.01 s (40x faster)
sum() mean() ifelse()を使って問題を解決できるなら、ループを書かないでください。
6. whileループ:条件付きループ
(1) while構文
while (Conditions) {
Execute repeatedly when the condition is true
}
(2) 典型的な例:「数字当てゲーム」
# Target Number
target <- 42
guess <- 0
attempts <- 0
while (guess != target) {
guess <- sample(1:100, 1) # Guess at Random
attempts <- attempts + 1
if (attempts > 1000) break # More than 1000 Second attempt
}
cat("Used", attempts, "Second guess\n")
(3) for との相違点
| 機能 | 対象 | 期間 |
|---|---|---|
| 目的 | 反復回数が既知のループ | 反復回数が不明で、条件によってトリガーされるループ |
| 終了 | ベクトル走査の終了 | 条件不成立による終了 |
| 適用対象 | データの反復処理 | イベントの待機、ポーリング |
7. repeatとbreak:無限ループ
(1) repeat 構文
repeat {
Code
if (Conditions) break # Must have break,Otherwise, an infinite loop
}
(2) 実践編:メニューの選択
choice <- 0
repeat {
cat("\n=== Main Menu ===\n")
cat("1. Check the weather\n")
cat("2. Look up stocks\n")
cat("0. Exit\n")
choice <- as.integer(readline("Please select:"))
if (choice == 0) {
cat("Goodbye!\n")
break
} else if (choice == 1) {
cat("It's sunny today,25°C\n")
} else if (choice == 2) {
cat("Shanghai Stock Exchange 3000 pt\n")
} else {
cat("Invalid input\n")
}
}
repeat は break と組み合わせて使用する必要があります。そうしないと、無限ループが発生し(プログラムがフリーズします)、動作しなくなります。
8. next と break:ループ制御
| キーワード | 機能 | シナリオ |
|---|---|---|
next |
このラウンドをスキップして次のラウンドに進む | 特定の項目をスキップする |
break |
ループ全体を終了 | 対象が見つかり次第、直ちに終了 |
# next:Skip even numbers
for (i in 1:10) {
if (i %% 2 == 0) next
cat(i, " ")
}
# Output:1 3 5 7 9
cat("\n")
# break:Find the first one 7 Just log out
for (i in 1:10) {
if (i == 7) break
cat(i, " ")
}
# Output:1 2 3 4 5 6
9. よくある落とし穴
(1) 浮動小数点数の比較における落とし穴
# Seemingly equal,The actual values are not equal
0.1 + 0.2 == 0.3
# [1] FALSE ← Actually, it is 0.30000000000000004
# The Correct Way to Do It:Comparison of Tolerances
abs(0.1 + 0.2 - 0.3) < 1e-9
# [1] TRUE
(2) else ステートメントは、新しい行、または同じ行に記述する必要があります
# ❌ Error:else Traveling Alone
if (TRUE) {
cat("yes")
}
else {
cat("no")
}
# Error: unexpected 'else' in "else"
# Correct: else must follow if block }
if (TRUE) {
cat("yes")
} else {
cat("no")
}
# Output:yes
} else { を同じ行に記述してください。
(3) 自動的に出力されない場合
# In R, if has no "Automatic Printing" (Not like a function call)
if (TRUE) "yes"
# No output ← Do not print
# Resolve: Use cat() or print() for explicit output
if (TRUE) cat("yes\n")
# Output:yes
10. 完全な例:顧客階層の管理
以下は、このレッスンで学んだすべての制御フローを結びつけた完全なワークフローの例です。
▶ サンプル:顧客セグメンテーションとマーケティング戦略
# ============================================
# Customer Segmentation and Marketing Strategies
# Features:By age+Classify Customers by Spending Amount
# ============================================
# 1. Preparation 6 Customer Data
customers <- data.frame(
name = c("Alice", "Bob", "Charlie", "Diana", "Eve", "Frank"),
age = c(15, 22, 35, 50, 65, 28),
spend = c(100, 500, 2000, 5000, 10000, 800)
)
# 2. Use ifelse() Batch Grading (Vectorization)
customers$tier <- ifelse(customers$spend < 500, "Regular",
ifelse(customers$spend < 3000, "Silver Card",
ifelse(customers$spend < 8000, "Gold Card", "Diamond")))
# 3. Go through the customer list,Output Marketing Strategy(for Loop)
cat("=== Customer Segmentation and Marketing Strategies ===\n\n")
for (i in 1:nrow(customers)) {
name <- customers$name[i]
age <- customers$age[i]
spend <- customers$spend[i]
tier <- customers$tier[i]
# Skip Diamond Members(Optimized)
if (tier == "Diamond") {
cat(name, "(", tier, "):", spend, "USD,Existing Customers,Priority Maintenance\n")
next
}
# Exit Conditions(Demo break)
if (spend > 5000) {
cat(name, ": High-spending customers! Enter VIP Process\n")
}
# Age-Based Marketing Recommendations
if (age < 18) {
cat(name, "(", tier, "):Minor,Recommended Parent Card\n")
} else if (age < 30) {
cat(name, "(", tier, "):Youth,New Product Releases\n")
} else if (age < 50) {
cat(name, "(", tier, "):Middle Age,Promote Family Plans\n")
} else {
cat(name, "(", tier, "):Middle-Aged and Older Adults,Promote Health Products\n")
}
}
期待される出力(抜粋):
=== Customer Segmentation and Marketing Strategies ===
Alice( Regular ):Minor,Recommended Parent Card
Bob( Regular ):Youth,New Product Releases
Charlie( Silver Card ):Middle Age,Promote Family Plans
Diana( Gold Card ):Middle Age,Promote Family Plans
Eve( Diamond ):10000 USD,Existing Customers,Priority Maintenance
Frank( Silver Card ):Youth,New Product Releases
❓ よくある質問
sum() mean() ifelse()を使って問題を解決できるなら、forループは書かないでください。RのループはPythonに比べて10~100倍遅いため、10万要素以上を扱う場合は慎重に使用してください。forの代わりにwhileを使うべきなのはどのような場合ですか?whileを、反復回数が既知の場合(例:ベクトルに対する反復処理など)にはforを使用します。「早期終了可能な無限ループ」の場合は、repeat + break を使用してください。📖 まとめ
- if/else/else if による条件分岐:Rでは、コードブロックを
{}で囲みます(インデントは入れないでください)。 ifelse()は、ベクトル全体を評価できる ベクトル化された条件文 です。一方、通常のif文では、単一の値しか評価できません。forループは既知の回数だけ反復し、whileループは回数が不明なループであり、repeatループは無限ループであるため、breakステートメントと組み合わせて使用する必要があります。- next:このラウンドをスキップする;break:ループ全体から抜け出す
- Rではベクトル化を優先することが推奨されています。forループはPythonに比べて10~100倍も処理が遅いため、ビッグデータの場合は代わりに
sum()やifelse()を使用してください。 - 浮動小数点数の比較には許容誤差(
abs(x - y) < 1e-9)を使用してください。==を直接使用しないでください。 elseは、}と組み合わせて使用する必要があります(解析時の曖昧さを避けるため)。
📝 練習問題
-
基本問題:
if/else if/elseを使用して、以下の機能を実装する R スクリプトを作成してください。スコアscoreが与えられた場合、評価(90以上:優秀、80以上:良好、60以上:合格、それ以外:不合格)を出力します。95、75、60、40の4つの得点でスクリプトをテストし、出力のスクリーンショットを保存してください。 -
基本問題:
ifelse()を使用して、ベクトルc(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)を奇数番目の要素と偶数番目の要素に分割し、その結果を出力してください。 -
基本問題:
forを使用して、ループ内で 5!(5 の階乗 = 5 × 4 × 3 × 2 × 1)を計算し、その過程と結果のスクリーンショットを保存してください。 -
応用演習:「数字当てゲーム」を作成してください:①
sample(1:100, 1)を使用して、1 から 100 までの間の乱数を目標値として生成します。②whileを使用して、ユーザーからの入力 (readline) を繰り返し処理します。③ 「高すぎます」または「低すぎます」というヒントを表示する;④ 数字が正しく当てられたら、「おめでとうございます!N回の試行で正解しました。」と出力する。プログラムを実行してテストしてください。 -
課題:1 から 100 までの整数を次のように処理するスクリプトを作成してください。① 3 の倍数(
next)をスキップします。② 50に達したら終了する (break); ③ 残りの数の和を計算する。結果を確認する(1+2+4+5+7+8+...+49 = ? となるはず)。コードと出力のスクリーンショットを保存してください。



