R – ตรวจสอบ package ที่เราต้องการเรียกใช้งานในโปรแกรม ถ้า package นั้นยังไม่ได้ติดตั้งให้โปรแกรมติดตั้งใหม่เองได้เลยอัตโนมัติ

โดยปกติเมื่อเราจำเป็นต้องเรียกใช้ฟังก์ชันจาก package ใดๆ เมื่อเริ่มต้นเขียนโปรแกรม เราจำเป็นต้องระบุให้โปรแกรมของเราโหลด package เหล่านั้นเข้ามาใน environment ที่เราทำงานอยู่เสียก่อน ถ้าในโปรแกรมของเราจำเป็นต้องเรียกใช้ฟังก์ชันที่มาจากหลายๆ package เราก็จำเป็นต้องระบุชื่อ package เหล่านั้นทั้งหมดด้วย โดยปกติในส่วนหัวของไฟล์หรือตอนต้นของโปรแกรมจะทำการเรียกโหลด package แบบนี้

# ทำการเรียกฟังก์ชัน library เพื่อโหลด package "dplyr"
library(dplyr)

เหตุผลที่เราจำเป็นต้องระบุชื่อ package เองเช่นนี้ ก็เป็นเพราะมี package ต่างๆ ที่นักพัฒนาจากหลายๆกลุ่มได้พัฒนาโดยใช้ภาษา R ให้เรียกใช้งานเยอะมาก แต่ละ package ก็เหมาะสำหรับทำงานในแต่ละอย่างแตกต่างกันไป ถ้าจำเป็นต้องโหลด package เหล่านั้นทั้งหมดขึ้นมาให้เราอัตโนมัติทุกครั้งที่เราใช้งานโปรแกรมใดๆ ไม่ว่าจะเป็นโปรแกรมทำงานเล็กๆ หรือทำงานใหญ่ๆ มันก็จะทำให้เครื่องคอมพิวเตอร์ที่เราทำงานอยู่จำเป็นต้องใช้หน่วยความจำและทรัพยาการเยอะจากเครื่องคอมพิวเตอร์มากจนเกินไป บางทีทรัพยาการในเครื่องคอมพิวเตอร์ที่เราทำงานอาจจะไม่เหลือพอที่จะรันโปรแกรมของเราเองด้วย ดังนั้นแทนที่จะโหลด package ที่มีอยู่มาทั้งหมด ในการเขียนโปรแกรมภาษา R ก็ออกแบบให้คนเขียนโปรแกรมสามารถเลือกโหลดเฉพาะบาง package ที่จำเป็นต้องใช้งานในโปรแกรมของเราแบบระบุเอาเอง โปรแกรมที่เราออกแบบจะได้ใช้ทรัพยาการของเครื่องคอมพิวเตอร์ของเราในการโหลด package เข้ามาใน environment ที่เรากำลังทำงานแค่บางส่วนที่เราระบุว่าจะเรียกใช้งานเท่านั้น เป็นการถนอมทรัพยากรเช่น หน่วยความจำและตัวประมวลผล ให้เก็บไว้ใช้คำนวณหรือเก็บข้อมูลอื่นๆ ที่จำเป็นแทน

เมื่อเราได้ทำการระบุ package ที่จำเป็นสำหรับโปรแกรมของเราเรียบร้อยแล้วและลองรันโปรแกรมเพื่อใช้งาน ถ้า package ที่เราระบุได้รับการติดตั้งไว้ในเครื่องที่เรารันโปรแกรมอยู่แล้ว โปรแกรมก็จะโหลด package นั้นขึ้นมาใน environment ของเราให้เรียบร้อย และทำการดำเนินการทำคำสั่งต่อๆ ไปในโค้ดของเราได้ตามปกติ แต่ว่าในกรณีที่เราอาจจะเอา source code ไปรันเพื่อทดสอบผลในเครื่องคอมพิวเตอร์อื่นๆ หรือส่งไปให้สมาชิกคนอื่นในทีมลองทดสอบโปรแกรมดู หาเป็นเครื่องที่ยังไม่เคยได้รับการติดตั้ง package ที่เราระบุเอาไว้เลย โปรแกรมก็จะแสดงข้อผิดพลาดออกมา(throw exception) เพื่อแจ้งว่าในเครื่องคอมพิวเตอร์ดังกล่าวนั้นนั้นไม่มี package ที่เราจะเรียกใช้ และหยุดการทำงานของโปรแกรมทันที ไม่ทำคำสั่งต่อไปเลย รอให้เราไปติดตั้ง package ให้เรียบร้อย เมื่อเราติดตั้งเสร็จแล้วค่อยเรียกรันโปรแกรมดังกล่าวใหม่
จากเหตุผลด้านบน ก็เลยคิดขึ้นมาว่ามันคงจะดีกว่าไหม ถ้าเขียนโปรแกรมเพิ่มไปอีกสักหน่อยเพื่อที่จะให้โปรแกรมเราติดตรวจสอบและติดตั้ง package ให้เรียบร้อยเองไปเลย ไม่ต้องนั่งรอติดตั้ง package พออันนึงเสร็จแล้วค่อยรอรันคำสั่งเพื่อติดตั้งอันต่อไป พอติดตั้งเสร็จแล้วก็ต้องนั่งรอมารันโปรแกรมใหม่ ถ้าเขียนโปรแกรมให้ติดตั้งเสร็จภายในรอบเดียว แม้จะรอรันโปรแกรมนานหน่อยแต่ว่าเวลาส่วนนั้นอาจจะเอาไปสะสางงานอย่างอื่นได้ด้วย ก็เลยลองไปหาข้อมูลว่าพอจำแก้ปัญหานี้ได้ยังไงบ้าง

ปกติแล้วในส่วนของการโหลด package ขึ้นมาใช้งานนั้น นอกจากเราสามารถเรียกโหลด package ได้จากฟังก์ชัน library(“ชื่อแพคเกจ”) แล้ว ยังมีอีกฟังก์ชันที่สามารถโหลด package ขึ้นมาใน environment ที่เราทำงานได้เช่นกัน นั่นก็คือฟังก์ชัน require(“ชื่อแพคเกจ”) ทั้งสองฟังก์ชันนี้จะมีรายละเอียดการใช้งานต่างกันเล็กน้อย

  • สำหรับฟังก์ชัน library จะทำการลองโหลด package ที่ระบุขึ้นมา ถ้าแพคเกจนั้นยังไม่ได้รับการติดตั้งไว้ในเครื่องที่รันโปรแกรม โปรแกรมจะแสดงข้อผิดพลาด throw exception เพื่อแจ้งให้ทราบปัญหาและหยุดการทำงานของโปรแกรมทั้งหมดไปเลย
  • สำหรับฟังก์ชัน require จะทำการลองโหลด package ขึ้นมา ถ้าแพคเกจนั้นยังไม่ได้รับการติดตั้งไว้ในเครื่องที่รันโปรแกรม แทนที่โปรแกรมจะหยุดการทำงาน ฟังก์ชันนี้จะคืนค่า ค่า TRUE/FALSE เพื่อบอกว่ามีแพคเกจที่ระบุนั้นติดตั้งอยู่แล้วหรือไม่ ถ้ามีแล้วจะคืนค่าเป็น TRUE ถ้ายังไม่มีการติดตั้งเอาไว้จะคืนค่าเป็น FALSE และยังสามารถทำการรันโปรแกรมในบรรทัดต่อไปได้โดยไม่ออกจากโปรแกรม จึงมักจะใช้คู่กับคำสั่งเพื่อทดสอบเงื่อนไขเช่น if…else เพื่อทดสอบดูว่าฟังก์ชัน require นั้น คืนค่าค่าอะไรออกมา แล้วโปรแกรมที่ออกแบบจึงค่อยทำการจัดการกับผลในแต่ละกรณีว่าจะแก้ไขอย่างไร (ถึงแม้ว่าในกรณีที่ไม่ได้ทำการติดตั้ง package ไว้แล้วฟังก์ชันคืนค่ามาเป็น FALSE เราก็ไม่ควรเรียกใข้ฟังก์ขันของ package นั้นต่อไป เพราะมันอาจจะนำไปสู่ข้อผิดพลาดอื่นๆ ที่รุนแรงได้ แต่เราควรจะเขียนโปรแกรมเพื่อทดสอบผลและจัดการข้ามไปทำงานอย่างๆอื่นเลยที่ไม่เกี่ยวข้องกับ function ใดๆ จาก package นี้แทน)

ส่วนในกรณีที่ถ้าเราต้องการขียนโปรแกรมสักอันหนึ่ง และต้องการว่าถ้าเอาโปรแกรมนี้ไปรันในเครื่องอื่น ก็อยากให้โปรแกรมของเรารันจบในครั้งเดียว(รวมไปถึงการเช็ค package และ ติดตั้ง package ถ้ายังไม่มีให้ด้วย) เราก็ยังพอจะเขียนโปรแกรมช่วยตรวจสอบเพิ่มเข้าไปให้โปรแกรมเราได้โดยอาศัยความสามารถของฟังก์ชัน require(), library() ที่ระบุไว้ในข้างต้น โดยการออกแบบโค้ดในส่วนนี้ต้องการจะให้ช่วยตรวจสอบว่า packages ทั้งหมดที่ระบุ ได้มีการติดตั้งไว้ในเครื่องคอมพิวเตอร์นี้แล้วหรือไม่ ถ้ายังไม่ได้รับการติดตั้ง ให้ทำการติดตั้งทั้งหมดให้ก่อน แล้วจึงค่อยเริ่มในส่วนของการโหลด package เหล่านั้น แล้วค่อยประมวลผลโปรแกรมของเราในส่วนอื่นๆ ต่อไป
อันแรกถ้าเราต้องการติดตั้ง package แค่อันเดียว เราก็สามารถเขียนคำสั่งง่ายๆ ลงไปกำกับโค้ดของเราตรงต้นไฟล์ดังนี้

# ตรวจสอบว่าเครื่องของเราได้ทำการติดตั้ง package dplyr ไว้แล้วหรือไม่
if (!require("dplyr")){

    #ถ้ายังไม่ได้ติดตั้งให้ทำการติดตั้ง, เรียกคำสั่งสำหรับติดตั้ง package และระบุชื่อ package ที่ต้องการติดตั้ง
    install.packages("dplyr")

    #เมื่อติดตั้งเสร็จ ก็โหลด package นั้นขึ้นมาอยู่ใน environment ของเรา
    library(dplyr)
}

# แล้วค่อยรันโค้ดส่วนที่เหลือทั้งหมด

แต่ถ้าในกรณีที่เรามี package ที่จำเป็นต้องโหลดขึ้นมาใช้ค่อนข้างเยอะ เราก็จำเป็นต้องทำให้โปรแกรมของเราสามารถจัดการกับ package ได้สะดวกขึ้น โดยอาจจะใช้ vector เข้ามาช่วยเก็บข้อมูลชื่อของ package ที่เราต้องการทั้งหมด แล้วใช้ for…loop ในการวนเพื่อจัดการติดตั้ง package แต่ละอันดังนี้

# กำหนด vector ที่เก็บข้อมูล string ของชื่อ package ที่เราต้องการใช้โหลดในโปรแกรมของเราทั้งหมด
required_packages <- c("dplyr", "ggplot2")

# ใช้ for...loop สำหรับวนลูปเพื่ออ่านชื่อของ package ที่เราระบุไว้ใน vector ที่ละชื่อ เพื่อทำการใช้ชื่อ package เหล่านั้นในการโหลด ติดตั้งต่อไป
for(package_name in required_packages){

  # ใช้ if...statement ในการทดสอบดูว่า library ที่ต้องการจะโหลดขึ้นมาใช้นั้น ได้รับการติดตั้งไว้ในเครื่องแล้วหรือไม่
  if ( !require(package_name, character.only = TRUE)  ){

      # ทำการติดตั้ง package ที่ระบุ( เพราะ package นี้ยังไม่ได้รับการติดตั้งในเครื่องมาก่อน)
      install.packages(package_name, dependencies = TRUE)
    
      # หลังจากติดตั้ง package เสร็จแล้ว ก็โหลด package ที่ระบุในแต่ละรอบนั้นของมาใช้ใน session
      library(package_name, character.only = TRUE)
  }
}

# โค้ดส่วนอื่นๆ ของโปรแกรมของเรา ซึ่งจะรันต่อหลังจาก package ได้รับการติดตั้งเรียบร้อยแล้ว

#โหลดข้อมูลตัวอย่างของ dplyr ซึ่งเป็นข้อมูลเกี่ยวกับพายุ
data(storms)

#ใช้ฟังก์ชัน filter จาก dplyr package เพื่อจะเลือกกรองข้อมูลพายุเฉพาะในแถวที่มีข้อมูลเป็น "tropical depression" และ "tropical storm"
filter_rows <- filter( storms, status=="tropical depression" | status=="tropical storm" | status=="hurricane")

# ใช้ฟังก์ชัน select จาก dplyr package เพื่อจะทำการกรองข้อมูลเฉพาะข้อมูลในคอลัมน์ "name", "year", "lat", "long", "status"
filter_columns <-  select(filter_rows, all_of( c("name", "year", "lat", "long", "status")))

# ใช้ฟังก์ชัน group_by, summarize จาก dplyr package เพื่อทำการสรุปข้อมูลจำนวนครั้งที่เกิดพายุที่กำหนดให้เป็นชนิดของ "tropical depression", "tropical storm" และ "hurricane" ในแต่ละปี 
summarized_storm_occur_in_year <- filter_columns %>% 
                                group_by(year, status) %>% 
                                  summarize(occur_in_year=n(), .groups ="drop")

#ใช้ฟังก์ชัน ggplot จาก package ggplot2 เพื่อทำการแสดงข้อมูลเปรียบเทียบในรูปแบบแผนภูมิแท่ง
ggplot(summarized_storm_occur_in_year, aes(x=year, y=occur_in_year, fill=status)) + 
          geom_bar(position = "dodge", stat = "identity") + 
            labs(title="Storm data occur in each year", x="Year", y="Amount")

เมื่อทำการรันโค้ดขั้นตอนต่างๆ เสร็จแล้ว โปรแกรมก็จะเริ่มประมวลผลในส่วนของโค้ดที่เขียนขึ้นมาทั้งหมดต่อไป โดยโปรแกรมสร้างไว้จะทำการพลอตกราฟแผนภูมิแท่งออกมา

อาจจะเป็นวิธีที่เขียนแล้วโค้ดอาจจะไม่ค่อยสวยนัก แต่ยังไงก็เป็นวิธีหนึ่งที่สามารถใช้ช่วยแก้ปัญหาในการนั่งรอกดติดตั้ง package ไปที่ละอันๆ ได้ระดับนึ่ง เพราะสามารถจะสั่งรันโค้ดแค่รอบเดียวแล้วก็ไปนั่งรอหรือไปนั่งสะสางงานอย่างอื่นไปพลางๆ ได้เลย รอจนกว่าโปรแกรมจะเสร็จแล้วค่อยมาเช็คผลต่อ
หวังว่าวิธีการนี้จะช่วยแก้ปัญหาให้คนที่มีปัญหาเดียวกันได้บ้าง ไม่มากก็น้อยนะ