使用purrr package學functional programming的觀念(五):一行同時讀取多個檔案,彙整成單一個data.frame且新增欄位

這邊嘗試要解決一個很棘手的問題,手上有一個下面這樣的資料清單,而每個資料夾下面有多個有固定編號的檔案。

screenshot.png

而每筆資料大概長的如下面這樣:

screenshot.png

而每個檔名是那筆資料的編號和資訊,最後希望可以把單個檔案讀取進來後,合併在一起,且根據每個檔案的檔名,新增4個欄位和其型態,最後理想上希望變成下面的樣子:

screenshot.png

根據這個問題的話,可以使用read_delim, pmap_chr, map, pmap, reduce這四個函數來使用,要完成這個小工作的話,能簡單可以分成幾個概念:
第一個是要彙整多個檔案路徑、第二個讀取多個檔案路徑的函數、第三個則是根據不同資料的檔名,來為其所讀取的data.frame新增欄位、第四個則是將所有放在list中的data.frame合併。

當概念解離清楚之後,便可以針對每一步挑選適用的函數來處理,比如
第一個
小步驟想要彙整多個檔案路徑,這步要準備的便是把所有路徑以list的方式來儲存,然後用paste0函數來將每個路徑合起來,使用pmap_chr來完成這件事。
pmap_chr函數可以用函數來處理list中的每個element,接者在使用map搭配read_delim來完成第二個小步驟,如下面這個代碼

#將所有的變數,使用list來儲存
list(as.list(rep(Pathway.path, pathway.number)),as.list(rep("/",pathway.number)),as.list(list.pathway.json)) %>%
#將這些變數導入到pmap_chr函數,因為pmap_chr是當list內的element為chr時所用的,這一部是為了把每個檔案的路徑組合起來
pmap_chr(paste0) %>%
#接者在使用map函數來針對上面處理完的一串路徑list,使用read_delim函數,分別讀取,並且在用list來吐出
map(read_delim,delim="\t")

第三個則是根據不同的資料檔名,來為其所讀取的data.frame新增欄位
此時我們已取得一個list,裡面的element都是一個檔案讀入的data.frame,而我們希望再把data.frame合併前,將每個data.frame使用其檔案名稱來增添其資料欄位,如下面的代碼:

#這邊的.代表從剛剛上面的代碼pipe進來的位置,後面三個則是我們希望增加的欄位,和每個欄位的名稱
list(.,pharmGKB_ID,pathwayName,Pharmacokinetics,Pharmacodynamics) %>%
#同樣的這邊可以使用pmap,此時不同使用pmap_chr,因為我們list中,一組是data.frame的格式
pmap(function(x,pharmGKB_ID,pathwayName,pharmacokinetics,pharmacodynamics){
                x %>%
mutate(`PharmGKB ID`=pharmGKB_ID,
       `PathwayName`=pathwayName,
        Pharmacokinetics=pharmacokinetics,
        Pharmacodynamics=pharmacodynamics )
                 })
#這邊比較值得一提的是pmap裡面可以使用函數作為參數,而這個函數可以直接在裡面定義,有點套用lambda的寫法,來做這件事情,這邊是為了把欄位的名稱確立

第四個則是將所有放在list中的data.frame合併,這邊使用reduce來解決這件事情,reduce可以將放入的list,把每個element用某個函數處理,一個接一個。

CleanPathway <-list(as.list(rep(Pathway.path, pathway.number)),                 as.list(rep("/", pathway.number)),as.list(list.pathway.json)) %>%
pmap_chr(paste0) %>%
map(read_delim,delim="\t") %>%
list(.,pharmGKB_ID,pathwayName,Pharmacokinetics,Pharmacodynamics) %>%
pmap(function(x,pharmGKB_ID,pathwayName,pharmacokinetics,pharmacodynamics){
                x %>% mutate(`PharmGKB ID`=pharmGKB_ID,
                             `PathwayName`=pathwayName,
                              Pharmacokinetics=pharmacokinetics,
                              Pharmacodynamics=pharmacodynamics )
                 }) %>%
                reduce(rbind)

這四個步驟便可以完成這件事情,這過程很重要的便是搞清楚map, pmap, reduce,他們要怎麼接受參數和處理,可以因此更清楚在R裡面list和data.frame的特性。不過在處理的過程也會使用到stringr的函數,來處理字串的問題。

閱讀參考:

How can I read in multiple files
Reading and combining many tidy data files into R

[閱讀筆記]從小工到專家 第二章 注重實效的途徑

原文:程序員修煉之道-從小工到專家

這時代很多領域都開始需要會寫程式來幫助其提高工作效率,已經不限於本科“計算機科學”的人了,而寫程式過了第一關基本語法的學習後,後多時候就是要培養好的思惟架構和技巧,如何讓自己在寫程式這件事情上事半功倍,絕對很重要。

這章提到如何提升編成效率的原則可以由下面的這句話總結:

“假如你做了,那麼你往後的效率會越來越好,因為…你沒有留給自己爛攤子,並且為自己的未來打造好的工具。”

兩個提升編成效率的要點分別是:

1. 不要重複 Don’t Repeat Yourself幫未來的自己打造好工具

2. 代碼的正交性(沒有給自己留爛攤子)

第一個提升自己編成效能的重點:不要重複
由不同脈絡下的重複行為來分類:

DRY:Don’t repeat yourself

a. 強加的重複 Imposed duplication

多多利用Snippet
常常我們在撰寫代碼或是分析時候,都會編著一些基本架構,像是日期、誰編的、分類等等,重複性的敘述,這邊往往可以藉由編寫簡單的過濾器、或是代碼生成器就可以解決。
           另外,編譯器都可以設定snippet等,第一手解決很多重複撰寫的問題。

文檔與代碼
          代碼的註解能精簡就精簡,不要註解很“簡單”的代碼。

b. 無意的重複 Inadvertent duplication

這邊指得是代碼撰寫時“設計”不良,所造成的重複,或是data model設計不好,造成後續引用或是修改時候會重複的緩存數據。
c. 無奈的重複 Impatient duplication

“欲速則不達時”我們就會把很多該參數化的代碼混過去,這樣造成後面無法簡單的去引用。
d. 開發者之間的重複 Interdeveloper duplication

在團隊合作開發時,要是沒有很好的策劃,容易重複開發“功能一樣”的模塊,這時候就會浪費時間。

第二個提升自己編成效能的要點:考慮代碼間的正交性

Eliminate effects between unrelated things

這點蠻好理解的,要撰寫的模塊之間彼此獨立,優點可以提高“往後”的生產效率,和降低開發風險,有一些小細節是可以注意的:

  1. 從一開始的設計就要抱持者layer by layer的概念
  2. 謹慎地挑選要引入的技術或是工具
  3. 讓代碼解離
  4. 避免全局數據的使用
  5. 模塊測試
  6. 文檔的撰寫(當你為代碼模塊撰寫文檔,要是這些文檔能輕易的單獨閱讀,當然代表這些代碼模塊之間是獨立的)

 

 

 

如何組織每次的分析專案檔案

每一次的資料分析,都會產生大量各式檔案,有原始資料、前處理過的、分析的程式碼,所以多花點心思在每個步驟都稍微整理回顧一下,長久來說會減少很多“災難”,讓自己能有reproducible research skill. (其實就算是wet實驗也都是如此,只是dry的分析,幾乎都在電腦上,所以好的習慣變得很重要)。

論壇上其實有不少人也有這樣的問題,故整理一些不錯的文章,雖然每一個人的做法些許不同,但重點是要建立自己一套流程。

screenshot.png

第一個重點是以project為單位來整理,不要用時間或是分散式的,所有跟某一次實驗或是分析相關的就用一組架構,架構裡最主要就分三類:資料、分析結果、分析程式碼,也是根據這三類來分,另外,可以用subproject來往下。而可以多多利用command line的技巧來減緩創建資料夾的麻煩(使用wild card),而在README文件要有良好的documentation,且可以用純文字撰寫,但可以用markdown的風格撰寫,可以在使用工具轉換成pdf、doc,使用像是pandoc的工具。

主要多花時間整理自己電腦裡的資料,整體分析的工作流程會進步更快,雖然一開始在資料量少的時候會比較煩!之後再分享用git來做版本控制!

R Shiny 快速使用R搭建app應用

Rstudio 開發的shiny基本架構

Shiny application是一款以R語言為框架,可以快速且方便搭健application,當幫忙使用R寫完清理或是視覺化資料後,最重要的是如何讓不懂R語言的人也可以享受,此時,用RStudio開發的Shiny框架便能快速有這效果,且其跟Rstudio整合得非常好,貼心宜人,即使非寫網頁應用程式出生的生物學家,只要略懂R語言,便能完成!

screenshot.png

shiny語法有非常詳細的解說,且搭配實例,只要到官方網頁就可以瀏覽,大概一兩個小時就可以了解他的架構,最棒的事其可以跟html / javascripts等等串接在一起,做出更多的效果!

做好的application可以直接使用Rstudio裡頭的快捷鍵發佈到shinyapp的網路平台,其提供後台完整的服務,付費的話可以獲得更佳的效能,但免費版已經可以玩得很開心了!

screenshot.png

 

點擊寫好的code,便能直接deploy到shinyapps的平台,一條龍服務!

screenshot.png

基本上,shiny的概念,就是直接用R code搭建網站的前端(ui.R)和資料處理的後端(server.R),server的code會處理由ui端或是使用者輸入的資料,處理後再丟回給ui!

古老的程式語言awk

程式語言不斷地隨者電腦科學的發展在演進,awk可以說是最早的scripting language,衍生自貝爾實驗室,在1977年出現,其為Perl(1987)和Python(1989)的前身,有一陣不太有人使用,但隨者有結構的資料大增,這種古老語言的處理速度,使其再度被使用。

就實用性來說,可以用其來取代cut,其在將資料分成field有非常大的彈性。

基本awk架構

awk ` pattern {action } `

  • awk處理邏輯是以行為單位的
  • 當pattern存在於line中,執行action
  • 將每行中的空白格當作是分隔
  • pattern的辨識以最大化為主

特殊變數special variables

在pattern或是action指令中有變數功能,如前述每個space中間即可被當作是一個單位的資訊

  • $0 整行
  • $1  第一個field(行中由空白格分隔裡,第一組文字)
  • $2  第二個field
  • NF 第幾個field
  • NR 當下的line數

指令operators

  • +-*/ 加減乘除
  • >< ==, !=比較
  • % 取mode
  • ~,!~ 有無match到

有用的awk教學資源