エクセルシートやcsvファイルにまとめた数値データはエクセル上で関数を使うなどして前処理してしまうことが多いですが、エクセル上の操作は記録の残らないマウス操作に依存するため、再現性がまったくありません。再現性を確保するため、可能な限りR上で前処理を行うことを強くお勧めします。
以下の内容は基本操作のごく一部です。ほとんどすべての情報は、以下のサイトとその内容をまとめた書籍に掲載されていますので自習することができます。
以下のリンク先をよく読んで、ファイルの拡張子の表示をするようにしてください(ウイルス対策として必須の作業です)。Macを使用している人も同様です。
https://www.pc-koubou.jp/magazine/36291
[ステップ1] 自宅PCでこの実習用で使っているファイルを保存してるフォルダ内に、今週用のフォルダを半角英数字のみを用いて作成してください。たとえば”R_analysis_biwa2021” などの名前がいいでしょう(ダブルクォーテーション""自体はフォルダ名の一部ではありません。以下同様)。フォルダ名の中間にスペースを入れるのは厳禁です(たとえば、"R analysis biwa2021"はダメ)。Rでの実行でエラーが出ないように、ここで作成したフォルダの上の階層にあるフォルダではすべて半角英数字のみが名前に使われている必要があります。たとえば、ローカルディスク C: >ユーザ >自分のユーザ名ホームフォルダ(英数字) の直下に新しいフォルダを作るとよいでしょう。
[ステップ2] [ステップ1]で作ったフォルダに先週提出してもらったファイルを全部ダウンロードする(google driveに龍大IDでログインすること、過去のものも含めて7つあるあず)。
注意:一度に複数のファイルをダウンロードしようとするとgoogle driveの場合は圧縮されます。圧縮された複数のファイルの解凍や適切なフォルダへの移動等に自信がない方は一つ一つダウンロードすることを強くお勧めします。また、同じファイルを何度もダウンロードしようとするとファイル名の末尾に(1)等が勝手に追加されますが、追加された部分は削除して既にダウンロード済みのファイルを上書きします。
[ステップ2.1] ダウンロード先を指定する画面が出たら1)で作成したフォルダ内に保存する。ダウンロード先を訊かれなかったら「ダウンロード」フォルダにダウンロードされている可能性が一番高いので、ダウンロードフォルダから1)で作ったフォルダ内にファイル移動する。
[ステップ3] 自分のコンピュータ上のRStudioまたはRを使っている人は、以下の説明に従って作業をします。RStudio Cloudを使っている人はここを飛ばして3-B)に進むこと。
RStudio利用の場合
[3-A-RS-i] RStudio利用者は、Rstudioを起動し、ツールバーからFile > New File > R Script を順にたどることによって新規Rスクリプトを作成する。ここで作ったスクリプトを今日の最後まで使用し、課題の成果として提出する用のものとする。
[3-A-RS-ii] スクリプトの一行目に以下のコメントを書く。T*****の部分は学籍番号を追加する。
#For 20210802 phytoplankton diversity analysis T*****
[3-A-RS-iii] キーボードショットカットの「Ctrl + S (マックの場合はCommand+S)」を押してファイルを保存する。このとき必ず1)で作成したフォルダ内に保存する。ファイル名は"phyto_diversity_2021_t*****.R"とすること(t****の部分は学籍番号)。
この部分でつまづいた人は、以下の部分を一行残らずしっかり復習してから再挑戦すること。
スクリプトファイルにおける基本操作 (「ライブラリのインストールと読み込み」の直前までの部分)
R直接利用の場合
[3-A-RN-i] Rを直接利用する人は、Rを起動し、 ツールバーからファイル>新しいスクリプト、を順にたどることによって新規Rスクリプトを作成する。
[3-A-RN-ii] スクリプトの一行目に以下のコメントを書く。T*****の部分は学籍番号を追加する。
#For 20200715 phytoplankton diversity analysis T*****
[3-A-RN-iii] キーボードショットカットの「Ctrl + S (マックの場合はCommand+S)」を押してファイルを保存する。このとき必ず1)で作成したフォルダ内に保存する。ファイル名は"phyto_diversity_2020_t*****.R"とすること(t****の部分は学籍番号)。
[ステップ3] 自分のコンピュータ上のRStudioまたはRを使っている人は、ここは飛ばして4)に進みます。RStudio Cloudを使っている人はここの説明通りに作業をします。
[3-B-RC-i] RStudio Cloud(https://rstudio.cloud/ )にログインする。
[3-B-RC-ii] 下の画面キャプチャを参考に新規プロジェクトを作成する。New Projectが作成されるまで時間がかかるので辛抱強く待つましょう。
New Projectが作られた直後はプロジェクトに名前がついていないので、下図にあるように "Untitled Project" の部分をクリックして名前を付けましょう。たとえば、"phyto2021"などがいいでしょう。
[3-B-RC-iii] 上の画面で言うと、右下のFiles, Plots, Packages等のタブの直下の「Upload」のボタンをクリックして、2)で自分のPCに保存したすべてのファイルをアップロードします。アップロードがうまくいくとFilesのところに下のように(実際のファイル名は違う)表示されるはずです。
[3-B-RC-iv] はい、まだ終わりではありません。新規Rスクリプトを作成する必要があります。3-A)の「RStudio利用の場合」の[3-A-RS-i], [3-A-RS-ii], [3-A-RS-iii]と同じ作業をRStudio Cloud上でやってください。
[ステップ4.1]エクセルを開いて新しいファイルを作り、ダウンロードしたファイルの名前(=拡張子まですべて含める)をA列に1セルにひとつづつ縦にならべて書いていく。例としては下の図のような感じにする(実際の書き込み内容はこの図とは同じではありません)。
[ステップ4.2] [ステップ4.1]で作ったファイルをcsv形式(=「CSV(コンマ区切り)(*. csv)」形式)で"datafile_list.csv"として、[ステップ1]で作ったフォルダに保存する(「""」の部分はファイル名の一部ではありません)。
[5-i] データの取り込みにおいては、まず「作業ディレクトリ(Working Directory)」を適切に指定しないとデータをRの上に取り込むことができません。自分のコンピュータ上のRStudioまたはRStudio Cloudを利用している場合は、「超重要情報」のところに載っている方法で、作業ディレクトリを指定してください。R単体利用の人は、「R-tips」という解説サイトの「06. 作業ディレクトリの変更」に載っている方法で、作業ディレクトリを指定してください。作業ディレクトリ(フォルダ)は[ステップ1]で作ったフォルダを指定します。
[5-ii] それでは[ステップ2]で保存した全てのcsvファイルを、「リスト」という種類のオブジェクトに保存します。
やり方のアイデアは、読み込むべきファイル名の情報("datafile_list.csv"に保存されている)を、Rスクリプト上にデータフレームとして読み込み、そのファイル名情報に基づいて、csvファイルを一つ一つ読み込んでリストの一つ一つの要素に保存していく、という流れです。以下、この流れに従ってスクリプトを書いていきます(コンソールに書くのではなくスクリプトの編集画面に書いていきます:「コンソール」と「スクリプト編集画面」の違いが分からない人は、Rstudioの外見(GUI)の説明を再度確認しましょう)。
まず、datafile_list.csvの内容ををdatafile_listというデータフレームにread.csv()という関数を使って保存します。
datafile_list <- read.csv("datafile_list.csv", header=F) #load file list
[5-i]の説明をちゃんと読みましたか? それを読んで再度挑戦してください。
それでもだめなら、以下のトラブルシューティングを参考にしてミスの原因を探してください。
それでもうまくいかないときは質問してください。
さあ、読み込みがうまくいった場合、データフレームの1番目と2番目の要素に入っている情報は、以下のように確認できます。
datafile_list$V1[1] #check the content
datafile_list$V1[2] #check the content
ファイル名がコンソールに表示されるはずです。
次に、中身が空のリストを作って実際のデータが保存されているcsvファイルからの読み込みの準備をします。ここでは、raw_dataという名前のリストをつくることにしました。
####load each data###############
raw_data <- list() #prepare empty list
ここらへんで分からなくなる人が多いと思いますので、データフレームとリストについて少し解説します。datafile_listは、Rの中でデータを加工したり計算に使ったりするためにデータを保存しておくハコ(=「オブジェクト」と呼ばれます)で、データフレームという形式のものです(「データフレーム」オブジェクトの形式の一つです)。datafile_listというデータフレームの名前を使う(スクリプトに書き込む)ことによって、そのデータフレーム内のデータにアクセスできるようになります。それに対しdatafile_list.csvはPC上に保存されているファイルで、そのファイルの名前です。PC上からならどこからでもアクセスできるファイルと、Rのスクリプト上だけでアクセス可能なデータフレームを混同しないように注意してください。ファイルにアクセスするにはファイル名を指定する一方、R上のオブジェクトの一つのタイプであるデータフレームにアクセスにするにはデータフレームの名前を指定します。
データフレームは行名や列名を持ったデータを保存するのに適したオブジェクトです。それに対してリストは、複数のオブジェクト(たとえば複数のデータフレーム、データフレームとベクトル等)を集めてひとつのオブジェクトとして扱える仕組みです。複数の「ハコ」を集めたオブジェクトです。空のリストは、list()によって生成することができ、それぞれの「ハコ」には二重括弧[[ ]]の中に数字を入れた形でアクセス(オブジェクトのコピー、呼び出し)ができます。
上で作ったリストraw_dataの一番目の要素にデータを入れてみましょう。具体的にはdatafile_list$V1[1]に書き込まれているファイル名のファイルを指定して植物プランクトンの計数データを読み込んで保存してみます。
raw_data[[1]] <- read.csv(as.character(datafile_list$V1[1]), header=T) #test loading
ここで、read.csv()関数の最初の引数が、as.character(datafile_list$V1[1])となっているのはdatafile_list$V1[1]の中身を文字列形式で指定する必要があるためです。Rのバージョンによって、あるいはcsvファイルの保存の仕方によってはas.character()は不要で直接datafile_list$V1[1]を引数にしたらうまくいくかもしれません。コンソールのほうにraw_data[[1]] と書き込んでreturnキーを押せば、その中身が以下のようになっていることが確かめられるはずです。
> raw_data[[1]]
type species abundance
1 diatom Aulacoseira ambigua 2
2 diatom Aulacoseira granulata 10
3 cyano Anabaena affinis 5
4 mobile Ceratium hirundinella 5
5 green Staurastrum dorsientiferum var.ornatum 5
6 cyano Microcystis sp. 10
・・・中略・・・
さて、このようなデータ読み込みを一行一行スクリプトに書いていってもよいのですが、煩雑です。そこでforループという制御構造を使います。まずはこのループ構造の仕組みを学ぶために別ページの「繰り返し・ループ(for loop)」の部分を読んでそこに書かれた内容は、これまでの内容を書き込んでいる提出用の"phyto_diversity_2021_t*****.R"というスクリプトとは別にスクリプトを作って試してみましょう。forループは今日の最後の「多様性指標の計算」部分でも自分で考えてスクリプトを書く必要がありますので、今の時点で良く理解しておくことが不可欠です。「繰り返し・ループ(for loop)」にのっている例は必ず自分で実行して確かめましょう。
ではこのforループを使ってdatafile_list$V1に格納されているファイル名で指定されるファイルのデータをすべて読み込むには以下のようにします。
for(i in 1:length(datafile_list[,1])) {
print(i)
raw_data[[i]] <- read.csv(as.character(datafile_list$V1[i]), header=T)
}
length(datafile_list[,1])によって、datafile_listに格納されている数だけループを繰り返すことができます。代わりに具体的な数値を入れてもかまいません。
このとき、ループの途中で以下のような読み込みエラーが出るかもしれません。
[1] 1
[1] 2
[1] 3
[1] 4
make.names(col.names, unique = TRUE) でエラー:
'<ef>サ<bf>type' に不正なマルチバイト文字があります
土の番号でエラーが出るかは、その場合、i = 4のところでエラーが出ていることが分かるので、4番目のcsvを開きます。上のようなエラーの場合、ファイルがCSV形式ではなく、CSV UTF-8形式で保存されていることが多いです。エクセルでエラーの含まれているファイルを開いたのち「名前を付けて保存」を選んで、名前は変えずに、ファイル形式のみ「CSV(コンマ区切り)(*. csv)」を選択しなおして、ファイルを上書きしましょう。みなさん、指示通りやってもらったおかげで今回提出してもらったファイルではこのようなエラーはなかったです。そこでこのエラーは意図的にあとから追加しました。「どの形式で保存するか?」というのはどんな時でも非常に重要な指示ですので、「なんとなく、適当、だいたいでいいや」という感じでやらないようにしましょう。
ファイルの中身を変えた場合は、CSVファイルを読み込むところからRスクリプトを実行しなおす必要があります(どこだか分かりますか?)。
このループの結果はコンソールにraw_dataと打ち込めばリストのすべての要素が順に表示されるはずです。その中には、以下のようなエラーを意図的に追加していたデータがあります。
[[5]]
type species abundance X X.1
1 diatom Aulacoseira granulata 44 NA NA
2 cyano Anabaena macrospora 24 NA NA
3 cyano Lyngbya limnetica 17 NA NA
4 cyano Aulacoseira ambigua 7 NA NA
5 green Staurastrum dorsidentiferum var. ornatum 5 NA NA
6 cyano Anabaena spiroides var. crassa 3 NA NA
7 green Gonium pectorale 3 NA NA
8 green Micrasterias hardyi 1 NA NA
9 green Tetraedron gracile 1 NA NA
10 diatom Nitzschia sp 1 NA NA
11 green Pediastrum biwae 1 NA NA
12 diatom Fragilaria crotonensis 1 NA NA
13 NA NA NA
NAが勝手に挿入されています。これは、CSVファイルの外見上空欄であるセルのどこかに意図せずスペースが挿入されてる場合によく起きるエラーです。CSVファイルを開いて編集してエラーを取り除いてもよいですが、外見上空欄のセルからスペースの挿入を見つけるのは至難の業ですのでお勧めしません。R上で以下のように13行目と4列目・5列目を指定して削除し、上書きしましょう。13の前のマイナス記号(ー)は、削除の意味です。たとえば、4列目、5列目も仮に削除したい場合は-c(4,5)のように指定します。
#remove NA's column & row
raw_data[[5]] <- raw_data[[5]][-13,-c(4,5)]
データの中身(たとえばraw_data[[1]])をチェックしてみると、植物プランクトンのタイプ(green, diatomなど)と種名(species)と個体数(群体数)(abundance = 細胞数もしくは群体数)の一覧であることが分かります。
#########Data merge####################
View(raw_data[[1]]) #check the content as a dataframe
raw_data[[1]]$type #check the content of "type"
View()関数を使うとデータの中身がすべて見れる一方、リストの要素(エントリー)(データフレーム名に相当)の後に$マークを追加して列名を指定すると特定の列の情報だけが表示されます。RstudioのRエディターでは、raw_data[[1]]$まで書き込むとそれ以降の候補を自動表示してくれるので便利です。
あるいは、以下のようにすると各行(1行目)、各列(1列目)、特定の行-列(3行め、2列め)の値にそれぞれアクセスできます。
#access to sub-data
raw_data[[1]][1, ]
raw_data[[1]][, 1]
raw_data[[1]][3,2]
ここで以下のミスがありました(意図的に加えています)。
> raw_data[[1]]$type #check the content of "type"
[1] "diatim" "diatom" "cyano" "mobile" "green" "cyano" "cyano" "cyano" "green" "green" "green"
[12] "green"
最初の要素に単純なスペルミスがあります。以下のようにするとデータフレーム内の値を変更できます。
raw_data[[1]]$type[1] <- "diatom"
このようにエラーを修正することができます。
つぎのセクションではデータの結合を行いますが、その前の準備として列名(column name, colname)を変更します。以下の方法でチェックできます。
colnames(raw_data[[1]]) #check the column names
列名の3つめ"abundance"をデータ元のファイル名(学籍番号と紐づいています)で置き換えましょう。それによってデータを結合した後にデータの出所が分かるようになります。
colnames(raw_data[[1]])[3] <- as.character(datafile_list$V1[1]) #test change
上の作業はforループ構造で自動化できます。ここでタブ(\t)区切りの形式のファイルが混ざっている等、元のファイルにエラーがある場合はそのファイルからのデータの列名を変えるところでループにエラーが生じてループが途中で止まってしまいます。元のファイルのエラーをすべて取り除くか、エラーが出ないファイルだけでループを回しましょう。つまりループの終着ポイント(length(datafile_list[,1]))は臨機応変に変更する必要があります。
#change colnames
for(i in 1:length(datafile_list[,1])) {
colnames(raw_data[[i]])[3] <- as.character(datafile_list$V1[i])
}
このセクションは列名が変更出来たら終了です。
次に、リストraw_dataに格納されている提出された計数結果のデータを結合して1つのデータフレームにまとめたいと思います。これによって同じ日に取った湖水サンプルの異なる観測者による結果を一つのデータフレームにまとめることになり、その後にいろいろな解析をするための土台とすることができます。
[3-i] merge()という関数をつかって、列名の共通部分(species)を残しながら結合します。結合は二つのデータフレーム(リストの二つのエントリー)間でしかできないので、すべてのデータフレームを結合するにはループ構造による繰り返し演算が必要ですが、まずは最初の二つをマージしてみましょう。
#merge with removing type info
merged_data_2021 <- merge(raw_data[[1]][,c(-1)], raw_data[[2]][,c(-1)], all=T)
上のスクリプトの意味は、リストの最初の二つのエントリー(raw_data[[1]], raw_data[[2]])のうち、一列目(Type情報)を取り除いた([,c(-1)])うえでマージしてその結果を新たなデータフレームmerged_data_2021に( "<-"という記号を使って)格納するということになります。本当はType情報も込みでマージしたいのですが、種名は同じなのにType名が異なるというミスが多発していて今後の解析に支障をきたすので今回はType情報を削除します。
このマージという作業について、何がうれしいかというと、種のリストが観測者によってバラバラでも共通部分、非共通部分を整理して一つの表にしてくれるというところなんです。実際にmerged_data_2021の中身は、以下のような感じに統一されています。この例ではありませんが、種名のスペルミス等で本来同じ種が別の行に入っていることもあります。大文字で書くべきところが小文字になっていることもあります。今日の実習は、データの取り扱いを学ぶことが目的であり、出てきた多様性の数値自体が重要なわけではないので、そのような些細なミスについては修正せずに進めても構いませんが、気になる人は元の種名リストのcsvファイルを編集してスペルミスを除去するとよいでしょう。
> merged_data_2021
species y200533_20210726.csv y200556_20210628.csv
1 Anabaena affinis 5 NA
2 Ankistrodesmus falcatus 1 NA
3 Aphanocapsa sp. 2 NA
4 Aulacoseira ambigua 2 2
5 Aulacoseira granulata 10 NA
6 Aulacoseira granulate NA 3
7 Botryococcus braunii 1 NA
8 Ceratium hirundinella 5 NA
9 Ceratium sp NA 1
10 Coelosphaerium kuetzingianum 1 NA
・・・中略・・・
次のこのマージ作業を必要な数(エラーが出ないファイルの数だけ)だけ繰り返します。マージの結果は次々とmerged_data_2021 に上書きするようにしています。(もしもエラーが出る場合は)ループの回数(終了地点)は適宜変えてください。
#looping merge
for(i in 3:length(datafile_list[,1])) {
merged_data_2021 <- merge(merged_data_2021, raw_data[[i]][,c(-1)], all=T)
}
[3-ii] View()関数を使って新しいデータフレームの中身を確認みると、サンプル間で共通していないspeciesの部分には、欠損データ(NA)が挿入されていることが分かります。
View(merged_data_2021)
上で説明したことをもう少し詳しく解説します。ここまでのマージ作業ができて何がうれしいかというと、非常に簡単なスクリプトで、種のレパートリーの異なる集計表を統合できるということなのです。もっと具体的に言うと、同じサンプルでも観測する人によって集計リストの種のレパートリー(集計表のspeciesのところに出てくる種の一覧)は当然変わってきますし、もっと実際の研究に即した状況を考えると、複数のサンプルで計測すればサンプルごとに種のレパートリーは当然異なります。つまり、出現しない種については個体数ゼロとして記録されるわけではなく、出現しなかった種は種のレパートリーには含まれません。集計する前から「すべての」種が載った集計表を作ってそれに実際に出現した種の個体数(細胞数、群体数)を書き込んでいくのでない限り、種のレパートリーが異なる集計表をたとえばエクセル上で単純にコピペで統合することは容易ではありません。merge()関数を使うと、簡単に出現しなかった部分については欠損値(NA)を自動で挿入してくれるので、勝手に統一した種のレパートリー表が作れてしまうのです。
このようにmerge()関数は自動で集計表を整理してくれるわけですが、挿入されたNAをそのまま放置すると、NAは当然数字ではないので後々の統計解析の時のエラーの下になります。NAというのは、観測されなかった、すなわち個体数がゼロで会った部分に挿入されているわけですから、NAを全部ゼロに変えてしまえばいいわけです。
これらの作業をするには下のたった一行のスクリプトを実行すればいいだけなのですが、その内容を説明しましょう。is.na()という関数はインプットのオブジェクト(データフレームやベクトル等)の各要素がNAかどうかを判定して、NAなら真(TRUE)、NAでないなら偽(FALSE)を返す関数です。これをデータフレーム名[]の中に埋め込むと、データフレームの要素のうちTRUEの要素だけにアクセスすることができます。そして、そのアクセスされた要素にゼロを代入する(<- 0)という意味になっているため、データフレームの要素のうち値がNAだった要素がすべてゼロに置き換わります(上書きです)。
#convert all NA to zero
merged_data_2021[is.na(merged_data_2021)]<-0
最後に一連の作業がうまくいったか、merged_data_2021の中身をもう一度View()関数を使って確認してみましょう。NAがなくなっていれば成功です。
View(merged_data_2021)
3)までのデータの前処理を終えたところで、植物プランクトン群集の多様性解析に用いる「生データ(raw data)」が整理されました。 ここでは、もう1ステップ前処理を進めて、次の解析の準備をしていきます。
[4-i] 今後のデータ加工用に新しいデータフレームにデータをコピーする
<-を使って新しいデータフレームspecies_biwa_dataに格納しなおします(加工前のデータも残しておくためです)。うまくいったか、View()関数を使って確かめておきましょう。
############Data preprocessing##############
#copy to another dataframe
species_biwa_data <- merged_data_2021
View(species_biwa_data)
[4-ii] 行名を変えてデータを修正
種のリストのデータフレーム(species_biwa_data)が完成しました。これに少し修正を加えます。まず、データフレームの列の一部となっている種名のリストを行(row)の名前にコピーします。(ここでspecies_biwa_data$species内に重複があるとエラーが出ます)
#copy species name to row names
rownames(species_biwa_data) <- species_biwa_data$species
これにより種名をデータフレームの要素として維持する必要はなくなったので、種名が保存されている一列目は削除します。
#remove the redundant info
species_biwa_data <- species_biwa_data[,-1]
これをすると何がうれしいかというと、データフレームの要素自体がすべて数字になったので数字を扱う統計解析の時に無用なエラーを避けることができるところです。
[4-iii] 行と列を入れ替える
さらに、このデータフレームでは表の縦方向(行方向)に種が並んでおり、表の横方向(列方向)に異なるサンプルの計数結果が並んでいる形になっています。ここでは、今後の統計解析の準備として、この縦と横の並びを逆転させます。表の横と縦を並び替える作業は、線形代数の用語で転置(transpose)といい(日本語と英語でイニシャルがともにTなのは偶然です)、R上では簡単にt()という関数でできます。ついでに単に転置するとデータフレームでなくなってしまうのでas.data.frameという関数も同時に使います。これについては上書きします。View(species_biwa_data)の出力結果が以下の図のようになっていれば成功です(図の詳細は実際とは異なります)。
#transpose
species_biwa_data <- as.data.frame(t(species_biwa_data))
View(species_biwa_data)
ここでひと段落なのですが、上のようなデータをコピーしたり縦横を変えたりしていると、データの種類(数字numericか文字characterか要因factorか、など)が勝手に変わってしまうことがあります。一番注意しないといけないのは、見た目は数字のままなのにcharacterかfactorとしてRに認識されてしまう場合です。こうすると、数字に対して行う計算や統計などがうまくいきません。したがって、このようなエラーを防ぐためにclass関数を使ってデータの種類をチェックします。class(species_biwa_data[1,1])の結果がnumericでないと困ります。
#check class
class(species_biwa_data)
class(species_biwa_data[1,1])