Rのデータフレームとファクター:tidyverseを用いたデータサイエンスの基礎
これまでの9回のレッスンでは、ベクトル、行列、リストについて学びましたが、これらにはそれぞれ限界があります。データフレーム(data.frame)は、これらの問題をすべて解決してくれます。Excelのスプレッドシートのように読みやすく、行列と同じくらい効率的です。このレッスンでは、Rの真の「主役」であるデータフレームについて学びます。
データフレームとtidyverseは、Rを用いたデータサイエンスの中核をなしています。このレッスンから、いよいよ「Rを用いたデータ分析」の世界に本格的に踏み込んでいきます。
1. 学習内容
data.frame()とtibble()の違い- データフレームの作成、表示、アクセス、および変更
- フィルタ、選択、並べ替え
- 因子(ファクター)カテゴリ変数
- dplyr の入門(データ処理の「5つの基本」)
- グループごとの集計(group_by + summarise)
- 実践的な活用:従業員データの包括的な分析
2. ExcelをRに変換した話
(1) 課題:Excelでは対応できない
陳氏の市場調査用スプレッドシートは、10,000行×8列で構成されています:
EmployeesID Name Department Salary Years Performance Gender Start Date
2024001 Alice Data Department 15000 3 A M 2021-03-15
2024002 Bob Engineering Department 18000 5 A+ M 2019-08-20
...
「部署」ごとの平均給与の算出、「業績」順の並べ替え、高収入の従業員の特定……。Excelでは、数式が複雑にネストされ、クラッシュしそうになるほどで、これらを行うのに30分もかかります。
(2) Rを用いた解決策
library(dplyr)
# 5 Code execution complete 5 An Analysis
df |>
group_by(Department) |>
summarise(Average Wage = mean(Salary), Number of people = n()) |>
arrange(desc(Average Wage)) |>
filter(Average Wage > 15000)
Excelで30分かかる作業を、たった5行のコードで。これこそがDataFrameとdplyrの真価です。
3. data.frame:Rの「主役」
(1) データフレームとは何ですか?
graph TB
A["Data Frame data.frame"] --> B["Each column = 1 equal-length vectors"]
A --> C["Each line = 1 records"]
A --> D["Mixed Types(Each column is independent)"]
A --> E["The bottom layer is'A list of vectors of equal length'"]
style A fill:#fff3cd
style B fill:#cce5ff
style C fill:#d4edda
style D fill:#f8d7da
style E fill:#e1d4ff
データフレームとは、「等長のベクトルのリスト」のことです:
- 各列は(同じ型の)ベクトルです
- すべての列は同じ長さです
- 列ごとに異なるデータ型(数値型、文字列型、論理型)を設定できます
(2) データフレームを作成する
# Methods 1:data.frame()(Basics R)
df <- data.frame(
name = c("Alice", "Bob", "Charlie"),
age = c(25, 30, 35),
score = c(95, 88, 92),
passed = c(TRUE, TRUE, TRUE)
)
print(df)
# name age score passed
# 1 Alice 25 95 TRUE
# 2 Bob 30 88 TRUE
# 3 Charlie 35 92 TRUE
# Methods 2:tibble(tidyverse Version,Recommendations)
# install.packages("tibble")
library(tibble)
df2 <- tibble(
name = c("Alice", "Bob", "Charlie"),
age = c(25, 30, 35),
score = c(95, 88, 92)
)
print(df2)
(3) data.frame と tibble の比較
| 機能 | data.frame | tibble |
|---|---|---|
| 印刷 | デフォルトですべての行を印刷(データ量が多い場合、システムがフリーズする可能性があります) | デフォルトで最初の10行と列の型を印刷 |
| 列名 | 特殊文字のサポート | 有効性の強制 |
| 部分集合の部分集合 | df[, "col"] ベクトルを返す |
常に tibble を返す |
| パフォーマンス | 遅い | 速い |
| 文字列 | デフォルトで因子に変換 | 文字列のまま保持 |
# View Structure
str(df)
# 'data.frame': 3 obs. of 4 variables:
# $ name : chr "Alice" "Bob" "Charlie"
# $ age : num 25 30 35
# $ score : num 95 88 92
# $ passed: logi TRUE TRUE TRUE
# Summary Statistics
summary(df)
# name age score passed
# Length:3 Min. :25 Min. :88 Mode :logical
# Class :character 1st Qu.:27 Median :92 TRUE:3
# Mode :character Mean :30 Mean :91 NA's :0
# 3rd Qu.:32 3rd Qu.:93
# Max. :35 Max. :95
4. DataFrameへのアクセス
(1) アクセス方法 4 つ
| メソッド | 構文 | 戻り値 | 目的 |
|---|---|---|---|
df[i, j] |
行 i、列 j | スカラー/ベクトル/データフレーム | 行と列の組み合わせ |
df[i, ] |
行 i | DataFrame | 行を取得 |
df[, j] |
列 j | ベクトル(R標準) / データフレーム | 列の抽出 |
df$name |
列名 | ベクトル | 列の取得 |
df[["name"]] |
列名 | ベクトル | 列の取得 |
df <- data.frame(
name = c("Alice", "Bob", "Charlie"),
age = c(25, 30, 35),
score = c(95, 88, 92)
)
# Retrieve a single element
df[2, 3] # [1] 88
df[2, "score"] # [1] 88
# Select the entire row
df[1, ] # Entire row (Data Frame)
# name age score
# 1 Alice 25 95
# Round an entire column
df[, "age"] # Digital Vectors [1] 25 30 35
df$age # Ibid.
df[["age"]] # Ibid.
(2) 論理インデックス(フィルター)
# Find the Fraction > 90 line
df[df$score > 90, ]
# name age score
# 1 Alice 25 95
# 3 Charlie 35 92
# Multiple conditions
df[df$age > 25 & df$score > 85, ]
(3) ⚠️ 重要:ベースRとtibbleにおける列の取得の違い
# base R:Retrieve the column return vector
df[, "age"] # [1] 25 30 35 ← Digital Vectors
# tibble:Retrieve and return the column tibble
library(tibble)
tb <- as_tibble(df)
tb[, "age"] # ← tibble(1 row 1 col)
# Want to extract a vector from tibble: Use [[ ]] or $
tb[["age"]] # [1] 25 30 35 ← Digital Vectors
[, "col"]は自動的にベクトルに変換されません。これは「安全」を目的とした設計上の機能であり、大規模なデータフレームが誤ってベクトルと解釈され、出力全体がフリーズしてしまうのを防ぐためのものです。
5. データフレームの変更
(1) 列を追加する
# Use $ to add
df$city <- c("Beijing", "Shanghai", "Guangzhou")
# Use transform()
df <- transform(df, bonus = score * 100)
# Use within() to reference column names
df <- within(df, level <- ifelse(score >= 90, "A", "B"))
print(df)
# name age score city bonus level
# 1 Alice 25 95 Beijing 9500 A
# 2 Bob 30 88 Shanghai 8800 B
# 3 Charlie 35 92 Guangzhou 9200 A
(2) 列の変更
# Array Assignment
df$age <- df$age + 1
# Condition Modification
df$score[df$name == "Bob"] <- 90
(3) 列を削除する
# Assign NULL
df$bonus <- NULL
df$level <- NULL
(4) 行の追加・削除
# Add a row: Use rbind
new_row <- data.frame(name = "Diana", age = 28, score = 85, city = "Shenzhen")
df <- rbind(df, new_row)
# Delete Row:Using Negative Indexes
df <- df[-1, ] # Delete 1st row
6. 因子:カテゴリ変数
(1) なぜ因子が必要なのか?
Rでは、カテゴリ変数(「低/中/高」など)を表す際に、factors を使用する方が、文字ベクトルを使用するよりも強力です:
# Character vector(Disorder)
gender_char <- c("M", "F", "M", "F", "M")
# factor(Orderly + Finite values)
gender_factor <- factor(gender_char, levels = c("M", "F"))
gender_factor
# [1] M F M F M
# Levels: M F
(2) ファクターの利点
graph TB
A["Character vector 'Low' 'Mid' 'High'"] --> B["factor factor<br/>+ levels Order<br/>+ Finite values<br/>+ Save memory"]
A --> C["Disadvantages: Cannot sort and compare"]
B --> D["Advantages: Can be compared for size<br/>Can be grouped in order<br/>Statistics/Knowing the Number of Categories in Modeling"]
style A fill:#f8d7da
style B fill:#d4edda
style D fill:#cce5ff
# Compare Sizes(Characters cannot,Factors can)
sizes <- factor(c("S", "L", "Mid", "L", "S"),
levels = c("S", "Mid", "L"),
ordered = TRUE)
sizes[1] < sizes[2] # TRUE <- Characters can't do that!
(3) 因数に対する一般的な演算
# View levels
levels(sizes)
# [1] "S" "Mid" "L"
# Frequency Count
table(sizes)
# sizes
# S Mid L
# 2 1 2
# Reorder
sizes <- factor(sizes, levels = c("L", "Mid", "S")) # Reverse the order
levels(sizes)
# [1] "L" "Mid" "S"
forcatsパッケージ(第11課で解説)を使用することをお勧めします。これは、ベースRよりも洗練されているためです。
(4) データフレーム内の要因
# data.frame() Convert character strings to factors by default (This is a trap!)
df <- data.frame(
name = c("Alice", "Bob"), # Character vector
stringsAsFactors = FALSE # Disable Auto-Conversion(Recommendations)
)
str(df)
# $ name: chr "Alice" "Bob" ← Preserve characters
stringsAsFactors = FALSE が使用されますが、古いコードでは異なる値が使用されている可能性があります。明示的に stringsAsFactors = FALSE と記述することをお勧めします。
7. dplyr入門:データ処理の5つの基本
dplyr は tidyverse の核となる存在であり、5つの関数でデータ処理シナリオの80%をカバーしています:
(1) インストールと読み込み
install.packages("dplyr")
library(dplyr)
(2) 5部構成の関数
| 関数 | 目的 | 対応するSQL |
|---|---|---|
filter() |
行のフィルタリング | WHERE |
select() |
列を選択 | SELECT |
mutate() |
列の追加・変更 | — |
arrange() |
並べ替え | ORDER BY |
summarise() |
集計統計 | GROUP BY |
(3) 連鎖演算子 |>
# |> is R 4.1+'s "pipe symbol", Pass the result from the previous step to the next step
df |> filter(age > 25) |> select(name, age)
(4) 実践編:従業員データの処理
# Prepare the data
employees <- tibble(
id = 2024001:2024010,
name = c("Alice", "Bob", "Charlie", "Diana", "Eve",
"Frank", "Grace", "Henry", "Ivy", "Jack"),
department = c("Data Department", "Engineering Department", "Data Department", "Product Department", "Engineering Department",
"Data Department", "Engineering Department", "Product Department", "Data Department", "Engineering Department"),
salary = c(15000, 18000, 16000, 20000, 17000,
15500, 19000, 21000, 16500, 17500),
years = c(3, 5, 4, 7, 4, 2, 6, 8, 3, 5),
performance = factor(
c("A", "A+", "B", "A+", "A", "B", "A", "A+", "B", "A"),
levels = c("B", "A", "A+"),
ordered = TRUE
)
)
# 1. filter:Screening Data Department Employees
data_dept <- employees |> filter(department == "Data Department")
# 2. select:Select a subset of columns
basic_info <- employees |> select(name, department, salary)
# 3. mutate:Add an "Annual Salary" column
employees <- employees |> mutate(annual_salary = salary * 12)
# 4. arrange:Sort by salary in descending order
ranked <- employees |> arrange(desc(salary))
# 5. summarise:By Department
dept_stats <- employees |>
group_by(department) |>
summarise(
Number of people = n(),
Average Wage = mean(salary),
Highest Salary = max(salary),
Total Annual Salary = sum(annual_salary)
) |>
arrange(desc(Average Wage))
print(dept_stats)
# # A tibble: 3 × 5
# department Number of people Average Wage Highest Salary Total Annual Salary
# `<chr>` `<int>` `<dbl>` `<dbl>` `<dbl>`
# 1 Product Department 2 20500 21000 492000
# 2 Engineering Department 4 17875 19000 858000
# 3 Data Department 4 15750 16500 756000
(5) 5段階の組み合わせの例
# Comprehensive Example:Identify High-Performing, High-Earning Employees
top_talent <- employees |>
filter(performance %in% c("A+", "A")) |> # Performance Screening A+ or A
filter(salary > 16000) |> # ② Filter by High Salary
mutate(salary_level = ifelse(salary > 18000, "High", "Upper-middle")) |> # ③ Add Category
arrange(desc(salary)) |> # ④ Sort
select(name, department, salary, performance, salary_level) # ⑤ Select Column
print(top_talent)
# # A tibble: 3 × 5
# name department salary performance salary_level
# `<chr>` `<chr>` `<dbl>` `<ord>` `<chr>`
# 1 Henry Product Department 21000 A+ High
# 2 Diana Product Department 20000 A+ High
# 3 Bob Engineering Department 18000 A+ Upper-middle
8. 完全な例:従業員データの包括的な分析
以下は、このレッスンで取り上げたすべての概念を結びつけた完全なワークフローの例です。
▶ サンプル:企業の従業員データの包括的な分析
# ============================================
# Comprehensive Analysis of Company Employee Data
# Features:Using a DataFrame + dplyr Comprehensive Analysis 10 employees
# ============================================
library(dplyr)
# 1. Prepare data
employees <- tibble(
id = 2024001:2024010,
name = c("Alice", "Bob", "Charlie", "Diana", "Eve",
"Frank", "Grace", "Henry", "Ivy", "Jack"),
department = c("Data Department", "Engineering Department", "Data Department", "Product Department", "Engineering Department",
"Data Department", "Engineering Department", "Product Department", "Data Department", "Engineering Department"),
salary = c(15000, 18000, 16000, 20000, 17000,
15500, 19000, 21000, 16500, 17500),
years = c(3, 5, 4, 7, 4, 2, 6, 8, 3, 5),
performance = factor(
c("A", "A+", "B", "A+", "A", "B", "A", "A+", "B", "A"),
levels = c("B", "A", "A+"),
ordered = TRUE
)
)
cat("=== Raw Data ===\n")
print(employees)
# 2. View Structure
cat("\n=== Data Structures ===\n")
str(employees)
# 3. Summary Statistics
cat("\n=== Abstract ===\n")
summary(employees)
# 4. By Department
cat("\n=== By Department ===\n")
dept_summary <- employees |>
group_by(department) |>
summarise(
Number of people = n(),
Average Wage = mean(salary),
Median Wage = median(salary),
Highest Salary = max(salary),
Minimum Wage = min(salary),
Average Length of Service = round(mean(years), 1)
) |>
arrange(desc(Average Wage))
print(dept_summary)
# 5. Identify High-Performing Employees (A+ or A)
cat("\n=== Employees with Outstanding Performance ===\n")
top_perf <- employees |>
filter(performance %in% c("A+", "A")) |>
arrange(desc(salary)) |>
select(name, department, salary, performance, years)
print(top_perf)
# 6. Add"Pay Grade"col
cat("\n=== Salary Grade Classification ===\n")
employees <- employees |>
mutate(
salary_level = factor(
ifelse(salary >= 18000, "High",
ifelse(salary >= 16000, "Mid", "Low")),
levels = c("Low", "Mid", "High"),
ordered = TRUE
),
annual_salary = salary * 12
)
# By Pay Grade
level_summary <- employees |>
group_by(salary_level) |>
summarise(Number of people = n(), Average Wage = mean(salary))
print(level_summary)
# 7. Identify the Best Employees (High Salary + High Performance + Senior)
cat("\n=== Top Employee (High Salary + Outstanding Performance + Senior) ===\n")
top_talent <- employees |>
filter(salary >= 17000, performance == "A+", years >= 5) |>
select(name, department, salary, years, performance, annual_salary)
print(top_talent)
期待される出力(抜粋):
=== By Department ===
# A tibble: 3 × 7
department Number of people Average Wage Median Wage Highest Salary Minimum Wage Average Length of Service
`<chr>` `<int>` `<dbl>` `<dbl>` `<dbl>` `<dbl>` `<dbl>`
1 Product Department 2 20500 20500 21000 20000 7.5
2 Engineering Department 4 17875 17750 19000 17000 4.5
3 Data Department 4 15750 15750 16500 15000 3
=== Employees with Outstanding Performance ===
# A tibble: 6 × 5
name department salary performance years
`<chr>` `<chr>` `<dbl>` `<ord>` `<dbl>`
1 Henry Product Department 21000 A+ 8
2 Diana Product Department 20000 A+ 7
3 Bob Engineering Department 18000 A+ 5
4 Grace Engineering Department 19000 A 6
5 Eve Engineering Department 17000 A 4
6 Jack Engineering Department 17500 A 5
❓ よくある質問
ordered = TRUE)② メモリを節約できる(整数エンコーディングのみを格納する)③ カテゴリ数が既知の場合、統計分析やモデリングが可能になる(「未知の値」の問題を回避できる)。📖 まとめ
- データフレームとは、「同じ長さのベクトルのリスト」であり、各列は異なるデータ型を持ち、各行には1つのデータレコードが含まれています。
data.frame()Rの基礎、tibble現代のtidyverse(新規プロジェクトにおすすめ)- 4つのアクセス先:
df[i, j]df$namedf[["name"]]df[, j] - 因子とは「順序付きカテゴリ変数」であり、レベルによって順序が制御されるため、メモリを節約できる
- dplyr 5点セット:
filterselectmutatearrangesummarise group_by() | summarise()グループ集計を実行する;|>パイプ記号 を使用して複数の操作を連結するmutateは、先ほど作成されたカラムを参照しています(transformではこれができません)。そのため、tidyverse ではmutateの方がよく使われています。
📝 練習問題
-
基本演習:
data.frame()を使用して、studentsというデータフレーム(学生 6 人 × 4 列:名前/年齢/得点/合格)を作成してください。データフレーム、str()、およびsummary()を出力し、3 行目のすべての列にアクセスしてください。 -
基本問題:前の問題の
name列をfactor(3 段階)に変換し、as.character()とas.numeric()の違いを比較する。この因子が大きさの比較(>)に対応していることを確認する。 -
基本問題:
dplyrをインストールして読み込み、filter()を使用して、前の問題で求めたstudentsに基づいてscore > 85から学生を抽出します。その後、arrange()を使用して、得点の降順で並べ替えます。 -
応用演習:
tibbleを使用して、salesデータフレーム(10行×4列:製品/地域/数量/日付)を作成してください。①mutate()を使用してdiscount = amount * 0.1の合計を算出する;②group_by(region) + summarise()を使用して各地域の総売上高を算出する;③arrange(desc())を使用して地域を順位付けする。 -
課題:模擬の従業員データ(従業員10名、3つの部署、給与・勤続年数・業績)を用いて、以下の7段階の分析を完了してください:① dplyrを読み込む ② 部署ごとの従業員数と平均給与を算出する ③ 勤続年数が5年以上で給与の高い従業員を特定する ④
mutateを使用して年俸の列を追加する ⑤case_when(またはifelse)を使用して給与帯ごとに分類する ⑥ 業績順に並べ替える ⑦ 新しいデータフレームtop_employeesに書き出し、CSVファイルとして保存する(write.csv())。



