ビッグデータ

脱・初心者!Rデータハンドリング実践術

2025年7月12日

はじめに:データと向き合うための準備

データ分析の始まり

臨床研究やその他の科学的な探求において、データ分析は結論を導き出すための非常に重要なステップです。しかし、どんなに高度な分析手法を知っていても、その前段階である「データハンドリング」、つまりデータの整理と加工が適切に行われていなければ、信頼できる結果を得ることはできません。データハンドリングは、しばしば分析全体の時間の大部分を占める地道な作業ですが、ここを乗り越えることで、分析は驚くほどスムーズに進みます。この記事では、統計解析言語Rを用いて、このデータハンドリング技術を基礎から実践まで、丁寧に解説していきます。

「プログラミング言語であるRは難しそう」と感じる方もいるかもしれませんが、心配はいりません。R、特に「tidyverse」と呼ばれるパッケージ群は、データサイエンスの作業を直感的かつ効率的に行うために設計されています 1。tidyverseは、データ操作、可視化、モデリングといった一連のタスクに対して、一貫した考え方と文法を提供します。これにより、一度考え方を身につければ、様々な応用が可能になります。この記事は、プログラミングの経験がない方でも、一歩一歩着実に理解を深められるように構成されています。データとの対話を始めるための最初のステップとして、データハンドリングの基礎をしっかりと学び、あなたの分析スキルを新たな高みへと引き上げていきましょう。

失敗しないためのプロジェクト管理:setwd()の罠とhereパッケージ

データ分析の作業を始めるとき、多くの初学者が最初に出会う困難の一つが、ファイルのパス、つまりコンピューター上でのファイルの所在地の指定です。特に、setwd()という関数を使って作業ディレクトリ(ワーキングディレクトリ)を設定する方法は、多くの入門書で紹介されていますが、実はこれは非常に「壊れやすい」アプローチであり、将来の自分自身や共同研究者を混乱させる原因となります 2

setwd()の問題点は、コンピューターの特定のフォルダ構造に依存してしまうことにあります。例えば、setwd("C:/Users/MyName/Documents/ClinicalStudy_2025")のように絶対パスを記述したとします。このコードは、あなたのそのコンピューターで、その瞬間に実行する限りは問題なく動作します。しかし、このスクリプトを同僚に共有したり、数か月後にあなたが新しいコンピューターで実行しようとしたりすると、同じフォルダ構造が存在しないため、即座にエラーが発生します。これは、分析の再現性を著しく損なう、避けるべき習慣です。

この問題を根本的に解決するために、私たちはhereパッケージの使用を強く推奨します。hereパッケージは、個人のコンピューターの絶対パスに依存するのではなく、「プロジェクト」という単位でファイルの場所を管理する考え方に基づいています 4。RStudioには「プロジェクト」機能があり、分析に関連するファイル(データ、Rスクリプト、レポートなど)を一つのフォルダにまとめて管理することができます。このプロジェクトフォルダの最上位階層(ルートディレクトリ)を基準点として、

hereパッケージはファイルへのパスを自動的に構築してくれるんです 3

例えば、プロジェクトフォルダの中にdataというサブフォルダを作り、そこにmydata.csvというファイルを保存したとします。このファイルを読み込む際、hereパッケージを使えば、here("data", "mydata.csv")と記述するだけで、Rはプロジェクトのルートからdataフォルダを探し、その中のmydata.csvへの完全なパスを生成してくれます 4。このコードは、プロジェクトフォルダがデスクトップにあろうと、サーバー上にあろうと、あるいは共同研究者のコンピューターのどこにあろうと、全く同じように正しく動作します。

このように、setwd()を使うかhereパッケージを使うかという選択は、単なる技術的な好みの問題ではありません。それは、個人の環境に固執した一度きりの分析を行うのか、それとも他者と共有可能で、将来にわたって再現可能な、堅牢なワークフローを構築するのかという、分析に対する根本的な姿勢の選択を意味します。最初からhereパッケージとRStudioのプロジェクト機能を組み合わせる習慣を身につけることは、再現性の高い科学研究を行う上での第一歩であり、将来のあらゆるトラブルからあなたを救ってくれる、最も価値のある投資の一つと言えるでしょう。

さらに、here::i_am()という関数を使うことで、スクリプト自身がプロジェクト内のどこに位置するのかを明示的に宣言することも可能です。これにより、より複雑なフォルダ構造を持つプロジェクトでも、パスの基準点が曖昧になることを防ぎ、ワークフローの堅牢性をさらに高めることができます 2

データの読み込み:read.csv()を使いこなす

プロジェクト管理の基礎を固めたら、次はいよいよデータをRに読み込むステップです。データハンドリングの旅は、ここから始まります。最も一般的に使用されるデータ形式の一つがCSV(Comma-Separated Values)ファイルであり、これを読み込むためにはread.csv()関数を使用します。

先ほどのhereパッケージの知識と組み合わせることで、非常に堅牢なデータ読み込みコードを記述できます。例えば、プロジェクトルート直下のdataフォルダにあるmydata.csvファイルを読み込み、dataという名前のオブジェクト(変数)に格納するには、次のように書きます。

data <- read.csv(here("data", "mydata.csv"))

しかし、実際の研究データは、単純にファイルを指定するだけでは正しく読み込めないことが多々あります。ここでread.csv()関数の便利な引数(オプション)を知っているかどうかが、作業の効率を大きく左右します。特に重要な引数が二つあります。それはna.stringsとfileEncodingです。

na.strings引数は、データの中でどの文字列を「欠損値」として扱うかを指定するためのものです。Rでは、欠損値は通常NAという特別な値で表現されます。しかし、実際のデータセットでは、空欄("")、ハイフン(-)、あるいは"NA"というただの文字列など、様々な方法で欠損が記録されていることがあります。これらの値を正しくNAとしてRに認識させるために、na.strings = c("", "-", "NA")のように、欠損値を表す可能性のある文字列をベクトルとして指定します。これを怠ると、欠損しているはずのデータが文字列やゼロとして読み込まれてしまい、後の計算で誤った結果を生む原因となります。

もう一つの重要な引数がfileEncodingです。これは、ファイルの文字エンコーディングを指定するものです。特に、日本語を含むデータを扱う際には、この設定が不可欠です。Windowsで作成されたCSVファイルは「Shift_JIS」("SJIS")で保存されていることが多く、一方でウェブやMac、Linux環境では「UTF-8」("UTF-8")が標準的です。もしファイルエンコーディングとread.csv()の指定が一致していないと、日本語部分が文字化けしてしまい、データを正しく解釈できなくなります。どちらのエンコーディングか不明な場合は、両方試してみると良いでしょう。

これらの引数を組み合わせると、より実践的な読み込みコードは次のようになります。

data <- read.csv(here("data", "mydata.csv"), na.strings = c("", "-", "NA"), fileEncoding = "SJIS")

この一行を正しく書くことが、その後のすべてのデータハンドリングと分析の正確性を保証する、非常に重要な基礎となるんです。

分析しやすいデータの形とは

整然データ(Tidy Data)という考え方

tidyverseの世界でデータハンドリングを学ぶ上で、避けては通れない非常に重要な概念があります。それが「整然データ(Tidy Data)」という考え方です 1。これは、

tidyverseの生みの親であるHadley Wickhamによって提唱された、分析しやすいデータの構造に関する一連のルールです。この考え方を理解することが、なぜtidyverseの関数群がそのように設計されているのかを理解する鍵となり、今後の学習を飛躍的に容易にします。

整然データの目的は、「データの構造と意味を一致させる」ことにあります 6。そして、そのための具体的なルールは、驚くほどシンプルです。整然データは、主に三つの条件を満たす必要があります 1

第一に、各変数が、それぞれ一つの列をなすこと。これは最も基本的で重要なルールです。例えば、患者のID、治療群、投薬前の測定値、投薬後の測定値という情報があったとします。このとき、「投薬前の測定値」と「投薬後の測定値」は、それぞれ別の列として表現されるべきではありません。なぜなら、これらは両方とも「測定値」という一つの変数であり、「投薬前」「投薬後」というのは「測定時点」という別の変数の値だからです。

第二に、各観測が、それぞれ一つの行をなすこと。観測とは、ある観測単位(例えば一人の患者)について測定された値の集合を指します。先の例で言えば、一人の患者に対して投薬前と投薬後の二回測定を行った場合、それは二つの異なる観測と見なされます。したがって、データフレームの中では、これらは二つの別々の行として表現されるべきです。

第三に、各値が、それぞれ一つのセルをなすこと。これは、一つのセルに複数の情報が混在してはならない、というルールです。例えば、"2025/01/17"のような日付データは、解釈によっては「年」「月」「日」という三つの値を含んでいると考えることもできますが、通常は一つの日付情報として扱われます。しかし、"男性, 53歳"のように明らかに複数の情報が一つのセルに入っている場合は、このルールに違反しています。

これらのルールを、具体的な例で考えてみましょう。ある研究で、3人の被験者(Aさん、Bさん、Cさん)に対して、治療前(Control)と治療後(Treatment)のスコアを測定したとします。多くの人が、スプレッドシートで次のような「横に広い(wide-format)」データを作成しがちです。

被験者, Control, Treatment

A, 85, 92

B, 78, 81

C, 90, 95

このデータは、一見して分かりやすいように見えますが、整然データのルールには違反しています。Control列とTreatment列は、本来「スコア」という一つの変数を表しているにもかかわらず、二つの列に分かれてしまっています。これは第一のルールに反します。また、各行には治療前と治療後の二つの観測が含まれており、第二のルールにも反しています。

このデータを整然な形、すなわち「縦に長い(long-format)」データに変換すると、次のようになります 6

被験者, 時点, スコア

A, Control, 85

A, Treatment, 92

B, Control, 78

B, Treatment, 81

C, Control, 95

C, Treatment, 95

この形こそが、整然データです。「被験者」「時点」「スコア」という三つの変数が、それぞれ独立した列になっています。そして、各行は「ある被験者の、ある時点における、一つのスコア」という単一の観測を表しています。この構造にすることで、tidyverseの関数群、特にデータ操作を行うdplyrや可視化を行うggplot2との連携が非常にスムーズになるんです。整然データは、いわばtidyverseという言語の文法のようなものです。この文法に従うことで、私たちはRと円滑な対話を行うことができるようになります。

tidyrパッケージによるデータの整形

整然データの概念を理解したところで、次に問題となるのは、手元にある「整然でない(messy)」データを、どのようにして整然な形に変換するかです。この役割を担うのが、tidyverseファミリーの一員であるtidyrパッケージです 9

tidyrは、データの「形」を整えるための強力なツールを提供します。

実世界のデータで最も頻繁に遭遇する整然でない形式は、先ほどの例で見たような「横に広い」データです。つまり、列名が変数の値(例えば、"2023年", "2024年", "2025年")を表してしまっているようなケースです。このようなデータを整然な「縦に長い」形式に変換するために、tidyrパッケージはpivot_longer()という非常に便利な関数を用意しています 6。この関数は、かつて

gather()という名前で知られていましたが、より直感的で高機能なpivot_longer()に置き換えられました。古いコードではgather()が使われていることもあるため、覚えておくとよいでしょう 8

pivot_longer()関数は、いくつかの重要な情報を引数として受け取ります。まず、どの列を縦長に変換したいのかをcols引数で指定します。次に、元の列名が格納される新しいキー列の名前をnames_to引数で、そして元のセルの値が格納される新しい値列の名前をvalues_to引数で、それぞれ文字列として指定します 6

先ほどの治療前後のスコアの例で、df1というデータフレームが横長の形式だったとします。これを整然な縦長データに変換するコードは次のようになります。

df1_long <- df1 %>% pivot_longer(cols = c(Control, Treatment), names_to = "時点", values_to = "スコア")

このコードを実行すると、Control列とTreatment列がまとめられ、その列名であった"Control"と"Treatment"という文字列が新しい「時点」列に格納されます。そして、それぞれのスコアの値が新しい「スコア」列に格納されます。

pivot_longer()の強力な点は、単にデータを変換するだけでなく、その過程で様々なデータクリーニングを同時に行えることです。例えば、names_prefix引数を使えば、元の列名に含まれる共通の接頭辞(例えば"Day1", "Day2"の"Day")を取り除くことができます。また、values_drop_na = TRUEと設定すれば、変換後の値が欠損値(NA)である行を自動的に削除することも可能です 6

なぜ、データ操作のdplyrや可視化のggplot2を学ぶ前に、このtidyrと整然データの概念を学ぶのでしょうか。それは、整然データがtidyverseのツール群とデータを結びつける「契約」のような役割を果たすからです。データを整然な形という契約に準拠させることで、その後のすべてのツールが驚くほど直感的に、そして意図した通りに機能するようになります。例えば、整然データがあれば、group_by(時点)のようにグループ化したり、ggplot(aes(x = 時点, y = スコア))のように可視化したりすることが、変数名を直接指定するだけで可能になります。この統一された枠組みを最初に理解することが、個々の関数をバラバラに暗記するよりも、はるかに効率的で本質的な学習へと繋がるんです。

データ操作の基本:dplyrの主要な動詞

パイプ演算子 %>%:処理を繋げる(ってどういうこと?)

tidyverseの世界、特にデータ操作パッケージであるdplyrを学ぶ上で、まず最初にマスターすべき最も重要な道具が「パイプ演算子」です。これは%>%という記号で表されます。この演算子は、Rのコードの書き方を劇的に変え、データ分析の思考プロセスをより自然な形で表現することを可能にします。

パイプ演算子がない場合、複数の処理を連続して行うには、関数を入れ子にするか、あるいは各ステップで中間的な変数を作成する必要がありました。例えば、データdに対して、まずh()という関数を適用し、その結果にg()を適用し、さらにその結果にf()を適用する場合、f(g(h(d)))のように書くことになります。この書き方は、処理の順番が内側から外側へと、読む方向と逆になるため、複雑になると非常に読みにくくなります。あるいは、中間変数を作る方法では、d1 <- h(d)、d2 <- g(d1)、d3 <- f(d2)のように、多くの変数を管理する必要が生じます 11

ここでパイプ演算子が登場します。パイプ演算子は、左側にあるオブジェクトを、右側にある関数の第一引数として「渡す」役割を果たします 12。これを使うと、先ほどの処理は次のように書くことができます。

d %>% h() %>% g() %>% f()

このコードは、英語の"then"のように、「データdを、次にh()で処理し、次にその結果をg()で処理し、最後にその結果をf()で処理する」と、左から右へ、思考の流れに沿って自然に読むことができます 12。これにより、コードの可読性が劇的に向上し、何をしているのかが一目瞭然になります。

dplyrの関数群は、すべてこのパイプ演算子と共に使われることを前提に設計されています。データフレームを起点として、%>%で次々と処理を繋げていくことで、一連のデータハンドリングが一つの連続したコードブロックとして表現されます。RStudioでは、この頻繁に使う%>%を簡単に入力するためのキーボードショートカット(WindowsではCtrl + Shift + M、macOSではCmd + Shift + M)が用意されており、これを活用することで、さらにスムーズにコーディングを進めることができます。このパイプ演算子こそが、dplyrによるデータ操作を流れるように、そして直感的にしてくれます。

行のフィルタリング:filter()

データハンドリングにおいて最も基本的な操作の一つが、特定の条件に合致する行だけを抽出することです。例えば、臨床研究データの中から「特定の治療群に属する患者」や「年齢が50歳以上の患者」だけを取り出したい、といった場面は頻繁にあります。この役割を担うのが、dplyrのfilter()関数です。

filter()関数は、第一引数にデータフレームを受け取り、その後の引数で抽出したい行の条件を論理式で指定します。パイプ演算子と組み合わせることで、その威力は最大限に発揮されます。例えば、dataというデータフレームから、treatmentという列の値が"Drug A"である行だけを抽出したい場合、次のように記述します。

data_filtered <- data %>% filter(treatment == "Drug A")

ここで注意すべき点は、等しいことを示す比較演算子が=ではなく==(イコール二つ)であることです。Rにおいて、=は代入に使われることがあり、比較には==を用いるのが一般的です。この違いは、初学者が陥りやすい間違いの一つです 13

数値の条件を指定することも簡単です。例えば、age列が50以上の行を抽出するには、filter(age >= 50)と書きます。>(より大きい)、<(より小さい)、>=(以上)、<=(以下)、!=(等しくない)といった比較演算子を自由に使うことができます 14

さらに、複数の条件を組み合わせて、より複雑な抽出を行うことも可能です。条件を「かつ(AND)」で結びたい場合は&記号またはカンマ(,)を、「または(OR)」で結びたい場合は|記号を使用します。例えば、「治療群が"Drug A"であり、かつ年齢が50歳以上」の行を抽出するには、次のように書きます。

data %>% filter(treatment == "Drug A", age >= 50)

あるいは、「性別が"Female"であるか、または年齢が65歳以上」の行を抽出するには、次のように書きます。

data %>% filter(sex == "Female" | age >= 65)

また、複数の特定のカテゴリーに含まれる行を一度に抽出したい場合には、%in%演算子が非常に便利です。例えば、region列が"Tokyo"、"Osaka"、"Nagoya"のいずれかである行を抽出したい場合、|を何度も使う代わりに、次のようにすっきりと記述できます 15

data %>% filter(region %in% c("Tokyo", "Osaka", "Nagoya"))

このようにfilter()関数を使いこなすことで、巨大なデータセットの中から、分析に必要な部分集合を的確かつ効率的に取り出すことができるようになります。

列の選択:select()

データフレームには多くの変数が含まれていることがありますが、分析の特定の段階では、そのうちのいくつかだけが必要になることがよくあります。不要な列を非表示にしたり、特定の列だけを取り出して新しいデータフレームを作成したりするために使うのが、dplyrのselect()関数です。

select()関数の基本的な使い方は非常にシンプルです。パイプでデータフレームを受け取った後、残したい列の名前をカンマで区切って指定します。例えば、dataというデータフレームからid、age、sexの三つの列だけを選択するには、次のように書きます。

data_selected <- data %>% select(id, age, sex)

逆に、特定の列を「除外」したい場合は、列名の前にマイナス記号(-)を付けます。例えば、notesという備考欄の列が不要な場合、次のようにして除外できます 15

data %>% select(-notes)

select()の真価は、列名を一つ一つ手で入力するのではなく、パターンを使って効率的に列を選択できる「ヘルパー関数」と組み合わせることで発揮されます。これは、特に変数名に一貫した命名規則がある場合に強力です。

例えば、starts_with()関数を使うと、特定の文字列で始まるすべての列を選択できます。臨床データで、visit1_score, visit2_score, visit3_scoreといった列がある場合に、visitで始まるすべての列を選択するには、select(starts_with("visit"))と書きます。同様に、ends_with()は特定の文字列で終わる列を、contains()は特定の文字列を含む列を選択するために使われます 15

また、everything()というヘルパー関数も便利です。これはすべての列を意味し、特定の列を先頭に移動させたい場合などによく使われます。例えば、patient_id列を一番左に、残りの列をその右に配置したい場合は、次のように書きます 15

data %>% select(patient_id, everything())

これらのヘルパー関数を駆使することで、数十、数百の列を持つような大規模なデータフレームでも、手作業によるミスを減らし、迅速かつ正確に必要な列だけを操作することが可能になります。select()は、単なる列の選択ツールではなく、データセットの構造を分析の目的に合わせて自在に再編成するための強力な手段です。

並べ替え:arrange()

データを特定の順序で並べ替えることは、結果の確認や可視化の準備段階で非常に重要な操作です。例えば、患者を年齢順に並べたり、検査値を高い順に並べたりすることで、データの傾向を把握しやすくなります。この役割を担うのがdplyrのarrange()関数です。

arrange()関数の使い方は直感的です。パイプでデータフレームを受け取った後、並べ替えの基準としたい列の名前を指定します。デフォルトでは、指定された列の値が小さい順、つまり昇順(ascending order)でデータフレーム全体の行が並べ替えられます。例えば、dataデータフレームをage列の昇順で並べ替えるには、次のように記述します。

data_sorted <- data %>% arrange(age)

もし、大きい順、つまり降順(descending order)で並べ替えたい場合は、desc()というヘルパー関数を列名に適用します。年齢が高い順に並べ替えるには、次のようにします。

data_sorted_desc <- data %>% arrange(desc(age))

arrange()は、複数の列を基準に並べ替えることも可能です。その場合、引数をカンマで区切って指定します。Rは、最初の引数で指定された列でまず並べ替えを行い、もしその値が同じ行があった場合には、次に指定された列の値を基準に並べ替えを行います。例えば、まずtreatment_group列でアルファベット順に並べ、同じ治療群の中ではageの降順で並べたい場合は、次のように記述します。

data %>% arrange(treatment_group, desc(age))

この操作により、まずデータ全体が治療群ごとにグループ化され、それぞれのグループ内で年齢の高い患者が上に来るようにソートされます。

欠損値(NA)の扱いはarrange()の重要な特徴です。デフォルトでは、NAは常に並べ替えの最後に配置されます。これは、desc()を使った降順の並べ替えでも同様です。この挙動は、欠損値を持つ行をまとめて確認したい場合などに便利です。

arrange()は、データの中身を直接変更するわけではありませんが、データの見方を変え、パターンを発見するための強力な補助ツールです。特に、filter()やselect()といった他のdplyr関数と組み合わせることで、データの探索的分析をより効率的に進めることができます 16

列の作成と変更:mutate() と case_when()

データハンドリングの中核をなす作業の一つが、既存の変数から新しい変数を作成したり、既存の変数の値を変更したりすることです。例えば、身長と体重のデータからBMIを計算したり、年齢から年代カテゴリーを作成したりする作業がこれにあたります。dplyrでは、このための主要な関数としてmutate()が提供されています。

mutate()関数は、データフレームに新しい列を追加するか、既存の列を上書きします。基本的な使い方は、新しい列名 = 式という形で記述します。例えば、dataデータフレームにheight_m(メートル単位の身長)とweight_kg(キログラム単位の体重)という列がある場合に、BMIを計算してbmiという新しい列を追加するには、次のように書きます。

data_with_bmi <- data %>% mutate(bmi = weight_kg / (height_m ^ 2))

複数の列を一度に追加することも可能です。その場合は、カンマで区切って式を並べます。

次に、条件に応じて値を変更する、より複雑なケースを考えてみましょう。初学者がよく使う方法に、ifelse()関数があります。これは、「もし条件が真ならAを、偽ならBを返す」という単純な二者択一の処理には非常に適しています。例えば、年齢(age)が20歳以上なら"adult"、そうでなければ"child"という値を持つage_group列を作成するには、次のように書けます。

data %>% mutate(age_group = ifelse(age >= 20, "adult", "child"))

しかし、実際の分析では、条件が3つ以上に分岐することが頻繁にあります。例えば、年齢を「child」(20歳未満)、「young_adult」(20歳以上40歳未満)、「adult」(40歳以上65歳未満)、「senior」(65歳以上)の4つのカテゴリーに分けたい場合、ifelse()を入れ子にして使うことになります。

mutate(age_group = ifelse(age < 20, "child", ifelse(age < 40, "young_adult", ifelse(age < 65, "adult", "senior"))))

このようにifelse()をネストさせると、括弧の対応が複雑になり、コードが非常に読みにくく、間違いやすくなります。

このような多分岐の条件分岐を、より安全かつ直感的に記述するためにdplyrが提供しているのがcase_when()関数です 17

case_when()は、複数の「条件 ~ 値」のペアを上から順に評価し、最初に真となった条件に対応する値を返します。先の年齢カテゴリーの例は、case_when()を使うと次のように劇的に分かりやすくなります 18

data %>% mutate(age_group = case_when(age < 20 ~ "child", age < 40 ~ "young_adult", age < 65 ~ "adult", age >= 65 ~ "senior"))

この書き方は、条件と結果の対応が一目瞭然であり、新しい条件の追加や修正も容易です。ifelse()からcase_when()への移行は、単に便利な関数を覚えるということ以上の意味を持ちます。それは、単に動くだけのコードから、自分自身や他人が将来容易に理解し、修正できる「メンテナンス性の高い」コードを書くという、より高度なプログラミングの考え方へのステップアップを意味します。case_when()は、tidyverseの設計思想である「単純なことは簡単に、複雑なことは可能に」を体現した関数であり、これを標準的な道具として使いこなすことが、データハンドリングのスキルを一段階引き上げる鍵となります。

グループ化と要約:データから情報を抽出する

Split-Apply-Combine戦略

これまでに学んだfilter()、mutate()、arrange()といった関数は、データフレーム全体に対して操作を行うものでした。しかし、データ分析で本当に知りたいことの多くは、「グループごと」の集計結果です。例えば、「治療群Aと治療群Bで、効果の平均値はそれぞれいくつか?」や「各年代における、疾患の有病率はいくつか?」といった問いに答えるためには、データをグループに分割し、それぞれのグループに対して計算を行い、最後に結果を一つにまとめる、という手順が必要になります。

この一連のプロセスは、「Split-Apply-Combine(分割-適用-結合)」戦略として知られています。これはデータ分析における非常に強力で普遍的なパターンです。まず、元の大きなデータセットを、分析したいカテゴリー(例えば、治療群、性別、年代など)に基づいて、複数の小さなサブセットに「分割(Split)」します。次に、分割された各サブセットに対して、平均値の計算や行数のカウントといった要約関数を「適用(Apply)」します。最後に、各サブセットから得られた結果を、一つの新しい、コンパクトな要約データフレームに「結合(Combine)」します。

この戦略により、元の生のデータが持つ複雑な構造の中から、意味のある知見を抽出することが可能になります。dplyrパッケージは、このSplit-Apply-Combine戦略を驚くほど簡単かつエレガントに実行するための二つの中心的な関数を提供しています。それが、データを分割するためのgroup_by()と、計算を適用し結果を結合するためのsummarise()です。次のセクションでは、これらの関数がどのように連携して、データから洞察を引き出すのかを詳しく見ていきます。

グループ化:group_by()

Split-Apply-Combine戦略の第一歩である「分割」を実行するのが、dplyrのgroup_by()関数です。この関数は、dplyrの中でも特に強力でありながら、その働きは少し独特です。group_by()をデータフレームに適用しても、見た目上、データフレームの中身は何も変わりません。しかし、水面下では、データフレームに「このデータはグループ化されています」という印が付けられ、その後のdplyr関数が、データ全体に対してではなく、グループごとに操作を行うように挙動を変えます 20

group_by()の使い方は非常にシンプルです。パイプでデータフレームを受け取った後、グループ化の基準としたい列(変数)の名前を指定します。例えば、dataというデータフレームをtreatment列の値(例えば"Drug A", "Drug B")ごとにグループ化するには、次のように記述します。

data_grouped <- data %>% group_by(treatment)

この操作の後、data_groupedオブジェクトは、外見上は元のdataと変わりませんが、内部的にはtreatment列のユニークな値ごとに分割された状態になっています。

グループ化の基準は、複数の変数を指定することも可能です。その場合、引数をカンマで区切って並べます。例えば、「治療群ごと、かつ性別ごと」にデータをグループ化したい場合は、次のようにします 20

data %>% group_by(treatment, sex)

これにより、データは「"Drug A"の男性」「"Drug A"の女性」「"Drug B"の男性」「"Drug B"の女性」といった、すべての組み合わせのグループに分割されます。

group_by()は、それ単体では目に見える変化を起こしませんが、後続のsummarise()やmutate()といった関数と組み合わせることで、その真価を発揮します。group_by()は、いわば分析の「レンズ」を変えるようなものです。それまではデータ全体をぼんやりと眺めていた状態から、特定のカテゴリーに焦点を合わせて、より詳細な分析を行うための準備を整える、非常に重要なステップです。

要約:summarise()

group_by()によってデータをグループに分割した後、各グループから意味のある情報を取り出す「適用」と「結合」のステップを実行するのがsummarise()(またはsummarize)関数です。summarise()は、グループ化されたデータフレームを受け取り、各グループを一つの行に要約した新しいデータフレームを作成します 20

summarise()の中では、新しい要約統計量の列名 = 計算式という形で、各グループに対してどのような計算を行うかを指定します。この計算には、様々な集計関数を使用することができます。最もよく使われるものには、平均値を計算するmean()、標準偏差を計算するsd()、中央値を計算するmedian()、最大値を計算するmax()、最小値を計算するmin()などがあります。また、各グループに含まれる行の数を数えるためには、n()という特別な関数が用意されています 20

例えば、treatment列でグループ化されたデータに対して、各治療群のresponse(治療効果)の平均値と、各群の患者数(サンプルサイズ)を計算するには、次のように記述します。

data %>% group_by(treatment) %>% summarise(mean_response = mean(response), n_patients = n())

このコードは、まずdataをtreatment列でグループ化し、次に各治療群に対してresponse列の平均値を計算してmean_responseという列に、そして各群の行数を数えてn_patientsという列に格納します。最終的に、treatment、mean_response、n_patientsの3つの列を持つ、治療群の数だけ行がある新しい要約データフレームが生成されます。

ここで非常に重要な実践的テクニックがあります。それは、集計対象の列に欠損値(NA)が含まれている場合の対処です。mean()やsd()といった多くの集計関数は、デフォルトでは計算対象に一つでもNAが含まれていると、結果としてNAを返してしまいます。これでは正しい集計ができません。これを避けるためには、各集計関数の中でna.rm = TRUEという引数を指定する必要があります。rmはremove(取り除く)を意味し、この引数は計算の前にNAを無視するように指示するものです 20

data %>% group_by(treatment) %>% summarise(mean_response = mean(response, na.rm = TRUE))

このna.rm = TRUEを忘れることは、初学者が陥りがちな典型的なエラーであり、常に意識しておくべき重要な習慣です。

最後に、summarise()を使った後は、ungroup()関数を使ってグループ化を解除することが推奨されます 20

group_by()で付けられた「グループ化の印」は、summarise()の後も一部残ることがあり、その後の意図しない操作で予期せぬ結果を生む可能性があるためです。%>% ungroup()を処理の最後に繋げることで、データフレームを通常の(グループ化されていない)状態に戻し、安全に次の分析ステップに進むことができます。

複数のデータを繋ぎ合わせる

結合の基本:Mutating Joins

実際のデータ分析プロジェクトでは、必要な情報がすべて一つのファイルにまとまっていることは稀です。多くの場合、患者の基本情報(デモグラフィックデータ)と、検査結果データ、あるいは投薬履歴データなどが、別々のファイルやデータベーステーブルとして存在します。これらの別々のデータを、一人の患者に対応する情報として一つにまとめる作業が必要になります。この役割を担うのが、「結合(Join)」と呼ばれる操作です。dplyrでは、このための強力で直感的な一連のjoin関数が提供されています。

データを結合する際には、両方のテーブルに共通して存在する「キー(key)」となる変数が必要になります。これは、通常、patient_idやsubject_idのような、各行(例えば、各患者)を一意に識別するためのIDです。dplyrのjoin関数は、このキー変数を手がかりにして、二つのテーブルの行を正しく対応させます。

dplyrが提供する結合操作のうち、新しい列を追加するタイプのものを「Mutating Joins」と呼びます。その中でも特に頻繁に使用されるのが、inner_join()、left_join()、full_join()の三つです 24

inner_join()は、最も厳格な結合方法です。これは、両方のテーブルにキーが存在する行だけを結果として残します 24。例えば、患者情報テーブルと検査結果テーブルをinner_joinすると、検査結果が存在する患者の情報だけが抽出されます。検査を受けていない患者の情報は、結果のテーブルから失われます。これは、両方の情報が揃っている完全なデータセットを作成したい場合に便利です。

left_join()は、おそらく実務で最もよく使われる結合方法です。これは、一つ目の(左側の)テーブルの行をすべて保持し、そこに二つ目の(右側の)テーブルからキーが一致する情報を付け加えます 24。もし左側のテーブルの行に対応するキーが右側のテーブルに存在しない場合、新しく追加される列にはNA(欠損値)が入力されます。例えば、患者情報テーブルを左側にして検査結果テーブルをleft_joinすると、すべての患者の情報が保持され、検査結果がある患者にはその値が、ない患者にはNAが結合されます。これにより、元の患者集団を失うことなく、情報を統合することができます。

full_join()は、両方のテーブルのすべての行を保持する結合方法です 24。どちらか一方のテーブルにしか存在しないキーの行も、結果に含まれます。キーが片方のテーブルにしか存在しない場合、もう一方のテーブルから来るはずだった列は

NAで埋められます。これは、二つのデータソースの情報を一切失いたくない場合に使用されます。

これらのjoin関数は、デフォルトでは両方のテーブルで同じ名前を持つ列をキーとして使用します。もしキーとなる列の名前が異なる場合(例えば、片方ではpatient_id、もう片方ではsubject_num)、by引数を使ってキーを明示的に指定する必要があります。by = c("patient_id" = "subject_num")のように記述することで、名前が異なる列同士を対応させることができます 24。これらの結合操作を使い分けることで、散在するデータを分析に適した一つの強力なデータセットへと統合することが可能になります。

差分を見つける:Filtering Joins

Mutating Joinsがテーブル同士を結合して情報を豊かにするのに対し、「Filtering Joins」は一方のテーブルを使って、もう一方のテーブルをフィルタリングする、つまり行を絞り込むために使われます。この中でも特にanti_join()は、データの不整合や欠損を調査するための強力な診断ツールとして非常に役立ちます。

anti_join()は、左側のテーブルにあって、右側のテーブルに「ない」行を抽出します 24。つまり、キーがマッチしなかった左側のテーブルの行だけを返します。結果として返される列は、左側のテーブルの列のみです。

これがどのような場面で役立つか、具体的な例で考えてみましょう。あなたが患者情報テーブル(patients)と、ある特定の検査を受けた患者の検査結果テーブル(lab_results)を持っているとします。ここで、どの患者がその検査を受けて「いない」のかを知りたいと考えました。このような場合にanti_join()が活躍します。

patients_without_lab <- patients %>% anti_join(lab_results, by = "patient_id")

このコードは、patientsテーブルの各patient_idをlab_resultsテーブルのpatient_idと照合します。そして、lab_resultsテーブルにpatient_idが見つからなかったpatientsテーブルの行、すなわち検査を受けていない患者のリストをpatients_without_labとして返します。

この機能は、データ品質のチェックに絶大な効果を発揮します。例えば、本来はすべての患者が受けているはずのベースライン調査のデータが、一部の患者で欠落している場合、anti_joinを使えば、その欠落している患者のリストを瞬時に特定できます。また、二つの部署から提供された顧客リストを比較し、一方にしか登録されていない顧客を抽出するといった、データの突合や差分検出の作業にも応用できます。

anti_joinは、データを結合して新しい変数を作るのではなく、データセット間の「関係性」に着目して行をフィルタリングする、という点で他のjoinとは一線を画します。分析を始める前に、データの完全性や整合性を確認する「データ監査」のステップにおいて、anti_joinは欠かすことのできない、探偵のような役割を果たしてくれます。

データ操作の発展レベル:効率化と応用

複数列への一括操作:across()

これまでのmutate()やsummarise()の例では、一度に一つの、あるいは数個の列に対して操作を行ってきました。しかし、実際のデータ分析では、数十個の数値変数すべてに対して同じ処理(例えば、単位変換や対数変換)を適用したい、といった場面が頻繁に発生します。このような場合に、各列に対して一つずつコードを書くのは非常に非効率で、ミスの原因にもなります。

この問題をエレガントに解決するのが、dplyr 1.0.0で導入されたacross()関数です。across()は、mutate()やsummarise()といった関数の中で使い、複数の列に対して同じ変換処理や要約計算を一度に適用するための、統一的で強力な構文を提供します 26。このacross()の登場により、かつて存在したmutate_at()、mutate_if()、mutate_all()といった、少しずつ役割の違う分かりにくい関数群は役目を終え、より直感的で一貫性のある方法に統一されました 26

across()の基本的な使い方は、第一引数で操作の対象としたい列を指定し、第二引数でそれらの列に適用したい関数を指定するというものです。列の指定には、select()で使ったようなヘルパー関数がそのまま利用できます。例えば、データフレーム内のすべての数値変数(numeric variables)に対して、その平均値を計算したい場合は、summarise()の中で次のように記述します。

data %>% summarise(across(where(is.numeric), mean, na.rm = TRUE))

where(is.numeric)の部分が「すべての数値列を選択する」という指示になり、across()は選択された各列に対してmean()関数を適用します。これにより、すべての数値列の平均値が一度に計算され、列ごとに結果がまとめられたデータフレームが返されます。

across()は、複数の関数を一度に適用することも可能です。その場合は、適用したい関数をリストとして渡します。例えば、すべての"score_"で始まる列に対して、平均値と標準偏差の両方を計算したい場合は、次のように書きます 26

data %>% summarise(across(starts_with("score_"), list(mean = mean, sd = sd), na.rm = TRUE))

このコードを実行すると、score_A_mean, score_A_sd, score_B_mean, score_B_sd... といった形で、各列と各関数の組み合わせに対応した新しい列が自動的に生成されます。この出力される列名を制御するために、.names引数を使うこともできます 26

across()の導入は、単なる便利機能の追加以上の意味を持ちます。それはdplyrの文法における大きな進化であり、ユーザーがコードを書く際の思考レベルを一段階引き上げるものです。個々の列名をハードコーディングするのではなく、「特定の性質を持つ列の集合」に対して操作を考えるという、より抽象的でスケーラブルなコーディングスタイルを可能にします。この考え方を身につけることは、再利用可能でメンテナンスしやすい、より高度な分析スクリプトを作成するための重要なステップとなります。

文字列操作:stringrパッケージ

データ分析で扱うデータは、数値だけではありません。患者のコメント、遺伝子名、住所、自由記述のアンケート回答など、テキストデータ、すなわち「文字列」を扱う場面も非常に多くあります。Rには標準で文字列を操作する関数が備わっていますが、tidyverseのエコシステムでは、より一貫性があり、直感的で、強力な文字列操作を実現するためにstringrパッケージが提供されています。

stringrパッケージの関数は、すべてstr_という接頭辞で始まっており、関数名からその機能が推測しやすいように設計されています。ここでは、特に使用頻度の高い基本的な関数をいくつか紹介します。

まず、特定のパターンが文字列に含まれているかどうかを検出するのがstr_detect()です。これは、真(TRUE)か偽(FALSE)の論理値を返します 30。例えば、

diagnosisという列に"cancer"という単語が含まれている行をfilter()で抽出したい場合、次のように組み合わせることができます。

data %>% filter(str_detect(diagnosis, "cancer"))

次に、文字列の中からパターンに一致する部分を「抽出」したい場合に使うのがstr_extract()です 31。例えば、"ID: 12345"のような文字列から、数字の部分だけを取り出したい、といった用途に使います。

そして、パターンに一致する部分を別の文字列に「置換」するのがstr_replace()です。str_replace()は最初に一致した部分だけを置換し、str_replace_all()は一致したすべての部分を置換します 31。例えば、データの入力ミスで"Male"と"M"が混在している場合に、"M"を"Male"に統一する、といったデータクリーニング作業に役立ちます。

これらのstringrの関数の真価は、「正規表現(regular expression)」と組み合わせることで発揮されます。正規表現は、文字列のパターンを記述するためのミニ言語のようなものです 33。例えば、.は任意の1文字を、^は文字列の始まりを、\dは任意の数字を表します 33。この正規表現をstr_detect()やstr_extract()のパターンとして使うことで、「3桁の数字で始まるID」や「末尾が".csv"で終わるファイル名」といった、非常に複雑な条件の文字列を柔軟に扱うことが可能になります。

stringrと正規表現の組み合わせは、一見すると複雑に感じるかもしれませんが、乱雑なテキストデータを構造化された情報へと変換するための、非常に強力な武器となります。

カテゴリカル変数(因子)の操作:forcatsパッケージ

データ分析において、性別、治療群、疾患の重症度といった、決まった数のカテゴリー(水準)しか取らない変数を扱うことは非常に多いです。Rでは、このようなカテゴリカル変数を効率的に扱うために、「因子(factor)」という特別なデータ型が用意されています。因子は、単なる文字列のベクトルとは異なり、そのカテゴリーの順序に関する情報も内部に保持しています。この順序は、特にモデリングや可視化において重要な意味を持ちます。

しかし、Rの標準機能だけで因子を操作するのは、時に直感的でなく、面倒な作業になることがあります。例えば、レベルの順序を並べ替えたり、レベルの名前を変更したりする作業です。この問題を解決するために、tidyverseファミリーにはforcats("for categorical variables"の略)という、因子を簡単かつ直感的に操作するための専門パッケージが含まれています 35

forcatsパッケージが提供する多くの便利な関数の中から、ここでは特に重要な二つ、fct_recode()とfct_reorder()を紹介します。

fct_recode()は、因子のレベルの名前を安全に変更(リコード)するための関数です 36。例えば、データ内で

"M"と"F"で記録されている性別のレベルを、より分かりやすい"Male"と"Female"に変更したい場合、fct_recode(sex_factor, "Male" = "M", "Female" = "F")のように記述します。これにより、元のレベルと新しいレベルの対応関係が明示的に示され、安全に名前を変更できます。

fct_reorder()は、可視化の質を劇的に向上させる非常に強力な関数です 38。これは、ある因子のレベルの順序を、別の数値変数の値に基づいて並べ替える機能を提供します。例えば、様々な国の平均寿命を棒グラフで表示する場合を考えてみましょう。デフォルトでは、国名はアルファベット順に並んでしまうため、どの国の寿命が長いのかを比較するのが困難です。ここで

fct_reorder()を使い、国の因子レベルを平均寿命の値で並べ替える(リオーダーする)と、棒グラフが平均寿命の長い順(または短い順)に美しく整列します。これにより、グラフから情報を読み取るのが格段に容易になります 39

ggplot(data, aes(x = fct_reorder(country, life_expectancy), y = life_expectancy)) + geom_col()

このように、forcatsパッケージは、カテゴリカルデータの前処理や、分析結果をより分かりやすく伝えるための可視化において、欠かすことのできないツールです。

分析ワークフローの実践

データ操作から可視化へ:dplyrとggplot2の連携

これまでに、dplyrを使ったデータの読み込み、整形、フィルタリング、要約、結合といった一連の操作を学んできました。これらの操作は、それぞれが強力ですが、その真価は、パイプ演算子%>%を使って一連の流れとして組み合わせ、最終的にggplot2による可視化に繋げることで最大限に発揮されます。tidyverseの設計思想の核には、この「データラングリングから可視化まで」のシームレスな連携があります 12

分析のプロセスを考えてみましょう。多くの場合、私たちは生のデータから出発し、それを集計・加工して、グラフで表現したい中間的なデータセットを作成します。この一連の作業を、パイプを使えば一つの連続したコードとして記述できます。

例えば、ある調査データsurveysがあり、そこから特定の種(species)に絞り込み、年(year)ごとに個体数を集計し、その推移を折れ線グラフで可視化したいとします。このワークフローは、次のように表現できます 41

surveys %>% filter(species == "Onychomys leucogaster") %>% group_by(year) %>% summarise(count = n()) %>% ggplot(aes(x = year, y = count)) + geom_line()

このコードの流れを左から右に読んでみましょう。まず、surveysデータフレームから始めます。次に(%>%)、speciesが特定の値である行をfilter()で抽出します。次に、その結果をyearでgroup_by()します。次に、各年についてsummarise()とn()を使って行数(個体数)を数え、countという新しい列を作成します。この時点で、年ごとの個体数を示した要約テーブルが出来上がります。そして最後に、この要約テーブルを直接ggplot()関数に渡し、aes()でx軸にyear、y軸にcountをマッピングし、geom_line()で折れ線グラフを描画します。

このように、中間的なデータフレームをいちいち変数に保存することなく、データ操作のパイプラインの最終結果を直接ggplot()に「パイプイン」できます 42。これにより、コードは簡潔になり、分析の論理的な流れが明確になります。もしグラフを描いた後で、フィルタリングの条件を変えたい、あるいは集計方法を変えたいと思った場合でも、パイプラインの一部を修正するだけで、すぐに結果のグラフを更新することができます。

このdplyrとggplot2の強力な連携こそが、tidyverseを用いた探索的データ分析のサイクルを高速化し、データとの対話をよりインタラクティブで創造的なものにしてくれます。

エラーに慣れちゃおう:よくあるエラーとデバッグ入門

Rでプログラミングを始めると、誰もが必ずエラーメッセージに遭遇します。赤い文字で表示されるエラーメッセージは、初学者にとっては脅威に感じられ、作業を中断させる壁のように思えるかもしれません。しかし、この考え方を改め、エラーメッセージを「Rがあなたに送ってくれる親切なフィードバック」と捉えることが、上達への近道です。エラーは失敗ではなく、コードの間違いを修正するためのヒントです。

Rやdplyrを使っていると、いくつかの典型的なエラーに頻繁に出会います。これらのパターンを知っておくだけで、多くの問題は迅速に解決できます。

例えば、"Error: could not find function..."というエラーは、最も一般的なものの一つです。これは、Rが指定された名前の関数を見つけられない、という意味です。原因は主に二つ考えられます。一つは、単純なタイプミスです。例えば、summariseをsummarizeと書くべきところをsumariseと間違えてしまうなどです。もう一つは、その関数が含まれるパッケージをlibrary()で読み込んでいない場合です 13

dplyrの関数を使おうとしてこのエラーが出たら、スクリプトの冒頭でlibrary(tidyverse)やlibrary(dplyr)を実行したかを確認しましょう。

次によくあるのが、"Error: object '...' not found"というエラーです。これは、指定した名前の変数(オブジェクト)が見つからない、という意味です。これも大抵はタイプミスが原因です。データフレーム名や列名を間違えていないか、大文字と小文字が正しく区別されているかを確認する必要があります 44

また、括弧の不一致も頻繁に起こる構文エラーです。(と)、{と}の数が合っていないと、Rはコードの構造を正しく解釈できず、"unexpected end of input"のようなエラーを返すことがあります 13

エラーに遭遇したときにパニックにならず、体系的に対処するための簡単なプロセスがあります 45。まず第一に、エラーメッセージをよく読み、そしてGoogleで検索してみることです。多くの場合、同じエラーで困っている人が世界中にいて、解決策が見つかります。次に、エラーを再現可能な最小限のコード(reproducible example)に単純化することです。問題が起きている部分だけを抜き出すことで、原因の特定が容易になります。そして、どこでエラーが発生しているのかを突き止め、仮説を立てて修正し、テストします。

このプロセスを繰り返すことで、デバッグ、つまりバグ(エラーの原因)を取り除くスキルは着実に向上します。エラーを恐れず、それを学びの機会と捉えることが、Rを使いこなす上で非常に重要な心構えです。

次のステップへ:大規模データとパフォーマンス

この記事では、tidyverse、特にdplyrを用いたデータハンドリングの基礎から応用までを学んできました。dplyrの文法は直感的で読みやすく、ほとんどのデータ分析タスクを効率的にこなすことができます。その可読性の高さは、チームでの共同作業や、将来の自分自身がコードを理解する上で、計り知れない価値を持ちます。

しかし、データ分析の世界は広く、時にはdplyrの標準的なアプローチだけでは不十分な場面も出てきます。その代表例が、数百万、数千万行といった非常に大規模なデータセットを扱う際の「パフォーマンス」の問題です。データが巨大になると、dplyrの処理、特にグループ化や集計に時間がかかり、分析のサイクルが遅くなってしまうことがあります 47

このようなパフォーマンスの壁に直面したときに、知っておくべきもう一つの強力なパッケージがdata.tableです。data.tableは、Rにおける高速なデータ操作を追求して開発されたパッケージであり、特に大規模データの集計、フィルタリング、結合といった操作において、dplyrよりも大幅に高速で、メモリ効率も良いことで知られています 47

data.tableはdplyrとは異なる、より簡潔で独特な構文DT[i, j, by]を持っています。この構文を習得するには新たな学習が必要ですが、パフォーマンスが最優先される状況では、その学習コストを払う価値は十分にあります。

ここで重要なのは、dplyrとdata.tableを「どちらが優れているか」という対立構造で捉えることではありません。むしろ、「どのような状況で、どちらのツールを選択するか」という、適材適所の考え方を持つことが大切です 50。分析プロジェクトの初期段階や、データサイズがそれほど大きくない場合は、可読性と生産性に優れるdplyrが最適な選択でしょう。しかし、処理速度がボトルネックとなり、分析の試行錯誤が滞るようになったとき、それはdata.tableの出番です。

この二つの世界の橋渡しをするパッケージとして、dtplyrも存在します。dtplyrは、使い慣れたdplyrの文法でコードを書きながら、その裏側(バックエンド)では高速なdata.tableのエンジンが動作するという、両方の利点を享受しようとする試みです 50

したがって、皆さんの学習の道筋としては、まずdplyrを完全にマスターすることをお勧めします。それがデータハンドリングの基本であり、ほとんどの場面であなたの要求を満たしてくれるでしょう。そして、将来、大規模データによるパフォーマンスの問題という具体的な壁にぶつかったときに、「data.tableという、この問題を解決するための専門ツールがある」ということを思い出してください。その時点でdata.tableを学ぶことで、あなたのデータサイエンティストとしてのツールボックスはさらに強力なものになるはずです。

おわりに

この記事を通じて、私たちはRを用いたデータハンドリングの基礎から応用まで、一連の旅をしてきました。まず、hereパッケージを使った再現性の高いプロジェクト管理から始まり、データ分析の堅牢な土台を築きました。次に、tidyverseの核となる概念である「整然データ」とは何かを学び、分析しやすいデータを理解しました。

そして、データハンドリングの中核をなすdplyrパッケージの強力な「動詞」たち、すなわち行を抽出するfilter()、列を選択するselect()、並べ替えを行うarrange()、そして新しい列を作成するmutate()の使い方をマスターしました。さらに、Split-Apply-Combine戦略を実現するgroup_by()とsummarise()を組み合わせることで、データから意味のある要約情報を抽出する方法を学びました。

また、join関数群を用いて複数のデータソースを一つに統合する方法や、across()、stringr、forcatsといったパッケージを使って、より複雑で現実的なデータクリーニングや加工を効率的に行うための発展的なテクニックにも触れました。最後に、これらの技術がどのようにしてggplot2による可視化へとシームレスに繋がるのか、そしてエラーへの対処法や、さらなるステップアップのためのパフォーマンスに関する知識も得ました。

データハンドリングは、時に地道で、華やかな分析手法の影に隠れがちな作業かもしれません。しかし、この工程こそが、信頼性の高い分析結果を生み出すための最も重要な基盤です。今回学んだtidyverseのツール群は、このデータハンドリングという対話のプロセスを、より直感的で、創造的で、そして楽しいものにしてくれます。

この教科書で得た知識とスキルは、あなたのデータ分析の旅における強力な羅針盤となるでしょう。しかし、最も大切なのは、実際にあなた自身のデータに向き合い、試行錯誤を繰り返すことです。練習を重ねることで、これらのツールはあなたの手足のように馴染み、データが語りかけてくる物語をより深く、より正確に聞き取ることができるようになるはずです。あなたのこれからの分析の旅が、実り多いものになることを心から願っています。

引用文献

  1. R言語のパッケージ集tidyverseとは?活用方法やインストール手順を紹介 - Udemy メディア, https://udemy.benesse.co.jp/data-science/data-analysis/tidyverse.html
  2. here, https://cran.r-project.org/web/packages/here/vignettes/here.html
  3. jennybc/here_here: I love the here package. Here's why. - GitHub, https://github.com/jennybc/here_here
  4. The here package, https://here.r-lib.org/
  5. Fix R File Path Errors Forever — Use the here() Package Like a Pro - YouTube, https://www.youtube.com/watch?v=14L--t_CzYs
  6. 17 整然データ構造 – 私たちのR - Jaehyun Song, https://www.jaysong.net/RBook/tidydata.html
  7. 統計_Tidyverseによるデータフレーム加工(01)tidyr - 須通り, http://www.sudori.info/stat/stat_tidyverse_01.html
  8. データの整然化, https://okumuralab.org/~okumura/python/tidy.html
  9. Rによるデータ解析のための前処理 - 2 データ整形および操作: tidyr, dplyrパッケージの基礎, https://uribo.github.io/dmr/ch2.html
  10. tidyr (データ生成) :: Jun Nishii, https://bcl.sci.yamaguchi-u.ac.jp/~jun/notebook/r/tidyverse/tidyr/
  11. 18 Pipes | R for Data Science, https://r4ds.had.co.nz/pipes.html
  12. Pipes and Ggplot2 in R - RPubs, https://www.rpubs.com/bwash318/466148
  13. Top 10 errors in R and how to fix them - Stats and R, https://statsandr.com/blog/top-10-errors-in-r/
  14. Lesson 5: dplyr and the pipe - Data Wrangling with R - Bioinformatics, https://bioinformatics.ccr.cancer.gov/docs/data-wrangle-with-r/Lesson5/
  15. dplyr Tutorial : Data Manipulation (50 Examples) - ListenData, https://www.listendata.com/2016/08/dplyr-tutorial.html
  16. 14 データハンドリング [要約] – 私たちのR, https://www.jaysong.net/RBook/datahandling2.html
  17. 【2-9】Rを使い連続変数や文字列のデータをカテゴリー変数に変更する様々な方法|MITTI - note, https://note.com/mitti1210/n/n326099eba68e
  18. 15 データハンドリング [拡張] – 私たちのR - Jaehyun Song, https://www.jaysong.net/RBook/datahandling3.html
  19. もっと早く知りたかった高速データフレーム処理~dplyrの使い方, https://www.medi-08-data-06.work/entry/dataframe_dplyr
  20. 【R前処理講座19】{dplyr} group_by:グルーピング【tidyverse】, https://datasciencemore.com/dplyr-group-by/
  21. dplyrを使いこなす!基礎編 #R - Qiita, https://qiita.com/matsuou1/items/e995da273e3108e2338e
  22. Rでデータを加工・集計する3つの操作を解説。 マーケターが1からRを勉強します【第5回】 - マナミナ, https://manamina.valuesccg.com/articles/804
  23. R入門 データフレームをグループごとに集計する方法 - トライフィールズ・ラボ, https://www.trifields.jp/dplyr-summarise-in-r-7975
  24. dplyrを使いこなす!JOIN編 #R - Qiita, https://qiita.com/matsuou1/items/b1bd9778610e3a586e71
  25. R入門 データフレームを内部結合(inner join)する方法 - トライフィールズ・ラボ, https://www.trifields.jp/dplyr-inner-join-in-r-7852
  26. Apply a function (or functions) across multiple columns - RDocumentation, https://www.rdocumentation.org/packages/dplyr/versions/1.0.10/topics/across
  27. Apply a function (or functions) across multiple columns - dplyr, https://dplyr.tidyverse.org/reference/across.html
  28. Apply a Function (or functions) across Multiple Columns using dplyr in R - GeeksforGeeks, https://www.geeksforgeeks.org/r-language/apply-a-function-or-functions-across-multiple-columns-using-dplyr-in-r/
  29. Why I love dplyr's across - Will Hipson, https://willhipson.netlify.app/post/dplyr_across/dplyr_across/
  30. Stringr and Regular Expressions Tutorial - Maloof Lab, https://malooflab.ucdavis.edu/apps/stringr-and-regular-expressions/
  31. Introduction to stringr, https://cran.r-project.org/web/packages/stringr/vignettes/stringr.html
  32. Extract the complete match — str_extract - stringr, https://stringr.tidyverse.org/reference/str_extract.html
  33. Regular expressions - stringr, https://stringr.tidyverse.org/articles/regular-expressions.html
  34. An Introduction to String Manipulation and Regular Expressions in R, https://burtmonroe.github.io/TextAsDataCourse/Tutorials/TADA-IntroToTextManipulation.html
  35. Tools for Working with Categorical Variables (Factors) • forcats, https://forcats.tidyverse.org/
  36. 8 Working with Factors in R (An Introduction to the forcats package) | DATA/STAT 234, https://myslu.stlawu.edu/~iramler/stat234/coursenotes/working-with-factors-in-r-an-introduction-to-the-forcats-package.html
  37. forcats - RPubs, https://www.rpubs.com/OCMath/DSCI300forcats
  38. Reorder factor levels by sorting along another variable — fct_reorder - forcats, https://forcats.tidyverse.org/reference/fct_reorder.html
  39. 16 Factors - R for Data Science (2e), https://r4ds.hadley.nz/factors.html
  40. Factors in R - The GRAPH Courses, https://thegraphcourses.org/courses/fdar/topics/factors-in-r/
  41. More dplyr and ggplot, tidying and exporting data - UofT Coders, https://uoftcoders.github.io/rcourse/lec05-dplyr.html
  42. Pipes, https://cran.r-project.org/web/packages/loon.ggplot/vignettes/pipes.html
  43. Applied Data Skills - Appendix F — Debugging - PsyTeachR, https://psyteachr.github.io/ads-v3/app-debugging.html
  44. A Beginner's Guide to Troubleshooting R Code - BTEP Coding Club - Bioinformatics, https://bioinformatics.ccr.cancer.gov/docs/btep-coding-club/CC2023/Troubleshooting_Rprog/
  45. 22 Debugging | Advanced R - Hadley Wickham, https://adv-r.hadley.nz/debugging.html
  46. Errors and Debugging in RStudio - R-bloggers, https://www.r-bloggers.com/2019/08/errors-and-debugging-in-rstudio/
  47. data.table vs dplyr: can one do something well the other can't or does poorly?, https://stackoverflow.com/questions/21435339/data-table-vs-dplyr-can-one-do-something-well-the-other-cant-or-does-poorly
  48. Fast data lookups in R: dplyr vs data.table - Appsilon, https://www.appsilon.com/post/fast-data-lookups-in-r-dplyr-vs-data-table
  49. Anybody use data.tables? Are they really faster than data.frames? : r/Rlanguage - Reddit, https://www.reddit.com/r/Rlanguage/comments/tyd80g/anybody_use_datatables_are_they_really_faster/
  50. data.table speed with dplyr syntax: Yes we can! | Towards Data Science, https://towardsdatascience.com/data-table-speed-with-dplyr-syntax-yes-we-can-51ef9aaed585/

-ビッグデータ

© 2025 RWE