Rリスト:Rの「ユニバーサルコンテナ」
これまでの3回のレッスンでは、ベクトルと行列について学びましたが、これらはいずれもすべての要素が同じ型であることが求められます。しかし、実際には、データは異種混在していることがよくあります。例えば、学生情報には、学生ID(数値)、氏名(文字列)、成績(ベクトル)などが含まれます。Rでは、リストを用いて、このような異種混在データの格納という問題を解決します。
リストはRの真の「スイスアーミーナイフ」です。リストにはあらゆる型(ベクトル、行列、データフレーム、関数、さらには他のリストさえも)を格納できます。データフレーム data.frame は、本質的に「等長のベクトルのリスト」です。このレッスンはフェーズ1において極めて重要です。
1. 学習内容
- list() は、任意の型のコンテナを作成します
- 名前一覧(名前で検索)
- 4つのアクセスモード (
[[ ]][ ]$[[ "name" ]]) - リスト内の項目の変更、追加、削除
- リストのバッチ処理に lapply() を使用する
- 入れ子になったリスト
- list2env() は、リストを環境変数に変換します
2. 学生情報管理に関する話
(1) 課題:異種データの保存
イワンは人事部門で働いており、ある社員に関する完全な情報を保存する必要があります:
Employee ID:2024001(Numbers)
Name:Alice(Character)
Department:Data Analysis Department(Character)
Salary:15000(Numbers)
Skills:c("R", "Python", "SQL")(Character vector)
ベクトルを使用する場合、すべての要素は同じ型でなければなりません――うまくいきません。データフレームを使用する場合、各列の列数が同じでなければなりません――これもうまくいきません。
(2) リストを用いた解法
# One list Fits all types
employee <- list(
id = 2024001,
name = "Alice",
department = "Data Analysis Department",
salary = 15000,
skills = c("R", "Python", "SQL"),
is_active = TRUE
)
# Access any field
employee$name # [1] "Alice"
employee$skills[1] # [1] "R"
employee$salary * 12 # [1] 180000 (Annual Salary)
異なる型の6つのフィールドを含む単一のリスト。これこそがRのリストの真骨頂です。
3. list(): リストを作成する
(1) 基本的な構文
list(key1 = value1, key2 = value2, ...)
(2) 創作のための5つの方法
# 1. List of Names(Most Commonly Used)
person <- list(name = "Alice", age = 25, scores = c(85, 90, 92))
person
# $name
# [1] "Alice"
#
# $age
# [1] 25
#
# $scores
# [1] 85 90 92
# 2. Anonymous List(Browse by Location)
unnamed <- list("a", 1, TRUE)
# [[1]] "a"
# [[2]] 1
# [[3]] TRUE
# 3. Nested Lists
company <- list(
hr = list(name = "HR", count = 5),
it = list(name = "IT", count = 20)
)
# 4. Empty list
empty <- list()
length(empty) # [1] 0
# 5. Use list() to convert vector (Maintain Heterogeneity)
as.list(c(1, 2, 3))
# [[1]] 1
# [[2]] 2
# [[3]] 3
(3) リストとベクトルの比較
graph TB
A[R Data Structures] --> B[Vector<br/>Homogeneous<br/>One-dimensional]
A --> C[Matrix<br/>Homogeneous<br/>Two-dimensional]
A --> D[List<br/>Heterogeneous<br/>Any type]
A --> E[Data Frame<br/>List of vectors of equal length<br/>Two-dimensional]
style A fill:#fff3cd
style B fill:#cce5ff
style C fill:#d4edda
style D fill:#f8d7da
style E fill:#e1d4ff
| 物件 | ベクター c(1, 2, 3) |
リスト list(1, "a", TRUE) |
|---|---|---|
| 要素の種類 | 同一でなければならない | 異なる場合もある |
| 要素の種類 | 6つの基本タイプ | 任意のRオブジェクト(関数やデータフレームを含む) |
| アクセス | v[1] |
l[[1]] |
| 可変長 | ❌ | ✅(必要に応じて追加・削除可能) |
| Pythonに似ている | tuple |
dict / list |
4. 4 アクセス方法(要点)
(1) ルックアップテーブルの4つの種類
| メソッド | 構文 | 戻り値 | 目的 |
|---|---|---|---|
[[i]] |
i番目の要素 | 要素そのもの | 単一の要素を取得する |
[i] |
i番目の要素 | 部分リスト | 部分集合を取り出す |
$name |
名前で | 要素自体 | 指定された要素を取得 |
[["name"]] |
名称 | 要素自体 | 同等 $name |
(2) [[ ]] 対 [ ]:主な違い
person <- list(name = "Alice", age = 25, scores = c(85, 90, 92))
# [[ ]] Return the element itself
person[[1]]
# [1] "Alice" ← Character
# [ ] Return to Sublist
person[1]
# $name
# [1] "Alice" ← Or a list
# Key Differences: Using [ ] after extraction, attempting to access sub-elements may cause an error
person[1]$name # ✅ $name Still accessible(Syntax sugar)
person[1][1] # ❌ This is the 1 element,But there is only one child list $name
# Practical Application:Calculate the average score
mean(person[[3]]) # [1] 89 ← [[3]] Extract the vector
mean(person$scores) # [1] 89 ← $scores Extract the vector
mean(person[3]) # Error: need numeric data
[[ ]] または $ を、部分集合にアクセスするには [ ] を使用してください。これは、R でリストにアクセスする際に最も分かりにくい点です。
(3) $ 対 [["name"]]
# $ is syntactic sugar for [[ "name" ]]
person$name # Equivalent person[["name"]]
person[["name"]] # Equivalent person$name
# $ Supports partial matches(Not recommended)
person$na # Automatically matched to "name"
# [1] "Alice"
# [[ ]] Partial matches are not supported(Safer)
person[["na"]] # Error
[[ "name" ]] を使用してください—明確で曖昧さがなく、部分一致に依存しません。
(4) ネストされたリストへのアクセス
company <- list(
hr = list(name = "HR", count = 5, head = "Alice"),
it = list(name = "IT", count = 20, head = "Bob")
)
# Accessing Nested Elements
company$hr$head # [1] "Alice"
company[["it"]][["head"]] # [1] "Bob"
company$it$count # [1] 20
5. リスト内の項目の変更、追加、削除
(1) 要素を変更する
person <- list(name = "Alice", age = 25)
# Edit ([[ ]] or $ both can be changed)
person$age <- 26
person[["age"]]
# [1] 26
# Batch Edit
person$age <- person$age + 1
person$age # [1] 27
(2) 要素を追加する
# Methods 1: Use $ to add
person$email <- "alice@example.com"
# Methods 2: Use [[ ]] to add
person[["phone"]] <- "13800000000"
# Methods 3: Use c() to merge
person <- c(person, address = "Haidian District, Beijing")
(3) 要素の削除
# Assign NULL to delete
person$phone <- NULL
# Or
person[["address"]] <- NULL
(4) リストの構造を確認する
# View Structure(Important Debugging Functions)
str(person)
# List of 4
# $ name : chr "Alice"
# $ age : num 27
# $ email : chr "alice@example.com"
# $ address : chr "Haidian District, Beijing"
# View All Names
names(person)
# [1] "name" "age" "email" "address"
6. lapply(): リストのバッチ処理
(1) なぜ lapply を使うのか?
リスト内の要素の型は異なる場合があるため、単に sum() mean() のように記述することはできません。lapply 関数を使用すると、各要素に関数を適用することができます:
mixed_list <- list(
numbers = 1:5,
chars = c("a", "b", "c"),
logical = c(TRUE, FALSE, TRUE)
)
# Calculate the length of each element
lapply(mixed_list, length)
# $numbers
# [1] 5
#
# $chars
# [1] 3
#
# $logical
# [1] 3
(2) lapply + カスタム関数
# CalculateFor each element,"Abstract"
summary_list <- lapply(mixed_list, function(x) {
if (is.numeric(x)) {
return(list(mean = mean(x), sum = sum(x)))
} else {
return(list(length = length(x), class = class(x)))
}
})
summary_list$numbers
# $mean
# [1] 3
#
# $sum
# [1] 15
(3) sapply() を用いた結果の簡略化
# lapply Back to List,sapply Simplify to a vector
sapply(mixed_list, length)
# numbers chars logical
# 5 3 3
7. リストの結合:c() と unlist()
(1) c() リストの結合
# Merge Multiple Lists
list1 <- list(a = 1, b = 2)
list2 <- list(c = 3, d = 4)
merged <- c(list1, list2)
merged
# $a 1
# $b 2
# $c 3
# $d 4
(2) unlist() はベクトルに展開される
# Flatten the list into a vector(Only for"Atom"Element Valid)
numbers_list <- list(a = 1, b = 2, c = 3)
unlist(numbers_list)
# a b c
# 1 2 3
# Note:The type will be coerced after flattening.
mixed <- list(1, "a", TRUE)
unlist(mixed)
# [1] "1" "a" "TRUE" ← Convert All to Strings
8. list2env(): リストを環境に変換する
リスト内の各要素をグローバル変数に変換します:
config <- list(
host = "localhost",
port = 3306,
user = "root",
password = "secret"
)
# Convert list elements to environment variables
list2env(config, envir = .GlobalEnv)
# You can use it right away
host # [1] "localhost"
port # [1] 3306
list2env() はグローバル環境を汚染する可能性があるため、使用には注意が必要です。これは主に、YAML や JSON から設定を読み込む場面で使用されます。
9. 一般的な操作の比較
(1) c() 対 list() 対 unlist()
| 関数 | 目的 | 入力 → 出力 |
|---|---|---|
c() |
原子要素の組み合わせ | c(1, 2, 3) → ベクトル |
list() |
異種コンテナの作成 | list(1, "a") → リスト |
unlist() |
リストをベクトルに変換する | unlist(list(1,2,3)) → ベクトル |
(2) リストをDataFrameに変換する
# A list of vectors of equal length can be converted data.frame
df <- as.data.frame(list(
name = c("A", "B", "C"),
age = c(20, 25, 30),
score = c(85, 90, 78)
))
print(df)
# name age score
# 1 A 20 85
# 2 B 25 90
# 3 C 30 78
10. 完全な例:従業員記録の管理
以下は、このレッスンで取り上げたすべてのリスト機能を結びつける完全なワークフローの例です。
▶ サンプル:従業員ファイルの管理
# ============================================
# Employee File Management
# Features:Manage with Lists 3 Complete information about each employee
# ============================================
# 1. Create 3 List of employees
employees <- list(
alice = list(
id = 2024001,
name = "Alice",
department = "Data Analysis Department",
salary = 15000,
skills = c("R", "Python", "SQL"),
projects = c("User Profiles", "Sales Forecast")
),
bob = list(
id = 2024002,
name = "Bob",
department = "Engineering Department",
salary = 18000,
skills = c("Java", "Go", "Docker"),
projects = c("API Refactoring", "Microservice Migration")
),
charlie = list(
id = 2024003,
name = "Charlie",
department = "Product Department",
salary = 20000,
skills = c("Figma", "Axure"),
projects = c("V2.0 Design", "User Research")
)
)
# 2. View a specific employee's full profile
cat("=== Alice Full Information ===\n")
str(employees$alice)
# List of 6
# $ id : num 2024001
# $ name : chr "Alice"
# $ department : chr "Data Analysis Department"
# $ salary : num 15000
# $ skills : chr [1:3] "R" "Python" "SQL"
# $ projects : chr [1:2] "User Profiles" "Sales Forecast"
# 3. Use sapply for batch processing
cat("\n=== Annual Salaries of All Employees ===\n")
annual_salaries <- sapply(employees, function(emp) emp$salary * 12)
print(annual_salaries)
# alice bob charlie
# 180000 216000 240000
# 4. Use sapply to count skills
cat("\n=== Number of skills per employee ===\n")
skill_counts <- sapply(employees, function(emp) length(emp$skills))
print(skill_counts)
# alice bob charlie
# 3 3 2
# 5. Use split for grouping by department
cat("\n=== Grouped by Department ===\n")
dept_groups <- split(
sapply(employees, function(emp) emp$name),
sapply(employees, function(emp) emp$department)
)
print(dept_groups)
# $Data Analysis Department
# [1] "Alice"
#
# $Engineering Department
# [1] "Bob"
#
# $Product Department
# [1] "Charlie"
# 6. Add a New Employee
employees$diana <- list(
id = 2024004,
name = "Diana",
department = "Data Analysis Department",
salary = 16000,
skills = c("R", "Tableau"),
projects = c("Data Visualization")
)
cat("\n=== Add Diana after ===\n")
cat("Total Number of Employees:", length(employees), "\n")
cat("Diana Department:", employees$diana$department, "\n")
# 7. Identify the employee with the highest salary
top_salary <- which.max(sapply(employees, function(emp) emp$salary))
cat("\nHighest Salary:", names(employees)[top_salary], "(", max(sapply(employees, function(emp) emp$salary)), "USD)\n")
# 8. Retrieve the skills of all employees(Merge all skill vectors)
all_skills <- unlist(lapply(employees, function(emp) emp$skills))
cat("\n=== Company-wide Skills Summary ===\n")
print(table(all_skills))
# all_skills
# Axure Docker Figma Go Java Python R SQL Tableau
# 1 1 1 1 1 1 2 1 1
期待される出力(抜粋):
=== Alice Full Information ===
List of 6
$ id : num 2024001
$ name : chr "Alice"
...
=== Annual Salaries of All Employees ===
alice bob charlie
180000 216000 240000
=== Company-wide Skills Summary ===
all_skills
Axure Docker Figma Go Java Python R SQL Tableau
1 1 1 1 1 1 2 1 1
❓ よくある質問
Q:
[[ ]]と[ ]の違いは何ですか? A:[[ ]]は要素そのものを返します(これに対してさらに操作を行うことができます)。一方、[ ]は部分リストを返します(その要素に対してはそれ以上の操作を行うことはできません)。要素を取得するには[[ ]]または$を、部分集合を取得するには[ ]を使用します。これは R の構文において最も分かりにくい点の一つです。
Q:
$と[[ "name" ]]は同じものですか? A: 基本的には同等です。ただし、$は部分一致をサポートしています($naは「name」を自動的に一致させます)が、[[ ]]はサポートしていません。本番環境のコードでは、[[ "name" ]]を使用する方が安全です。
Q: リストとベクトルの関係はどのようなものですか? A: ベクトルは同質で1次元(すべての要素が同じ型)であるのに対し、リストは異質で、任意の次元を持つことができます(要素は任意の型であることができます)。
data.frame本質的に、リストとは「等長のベクトルのリスト」です。リストを理解することは、データフレームを理解することにつながります。
Q:
lapply()とsapply()のどちらを選べばよいですか? A:lapply()は(構造を保持したまま)リストを返しますが、sapply()は結果をベクトルまたは行列に簡略化します(読みやすくなります)。日常的なタスクにはsapplyを、関数型プログラミングのパイプラインにはlapplyを使用してください。
Q:
unlist()いつ使用すべきですか? A: リストをベクトルに「フラット化」するためです。ただし、フラット化できるのは単一型の要素のみです。型が混在している場合は、型変換が行われます(例:list(1, "a") → c("1", "a"))。
📖 まとめ
- リストはRの「汎用コンテナ」であり、あらゆる型(ベクトル、行列、関数、あるいは他のリストなど)を格納することができます。
- 4つのアクセス方法:
[[i]]$name[[ "name" ]](要素の取得)対[i](部分集合の取得) $name部分一致に対応(推奨されません)、[[ "name" ]]完全一致(推奨) 追加・削除・変更:l$new <- x(追加)/l$old <- NULL(削除)/l$old <- new_x(変更)lapply()各要素に関数を適用すると、リストが返されます;sapply()ベクトルに簡略化されましたunlist()リストをベクトルに平坦化する(異種の要素は強制変換される)- データフレーム
data.frameは、本質的に「等長のベクトルのリスト」です。データフレームを理解するには、リストを理解していることが前提となります。
📝 練習問題
-
基本演習:
studentという名前のリストを作成し、その中に 4 つのフィールドを含めます:name(文字)、age(数値)、scores(値 c(85, 90, 92) のベクトル)、およびpassed(ブール値)。リストの構造 (str()) を出力し、nameおよびscores[2]にアクセスしてください。 -
基本問題:3つのサブリスト
father、mother、child(それぞれがnameとageを含む)を含むネストされたリストfamilyを作成してください。child$ageにアクセスして、その値を出力してください。 -
基本問題:
lapply()を使用して、3人の従業員(自分で作成したもの)のリストに対する「年収」(salary * 12)を一括計算し、sapply()を使用して結果をベクトル出力に簡略化してください。 -
応用問題:名前付きリスト(id、name、dept、salary、skills=空のベクトル、is_active=TRUEを含む)を返す関数
create_employee(name, dept, salary)を記述してください。この関数を3回呼び出して3人の従業員を作成し、それらを大きなリストに格納してください。さらに、sapply()を使用して、全従業員の「年収」を抽出してください。 -
課題:「図書館」の管理をシミュレートするスクリプトを作成してください:① 3冊の本を含むリスト
libraryを作成します(各本には、title、author、year、availableの4つのフィールドがあります); ②lapplyを使用して、すべての書籍のavailableの値を FALSE(貸出中)に設定する; ③sapplyを使用して、貸出可能なすべての書籍を検索する (available == TRUE); ④ リストに新しい書籍を追加する。



