Try   HackMD

R 語言的撰寫技巧

tags: R Language

跟中文、英文作文一樣,我們在撰寫程式碼時,最重要的兩件原則是:

  • 自己或團隊成員乃至網友們能夠看懂程式碼
  • 專案管理方便

因此我們在寫程式時,第一步要確定程式碼能夠正確運行(無法正確運行就沒有下面的步驟),第二步就是確保程式碼的可讀性,也就是撰寫出的程式碼應該要符合上述兩個原則。不過每個人的寫作風格都不盡相同,因此在與團隊成員合作時應該要一同討論該專案的風格應是如何,否則會出現看不懂其他成員程式碼的情況。

程式碼內的重要元素:變數

在程式設計中,變數是指一個包含部分已知或未知數值或資訊(即一個值)的儲存位址,以及相對應之符號名稱(識別字)。通常使用變數名稱參照儲存值;將名稱和內容分開能讓被使用的名稱獨立於所表示的精確訊息之外。[1]白話來說,透過變數我們可以將值(你的物品)暫時放在電腦中的記憶體(置物櫃),方便日後需要使用時取出。以下我們來介紹在R中的變數使用規則與注意事項。

賦值與傳值

R中,如果我們想要將某個值賦予給某個變數,我們可以使用<-進行賦值(assign value),用=進行傳值(sending value)。肯定會有人問這兩者的差別,簡單來說,如果使用<-賦予變數一個值,其作用範圍是全域(global)的,代表在整個程式碼中我們都可以使用它;而如果使用=傳送變數一個值,其作用範圍則僅限於局部(local)的程式碼,例如僅能在迴圈中使用。

## assign value: global
x <- 10

## send value: local
x = 10

命名規則(naming convention)

一個程式一定有許多變數,而變數命名規則是很重要的。除了上述提及的易讀性之外,我們如此注重變數命名方式的另一個原因在於方便管理。以下是作者參考維基百科上命名規則基礎但不簡單: 變數命名規則整理出的幾項命名規則。舉一個簡單的例子,如果我們想要將10賦予給某一變數,則我們如果使用以下方式

aaa <- 10

不相信十天之後回來看這個變數能夠想起為何要這樣命名。因此我們可以藉由以下幾項命名規則進行變數的命名。

  • 駝峰式命名(camel case):首單字全部小寫,爾後單字首字母大寫,如userNamefileName
  • 蛇型命名(snake case):每個單字都小寫,但彼此之間透過下底線_分隔,如user_namefile_name
  • Screaming Case 命名:與蛇型命名相同,但每個字母都需要大寫,如USER_NAMEFILE_NAME。這個命名方式多半用在進行常數(constant) 的賦值,如重力加速度
    g=9.8 m/s2
    可用 gravity <- 9.8進行賦值。

除了上述這些命名規則之外,切記不要自己胡亂發明縮寫或簡寫,如fileName寫成fNamefileAddress寫成fAdr,這大概除了自己之外沒人看得懂。一些意義不明的變數命名也應該避免,如isCheck寫成isOK,沒人知道此處的 OK 是什麼。另外,我們更應該避免使用R原本既有的變數名稱或指令,如

## 糟糕的寫法
T <- TRUE ## T 在 R 中本來就有意義
F <- FALSE ## T 在 R 中本來就有意義

## 好的寫法
checkPass <- TRUE
checkNotPass <- FALSE

另一個能夠增加程式碼易讀性與管理的方式即是確定該變數的型別,假設我們想要替學生名單建立一個data.frame的型別,我們就可以用df_Student,或是建立一個可反轉的(invertible)矩陣,則可使用inv_matrix。最後,作者提供自己在寫作上的小習慣,如果今天我想要建立一個函式,那麼該函式我就會使用動詞進行命名,表示呼叫函式時我便是要執行該函式的內容,讀起來方便、用起來容易!

程式碼的外觀:架構

了解完如何對於變數進行命名與命名的規則之後,接著我們就要來針對程式碼的外觀進行說明。

註解(comment)

撰寫註解是一件很重要的事,這不僅是幫助自己能夠在數天或數個月之後回來看程式碼還能夠看得懂之外,更能夠在程式碼交接時降低溝通時間的成本。在R中撰寫註解的方式為在想要撰寫註解的文字前面或後面加上#,在#後的文字便不會執行。例如:

# Test 
x <- c(1,2,3,4,5) ## assign a sequence from 1 to 5
mean(x) ## find the mean of x

不過必須注意的是,註解不是寫作文,寫的落落長會佔據程式碼本體的寫作空間,且讀起來很不容易(因為有可能需要在編輯器內不斷地捲動頁面),最佳的註解應是透過簡單、明瞭地語言描述之。

空格(spacing)

如果在進行賦值時沒有加上空格,或是函數與函數之間緊鄰彼此,會發生什麼事呢?

## 黏在一起:很難閱讀
studentID<-c("B08302273","B09303384")
studentHeight<-c(183,175)

## 分開:好閱讀
studentID <- c("B08302273", "B09303384")
studentHeight <- c(183, 175)

你可能會想說:「有這麼誇張嗎?」沒關係,我們來看一個極端的例子:

teen<-original[original$age<30,]
names(teen)<-c("age","bike")
adult<-original[original$age>=30&original$age<65,]
names(adult)<-c("age","bike")
elder<-original[original$age>65,]
names(elder)<-c("age","bike")

上面這段程式碼的可讀性十分的低,因此應該盡量避免。

縮排(indent)

縮排的重要性猶如中文作文在每段的首行要空兩格,縮排發生的場景多半是在撰寫函式與撰寫流程控制的程式碼時,透過縮排能夠大幅提升可讀性。

findMean <- function(x){
  x <- as.integer(x)
  mean_x <- mean(x)
  return(mean_x)
}

  1. https://zh.wikipedia.org/zh-tw/变量_(程序设计) ↩︎