日付;2022/04/25(月)
Rによるデータ解析(その2)
ここでは、Rを使って、データセットを整形するための方法を述べる。基礎医学・生物学で利用するデータセットはそんなに大きくないし、複雑でもない。もし何かおかしなレコードがあれば、個別に対応することも可能である。したがって、自分はここに述べるような方法で十分に実験データやTCGAの解析ができていた。これでRを使ったデータ整形はだいたいイケるのではないかと思っている。自分は主にtidyverseのdplyrを使っている。その理由は圧倒的に簡単だからである。他のものを無理して使う必要もない。
注意点だが、以降に述べる各関数の前にライブラリ名が付いたり付かなかったりしているが、それは自分がよく使っているライブラリによりマスクされてしまい、時々エラーがでるためである。必要に応じて消したりつけたりする必要がある。
- 1 使うライブラリ(tidyverse)
- 2 コツ
- 3 データの型を設定する(as.numeric())
- 4 必要な列の選択(select())
- 5 特定の列の抽出(select(any_of())、select(all_of())
- 6 不要な列の削除(select(-one_of()))
- 7 列を分ける(separate())
- 8 2つのデータセットの結合(tibble型のデータ)(right_join(), left_join(),full_join(), inner_join())
- 9 2つのデータセットの結合(データフレームの場合)(cbind())
- 10 列の名前を変える(rename())
- 11 同一列内の重複を除く(distinct())
- 12 ある条件の行(データ)を抽出する(filter())
- 13 ある条件の行(データ)を抽出する([]に条件式を入れる)
- 14 2つの列を一つに結合する(unite())
- 15 新しい列を追加する(mutate())
- 16 ある条件のデータ(行)を抽出し、新しい名前の列をつける(mutate())
- 17 データフレームとtibble型のデータ(as.tibble()、data.frame())
使うライブラリ(tidyverse)
library(tidyverse)
コツ
色々とライブラリを読み込んでいると、単純な名前の関数名が他のライブラリの同じ関数名でマスクされることがあるので、もしそうなった場合はその関数の前にdplyr::などをつけて限定してやったら良い。
データの型を設定する(as.numeric())
特にこれはやらなくても良いかも知れないが、時々数字のデータであるべきものが文字列になっていたり、その逆になっていたりするので目的に合わせて行ったほうが良い。as.character()、as.integer()、as.logicalなんかも必要だったりする。
Original$Day_after_injection <- as.numeric(Original$Day_after_injection)
Original$Long <- as.numeric(Original$Long)
Original$Short <- as.numeric(Original$Short)
Original$Volume <- as.numeric(Original$Volume)
Original$Ratio_volume <- as.numeric(Original$Ratio_volume)
Original$Ratio_body_weight <- as.numeric(Original$Ratio_body_weight)
Original$Tumor_Weight <- as.numeric(Original$Tumor_Weight)
Original$Spleen_Weight <- as.numeric(Original$Spleen_Weight)
必要な列の選択(select())
以下は、OriginalというデータセットからGeneid, DMSO1, DMSO2, DMSO3, DMSO4, ON2, ON3, ON3, ON4, ON5という列を選んでNew_Datasetという新しいデータセットを作る、という意味である。
New_Dataset <- Original %>% dplyr::select("Geneid", "DMSO1", "DMSO2", "DMSO3", "DMSO4", "ON2", "ON3", "ON4", "ON5")
特定の列の抽出(select(any_of())、select(all_of())
あるデータセットのうち、特定の値を含む列を抽出する必要があるとする。例えば、列がサンプル名、行が遺伝子名のRNA-seqのデータであり、サンプル(列)が500個あったとする。こんなもの、手動で差サンプル名を書いていたら抽出するだけで10年かかってしまうし、できたとしてもあと10年かけて自分の記述が正しいのかチェックする羽目になる。
そんなときは以下が使用できる。clinical_infoというデータセットから、conditionという値がPDまたはCRのサンプルをfilter()で抽出し、そのサンプル名をrownames()で取ってくる。次に、originalのデータセットから取ってきたサンプル名に一致する列をselect(all_of())またはselect(any_of())で抽出するという意味である。
sample_you_need <- clinical_info %>% filter(condition == "PD"|condition == "CR") %>% rownames()
subset <- original %>% select(all_of(sample_you_need))
# or
subset <- original %>% select(any_of(sample_you_need))
all_of()とany_of()の違いは、originalのデータセットにsample_you_needに含まれる列名がなかったときにエラーで止めるか止めないかだったと思う。
不要な列の削除(select(-one_of()))
以下は、Originalというデータセットからid、gene_id、versionという列を削除して、新しくNew_datasetというデータセットを作るという意味である。
New_Dataset <- Original %>% dplyr::select(-one_of("id", "gene_id", "version"))
列を分ける(separate())
たまに、Gene IDのバージョンが邪魔だったりする。そんなときにこれが使える。以下はgene_idという列(に入っているデータ)を、” . “で切って、”id”と”version”という2つの列に分けるという意味である。
New_dataset <- Original %>% tidyr::separate("gene_id", sep = "\\.", remove = FALSE, into = c("id", "version"))
2つのデータセットの結合(tibble型のデータ)(right_join(), left_join(),full_join(), inner_join())
以下は2つのデータセットを結合するという意味である。なお、これはas.tibble()で作られた型のデータを扱うことができる。data.frame()で作られたデータは扱えないので、もしdata.frame()やc()で作られたようなデータをdplyrで扱うためには、まずはNew_datasetをas.tibble()によりtibble型にする。これは後ほど述べておく。
New_dataset <- tibble::as_tibble(New_dataset)
New_dataset <- right_join(Dataset1,Dataset2)
他にはleft_join()とかfull_join()とかを、必要に応じて使用すれば良い。2つのデータセットの共通因子を抽出する場合は、inner_join()が一番良いと思う。
2つのデータセットの結合(データフレームの場合)(cbind())
data.frame()で作られたデータの結合は以下のようにcbind()を用いる。DEseq2なんかはこっちを使う必要があったりする。説明の順序が逆になったが、こういうのが上述のdata.frame()で作られたデータである。
column <- c("DMSO1", "DMSO2", "DMSO3", "DMSO4", "ON2", "ON3", "ON4", "ON5")
condition <-c("control","control", "control", "control", "treated", "treated", "treated", "treated")
type <- c("paired-end", "paired-end", "paired-end", "paired-end", "paired-end", "paired-end", "paired-end", "paired-end")
coldata <- cbind(column, condition, type)
列の名前を変える(rename())
以下は、mnt/Output_STAR/DMSO1_RAligned.out.sorted.bamという冗談では済まない列名をDMSOに変えるという意味である。ときどき、STARを走らせた後にやってしまう。
New_dataset <- Original %>% dplyr::rename("DMSO" = "/mnt/Output_STAR/DMSO1_RAligned.out.sorted.bam")
同一列内の重複を除く(distinct())
同じ遺伝子名(ensemblなどでは、Gene IDやバージョンは違うが、遺伝子名が同じということが起こる。もちろん、カノニカルな方を選ぶ。)などを除くときに使用する。
New_dataset <- Original %>% distinct(Case_ID, .keep_all = TRUE)
ある条件の行(データ)を抽出する(filter())
データセットOriginalから、filter()内の条件に合うデータを抽出して、新しいデータセットNew_datasetを作るという意味。例えば、一番上のスクリプトは「Volumeという列の数字が0ではないヤツを抽出する」という意味。ANDは&、ORは|、==は等しい、!=は等しくない、である。
New_dataset <- Original %>% dplyr::filter(Volume != 0)
New_dataset <- Original %>% dplyr::filter(Drug != "NA")
New_dataset <- Original %>% dplyr::filter(Drug_ID != "DMSO_Extra_1" & Drug_ID != "DMSO_Extra_2")
New_dataset <- Original %>% dplyr::filter(padj < 0.05 & log2FoldChange > 0)
New_dataset <- Original %>% dplyr::filter(gene_name == "Gene1" | gene_name == "Gene2" |gene_name == "Gene3" | gene_name == "Gene4" | gene_name == "Gene5")
ある条件の行(データ)を抽出する([]に条件式を入れる)
汎用性はdplyr::filter()のほうが使いと思うのだが、行を抽出するためにはもう一つ方法がある。データフレームのアクセスにはoriginal[行x:行y,列x:列y]を使うが、それに条件を入れてしまう方法である。これは、たぶん、昔からある方法である。知らんけど。
もし、重要な点としては、データセットがマトリックスだった場合、これを使う必要があると思う。
以下は、originalのデータセットのgeneという列に入ってる値が、referenceというデータセットのref_geneという列に入っている値と同じであり、かつ、originalのFDRという列に入っている値が0.05下である値を抽出して、新しくNew_datasetを作る、という意味である。%in%は、match()と同じであり、言うてみればdplyr::inner_join()の低水準版というか、そこから結合の機能を取り払った演算子である。
New_dataset <- original[(original$gene %in% reference$ref_gene == TRUE)&(original$FDR < 0.05) == TRUE,]
これは、例えば以下のように、ある特定の値だけがほしいときなんかは有効である。originalというデータセットのFC(Fold Change)という列の値が最大値であるgeneという列の値をgene_with _maximum_FCという変数に入れるという意味である。
gene_with_maximum_FC <- original[original$FC == max(original$FC),]$gene
dyplr::inner_join()と違ってこれはデータフレームに直接アクセスする感じである。正直、これに慣れてしまったらdplyrがとても面倒な方法に思えてくる。
余談だが、これってよく見てみるとpandasのデータフレーム操作にすごく似ているので、pandasに慣れている人は自然にこっちを選んでしまうかもしれない。
2つの列を一つに結合する(unite())
実験の都合上、マウスの個別ID(これはメインキーというか、メインIDになる)に加えて、各薬剤投与群ごとの個別ID(行ってみればサブID)が必要になる場合がある。マウスの個別IDはほとんどの実験でつけてあるはず(メインID、メインキーなので)なので、その個別IDとそのマウスに投与した薬剤名を記載した列を結合することで、サブIDが出来上がる。その場合は以下のuniteが使える。
Analysis <- Analysis %>% tidyr::unite(Drug, Mouse_ID, col = "Drug_Mouse_ID", remove = "FALSE")
以下は、AnalysisというデータセットのDrugとMouse_IDという列を結合して、新しくDrug_Mouse_IDをという列を付けるという意味である。尚、この関数はデフォルトでセパレーターとしてアンダーバーがついている。また、デフォルトでremoveがTRUEになっているので、そのままではDrugとMouse_IDという元の列が削除されてしまう。そうならないために、remove = “FALSE”としたほうが良いように思う。
新しい列を追加する(mutate())
単純に列を追加したい場合、mutate()が使える。以下はOriginal_datasetというデータセットにNivolumabという文字列が入ったDrugという列と、NSGという文字列が入ったMouseという列を加えて、新しくNew_datasetというデータセットを作る、という意味。
New_dataset <- Original_dataset %>% mutate(Drug = "Nivolumab", Mouse = "NSG")
ある条件のデータ(行)を抽出し、新しい名前の列をつける(mutate())
以下はデータセットOriginalにあるDayという列が3かつConstractという列のVectorというヤツを抽出し、それらに0という値を持つOrder_graphという新しい列を作り、その結果出上がったデータセットをNew_datasetとする、という意味。
New_dataset <- mutate(
Original,
Order_graph =
case_when(
Day == 3 & Constract == "Vector" ~ 0,
Day == 3 & Constract == "M2" ~ 1,
Day == 7 & Constract == "Vector" ~ 2,
Day == 7 & Constract == "M2" ~ 3,
Day == 14 & Constract == "Vector" ~ 4,
Day == 14 & Constract == "M2" ~ 5))
類似の方法に以下のようにstr_detect()を使う方法がある。これはデータセットOriginalのTime_Drugという名前の変数(列)のデータにもし”DMSO”という文字が含まれていた場合に、DMSOという値を持つDrugという新しい変数(列)を作って、その結果できたデータセットをNew_datasetとする、という意味である。
New_dataset <- mutate(
Original,
Drug =
case_when(
str_detect(Time_Drug, "DMSO") == "TRUE" ~ "DMSO",
str_detect(Time_Drug, "0.125uM") == "TRUE" ~ "0.125uM",
str_detect(Time_Drug, "0.25uM") == "TRUE" ~ "0.25uM",
str_detect(Time_Drug, "0.5uM") == "TRUE" ~ "0.5uM"
))
データフレームとtibble型のデータ(as.tibble()、data.frame())
c()で読み込んでcbind()なんかで作ったデータフレームは、dplyrでは扱えないので、as.tibble()でtibble型のデータに変換しなくてはならない。そうすれば、select()やfilter()などを適用できる。
Dataframe1 <- c("DMSO", "DMSO","DMSO","DMSO","DMSO", "Drug","Drug","Drug","Drug","Drug")
Dataframe2 <- c(1,1,1,1,1,3,3,3,3,3)
Dataframe3 <- c("Succeed","Succeed","Succeed","Succeed","Fail","Succeed","Fail","Succeed","Succeed","Succeed")
New_dataset <- cbind(Dataframe1, Dataframe2, Dataframe3)
New_dataset <- as.tibble(New_dataset)
逆にdataframeが必要なら、作ったtibble型のNew_datasetをas.dataframe()に入れれば良い。そのとき、一列目が番号になってたりするので、要注意である。
New_dataframe <- as.dataframe(New_dataset)