R

สำหรับคนทำงานสาย IT ช่วงหลายปีหลังมานี้น่าจะไม่มีใครไม่เคยได้ยินคำว่าข้อมูลขนาดใหญ่ (big data) แม้หลายคนจะคิดว่าคำดังกล่าวเป็นเพียงแค่คำแฟชั่นเท่ๆ (buzzword) เท่านั้น แต่ก็ปฏิเสธไม่ได้ว่าโลก IT ก้าวมาถึงขั้นที่ให้ความสำคัญกับการขุดหาความรู้ (data mining) จากข้อมูลที่มีอยู่กันซักพักแล้ว

ส่วนก้าวต่อไปในโลก IT คงหนีไม่พ้นเครื่องจักรที่เรียนรู้ได้ (machine learning) และปัญญาประดิษฐ์ (artificial intelligence) การจะเข้าใจในศาสตร์เหล่านี้ได้ แค่เขียนโปรแกรมเป็นอย่างเดียวนั้นไม่เพียงพออีกต่อไป แต่ยังต้องรู้จักและจัดการกับข้อมูลเป็นอีกด้วย

บทความนี้จะพาไปสัมผัสกับภาษา R ที่แม้จะมีรากฐานมาจากการใช้งานทางสถิติ แต่ภายหลังก็ปรับตัวมารองรับการคำนวณข้อมูลที่ซับซ้อนยิ่งขึ้น จนกลายเป็นหนึ่งในภาษาที่มาแรงไม่ควรมองข้าม

ประวัติโดยย่อ

R เป็นภาษาแบบเปิดซอร์ซที่ได้รับแรงบันดาลใจมาจากภาษา S โดยมีจุดประสงค์สำหรับการคำนวณและนำเสนอกราฟิกทางสถิติ มันถูกสร้างและเผยแพร่เป็นครั้งแรกในปี 1993 โดย Ross Ihaka และ Robert Gentleman ปัจจุบันตัวภาษาเดินทางมาถึงรุ่นที่ 3.4 แล้ว

ด้วยความเฉพาะทางของมัน R จึงแตกต่างจากภาษาโปรแกรมสำหรับงานทั่วไป (general-purpose programming language) อย่างเช่น C, Python ถึงกระนั้น การจะเรียนรู้ R ก็ไม่จำเป็นต้องทิ้งความรู้จากภาษาอื่นๆ ไปเสียทั้งหมด เพียงแค่ให้ระวังความแตกต่างอันเป็นเอกลักษณ์จากภาษาใหม่นี้ก็พอแล้ว

ซึ่งเอกลักษณ์สำคัญอย่างหนึ่งของภาษา R ก็คือการเป็นภาษาโปรแกรมเชิงอาเรย์ (array language) ที่เน้นการคำนวณข้อมูลพร้อมกันเป็นกลุ่ม แนวคิดนี้อาจฟังดูแปลกและไกลตัว แต่อันที่จริงแล้วมันอาจเป็นเรื่องใกล้ตัวที่หลายคนเคยผ่านหูผ่านตาจนชินด้วยซ้ำ นั่นก็คือ การคำนวณเซลล์หลายเซลล์ด้วยสูตรเดียวกันบนโปรแกรม Excel นั่นเอง

เริ่มต้นใช้งานผ่าน REPL

สำหรับใครที่คุ้นเคยแต่กับการเขียนภาษาที่ต้องคอมไพล์ก่อน เช่น C, Java จะพบว่าการทดลองคำนวณเล็กน้อยๆ ก่อนการเขียนโปรแกรมจริงนั้นเป็นเรื่องที่ยุ่งยากพอสมควร ในภาษาแบบสคริปต์หลายๆ ภาษาจึงมักมีเครื่องมือคำนวณแบบโต้ตอบที่เรียกว่า REPL (read-eval-print loop) แถมมาให้ โดยเครื่องมือนี้มีหลักการทำงานง่ายๆ 3 ขั้นตอนตามชื่อของมัน คือ อ่านคำสั่ง คำนวณค่าตามคำสั่งนั้นๆ แล้วแสดงผลลัพธ์กลับมาให้ผู้ใช้งานเห็นทันที ก่อนจะวนกลับไปรออ่านคำสั่งถัดไปซ้ำเรื่อยๆ นั่นเอง

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

เราสามารถทดลองใช้ REPL ของภาษา R ได้ผ่านเว็บ R-Fiddle หรือ Jupyter ได้ทันที หรือถ้าใครติดตั้งโปรแกรมไว้ในเครื่องแล้ว ก็เพียงแค่เปิดโปรแกรม terminal/cmd ขึ้นมา พิมพ์ R (ใช้ตัวอักษรตัวใหญ่ ต่างจากคำสั่งโดยทั่วไปที่มักใช้ตัวเล็กทั้งหมด) แล้วกดปุ่ม <Enter>

เมื่อเข้ามาแล้วเราจะพบกับข้อความต้อนรับที่บอกรายละเอียดว่ากำลังใช้โปรแกรมเวอร์ชันใด พร้อมทั้งแสดงคำสั่งพื้นฐานสำหรับช่วยเหลืออีกเล็กน้อย เลื่อนลงมาดูที่ด้านล่างสุดของหน้าจอ จะพบกับเครื่องหมาย > ที่ตามด้วยเคอร์เซอร์กะพริบรอรับคำสั่งที่เราพิมพ์เข้าไป เราอาจทดลองคำนวณการบวกเลขง่ายๆ เช่น 1+1 ได้ดังนี้

> 1+1
[1] 2

สังเกตว่าที่ด้านหน้าของผลลัพธ์ (เลข 2) จะมีตัวเลขในวงเล็บปีกแข็ง ([1]) แสดงอยู่ นี่เป็นตัวเลขที่จะแสดงเฉพาะในโหมด REPL เท่านั้น มันมีไว้เพื่อช่วยให้เรานับได้อย่างสะดวกว่า ค่าผลลัพธ์ที่เห็นเป็นตัวแรกในแถวนี้เป็นผลลัพธ์ตัวที่เท่าไรจากผลลัพธ์ทั้งหมด

เราอาจทดลองคำนวณค่าอื่นๆ ด้วยตัวดำเนินการพื้นฐานทางคณิตศาสตร์ที่เราคุ้นเคยในภาษาทั่วไป อันได้แก่ บวก (+) ลบ (-) คูณ (*) หาร (/) หรือบางตัวก็แปลกกว่าภาษาอื่นบ้าง เช่น ยกกำลัง (^) หารเอาเศษ (%%) และหารปัดเศษทิ้ง (%/%) สังเกตว่า R จะมองว่าตัวเลขต่างๆ เป็นตัวเลขแบบจุดทศนิยมลอยตัว (floating point) โดยปริยาย ดังนั้นการคำนวณตัวเลขแปลกๆ มักจะไม่ส่งผลให้โปรแกรมต้องหยุดทำงานเนื่องจากมีข้อผิดพลาดเกิดขึ้น เช่น

> 1/0
[1] Inf

แต่นั่นก็ไม่ได้หมายความภาษา R จะเป็นภาษาที่เขียนโปรแกรมได้โดยไม่มีข้อผิดพลาดแต่อย่างใด เช่น ข้อผิดพลาดนี้ที่เกิดจากการพิมพ์คำสั่งผิด (syntax error)

> (1+)*3
Error: unexpected ')' in "(1+)"

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

ส่วนในการทำงานจริง เราอาจลืมไปว่าฟังก์ชันที่ต้องการใช้นั้นเรียกใช้งานอย่างไร หรือประเภทข้อมูลที่ใช้มีสมบัติใดบ้าง เราสามารถเรียกเอกสารขึ้นมาอ่านได้ทันทีผ่านฟังก์ชัน help() (หรือจะใช้ทางลัดเป็นเครื่องหมาย ? เพียงตัวเดียวนำหน้าหัวข้อที่ต้องการก็ได้)

help()           # หน้าแรกเอกสาร
help("+")        # เอกสารเกี่ยวกับการดำเนินการตัวเลขพื้นฐาน
help(numeric)    # เอกสารเกี่ยวกับข้อมูลประเภทตัวเลข

เมื่อต้องการออกจาก REPL สามารถพิมพ์ฟังก์ชัน q() จากที่ได้เกริ่นไปข้างต้นว่าการใช้งานโปรแกรม REPL นี้เปรียบได้ดั่งกระดาษทด โปรแกรมจะถามว่าเราต้องการเก็บบันทึกตัวแปรและคำสั่งต่างๆ บนกระดาษทดครั้งนี้ไว้เผื่อใช้ซ้ำในครั้งถัดไปหรือไม่ หากตอบว่าใช่ (y) ทุกครั้งนับจากนี้ที่เปิดโปรแกรม REPL จากตำแหน่งแฟ้มเดิมขึ้นมา เราจะสามารถเรียกใช้ตัวแปรที่เคยสร้างและย้อนดูคำสั่งที่เคยเรียกจากครั้งนี้ได้เสมอ

ตัวแปรและประเภทข้อมูล

แม้ภาษา R จะรับแนวคิดการเขียนโปรแกรมเชิงวัตถุ (object-oriented programming) ที่ทำให้เราสามารถดัดแปลงและสร้างประเภทข้อมูลชนิดใหม่ๆ ขึ้นมาได้ แต่โดยส่วนใหญ่เราจะวนเวียนอยู่กับข้อมูลพื้นฐานเพียงไม่กี่ประเภทเท่านั้น

การทดสอบว่าข้อมูลดังกล่าวถูกจัดอยู่ในประเภทใด สามารถใช้ฟังก์ชัน class() เพื่อตรวจสอบประเภทของข้อมูลนั้นได้ เช่น

> class("hello")
[1] "character"

แต่ก่อนที่เราจะไปดูว่าภาษา R มีประเภทข้อมูลที่น่าสนใจใดบ้าง จะขอกล่าวถึงเรื่องพื้นฐานที่น่าสนใจไม่แพ้กันอย่างการประกาศตัวแปรเสียก่อน

ประกาศตัวแปร

การประกาศตัวแปรในภาษา R จะใช้สัญลักษณ์ที่แตกต่างจากภาษาโปรแกรมโดยทั่วไป แต่ดูคุ้นเคยเมื่อเขียนเป็นสมการคณิตศาสตร์ ซึ่งก็คือสัญลักษณ์ลูกศรซ้าย (<-) นั่นเอง ดังเช่นตัวอย่างการประกาศตัวแปรเหล่านี้

> x <- 42
> y <- "We \u2764 R-lang"

อย่างไรก็ตาม R ยังยอมให้ใช้สัญลักษณ์เท่ากับ (=) เพื่อประกาศตัวแปรได้เช่นกัน (แม้หลายที่เช่น Google จะไม่แนะนำวิธีนี้) ความแตกต่างคือสัญลักษณ์เท่ากับถูกออกแบบมาเพื่อใช้ประกาศพารามิเตอร์/อาร์กิวเมนต์ของฟังก์ชันเป็นหลัก การใช้สัญลักษณ์ลูกศรซ้ายเพื่อประกาศพารามิเตอร์/อาร์กิวเมนต์ฟังก์ชันอาจทำให้โปรแกรมทำงานผิดพลาดได้

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

เราสามารถขอดูตัวแปรทั้งหมดที่เราสร้างขึ้นมาได้ผ่านฟังก์ชัน ls() และทำลายตัวแปร ได้ผ่านฟังก์ชัน rm()

ประเภทข้อมูลเดี่ยว

ข้อมูลเดี่ยวคือข้อมูลขนาดเล็กที่สุดที่ไม่สามารถแบ่งย่อยลงไปได้อีก และไม่สามารถนำไปใช้คำนวณทางสถิติได้

ข้อมูลตัวเลข

เนื่องจาก R เป็นภาษาที่เน้นการนำไปใช้งานทางสถิติเป็นหลัก การเก็บตัวเลขแบบจุดทศนิยมลอยตัว (ในภาษา R เรียกข้อมูลชนิดนี้ว่า numeric) จึงเป็นท่ามาตรฐานที่ R เลือกใช้ เพราะนำไปคำนวณต่อได้ง่าย อย่างไรก็ตาม R ยังมีข้อมูลตัวเลขอีกสองประเภทให้เลือกใช้เพิ่มเติมตามความเหมาะสมเช่นกัน ซึ่งก็คือ

  1. จำนวนเต็ม (integer) สร้างได้โดยเขียนห้อยตัว L ไว้ข้างหลังตัวเลข เช่น 100L จำนวนเต็มมีไว้สำหรับใช้ในงานที่ต้องการให้แน่ใจว่าการคำนวณต่างๆ เป็นแบบวิยุตคณิต (discrete mathematics) หรือใช้เพื่อบ่งบอกจำนวนการวนซ้ำ
  2. จำนวนเชิงซ้อน (complex) สร้างได้โดยเขียนห้อยตัว i ไว้ข้างหลังตัวเลข เช่น 1i, 3+4i จำนวนเชิงซ้อนมีไว้สำหรับงานทางด้านวิทยาศาสตร์-วิศวกรรมบางแขนง เช่น การคำนวณด้านแม่เหล็กไฟฟ้า พลศาสตร์ของไหล

ลำดับของตัวเลขในภาษา R เรียงจากต่ำไปสูงได้แก่ จำนวนเต็ม จำนวนทศนิยม และจำนวนเชิงซ้อน หากมีการใช้งานตัวเลขคละประเภทกัน R จะแปลงตัวเลขที่อยู่ในชั้นต่ำกว่าขึ้นไปเป็นชั้นที่สูงกว่าเสมอ

ข้อมูลตัวอักษร

ภาษา R ไม่แบ่งแย่งข้อมูลตัวอักษรเป็นหลายระดับ (แบบภาษา C) แต่จะมองว่าตัวอักษรชุดหนึ่งไม่ว่าจะยาวเท่าใดคือหนึ่งข้อความเสมอ (แบบภาษา Python) และเรียกข้อมูลชนิดนี้ว่า character การประกาศข้อความสามารถใช้ได้ทั้งอัญประกาศเดี่ยว (') หรืออัญประกาศคู่ (") ล้อมรอบข้อความที่ต้องการโดยไม่มีความแตกต่างกันแต่อย่างใด

ข้อมูลตรรกะ

การแสดงข้อมูลตรรกะ (logical) ว่าถูกหรือผิด จะใช้คำว่า TRUE กับ FALSE ตามลำดับ ไม่สามารถใช้ตัวเลขทดแทนได้ อย่างไรก็ตาม หากต้องการประหยัดเวลาพิมพ์ในส่วนนี้ ก็สามารถป้อนแค่ตัวอักษรตัวแรก (T,F) เข้าไปได้เช่นกัน

R ยังมีข้อมูลตรรกะแบบพิเศษอีกตัวหนึ่งเพิ่มเข้ามา คือ ข้อมูลว่าง (NA) ซึ่งจะเกิดขึ้นเมื่อพยายามเข้าถึงข้อมูลในตำแหน่งที่ไม่มีข้อมูล หรือพยายามคำนวณค่าทั้งที่ไม่มีข้อมูลอยู่ หมายเหตุว่า R จะไม่ถือว่าเกิดข้อผิดพลาดขึ้นจนต้องหยุดการคำนวณ แต่อาจขึ้นคำเตือนบางครั้งเมื่อพยายามทำงานบนข้อมูลที่ไม่สมบูรณ์นี้

ประเภทข้อมูลชุด

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

เวกเตอร์

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

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

> x <- 1
> y <- c(2,3,4)
> z <- c(x,y)
> z
[1] 1 2 3 4

การถามประเภทข้อมูลของเวกเตอร์ด้วยฟังก์ชัน class() จะไม่รับคำตอบกลับมาว่ามันคือเวกเตอร์ แต่จะได้รับคำตอบว่าสมาชิกทุกตัวในเวกเตอร์นี้เป็นข้อมูลเดี่ยวประเภทใด นี่ทำให้เมื่อนำเวกเตอร์ของข้อมูลคละชนิดกันมารวมกัน สมาชิกบางตัวจะถูกแปลงประเภทข้อมูลขึ้นไปเป็นแบบที่สามัญกว่าทันที

> class(z)
[1] "numeric"
> mix <- c(1,"a",NA,T)
> mix
[1] "1"    "a"    NA     "TRUE"
> class(mix)
[1] "character"

การเข้าถึงสมาชิกในเวกเตอร์ สามารถใช้สัญลักษณ์วงเล็บปีกแข็งล้อมรอบตัวเลขตำแหน่งที่ต้องการ โดย R จะเริ่มนับสมาชิกตัวแรกด้วยเลขหนึ่ง (one-based indexing) และการเข้าถึงสมาชิกตัวที่สูงเกินกว่าขนาดของเวกเตอร์จะได้ผลลัพธ์เป็นข้อมูลว่าง เช่นนี้

> z[3]
[1] 3
> z[10]
[1] NA
> length(z)
[1] 4

นอกจากนี้ เรายังสามารถเข้าถึงข้อมูลย่อยพร้อมๆ กันหลายตัวได้ โดยส่งเวกเตอร์ของตำแหน่งทั้งหมดที่ต้องการเข้าไป ซึ่งสามารถเขียนย่อช่วงตำแหน่งที่ติดกันโดยใช้สัญลักษณ์โคลอน (:) หรือจะส่งเวกเตอร์ตรรกะเพื่อบอกว่าจะเลือกสมาชิกตัวไหนบ้างก็ได้ ตามตัวอย่างต่อไปนี้

> z[c(2,4)]
[1] 2 4
> z[1:3]
[1] 1 2 3
> z[4:2]
[1] 4 3 2
> z[c(T,F,F,T)]
[1] 1 4
> z[c(T,F)]
[1] 1 3

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

> z - 1
[1] 0 1 2 3
> z * c(1,-1)
[1]  1 -2  3 -4
> z + c(4,5,6)
[1] 5 7 9 8
Warning message:
In z + c(4, 5, 6) :
  longer object length is not a multiple of shorter object length

ข้อมูลชุดสำหรับคำนวณทางคณิตศาสตร์

หากเราต้องการเก็บข้อมูลที่เทียบเท่ากับอาเรย์สองมิติในภาษาอื่น ภาษา R จะเรียกข้อมูลชนิดนั้นว่าเมทริกซ์ (matrix) การจะสร้างข้อมูลชนิดนี้ได้ต้องเตรียมข้อมูลให้อยู่ในรูปของเวกเตอร์เสียก่อน แล้วจึงค่อยเปลี่ยนประเภทข้อมูลเป็นเมทริกซ์ ดังนี้

> A <- matrix(z, nrow=2, ncol=2)
     [,1] [,2]
[1,]    1    3
[2,]    2    4
> B <- matrix(z, nrow=2, ncol=2, byrow=TRUE)
     [,1] [,2]
[1,]    1    2
[2,]    3    4

สังเกตว่าที่ตัวเลขกำกับตำแหน่งผลลัพธ์ จะมีสัญลักษณ์ลูกน้ำ (,) เพิ่มเข้ามาด้วย นั่นบ่งบอกว่าการเข้าถึงสมาชิกในข้อมูลประเภทเมทริกซ์ จะต้องเขียนสัญลักษณ์ลูกน้ำกำกับด้วยเช่นกัน

> A[1,2]
[1] 3
> B[,2]
[1] 2 4
> A[2:1,2:1]
     [,1] [,2]
[1,]    4    2
[2,]    3    1

หากเรายังต้องการเก็บอาเรย์ที่มีมิติสูงขึ้นไปกว่านี้ ก็สามารถสร้างประเภทข้อมูลอาเรย์ได้ผ่านฟังก์ชัน array() โดยระบุขนาดในแต่ละมิติเข้าไป

> array(1:24, c(4,3,2,1))
, , 1, 1
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12

, , 2, 1
     [,1] [,2] [,3]
[1,]   13   17   21
[2,]   14   18   22
[3,]   15   19   23
[4,]   16   20   24

สังเกตว่าการดำเนินการทางคณิตศาสตร์โดยใช้เครื่องหมายธรรมดาทั่วไป (+,-,*,/) จะเป็นการนำสมาชิกในข้อมูลทั้งสองชุดมาจับคู่กันตัวต่อตัวแล้วดำเนินการทางคณิตศาสตร์แบบธรรมดาเท่านั้น หากต้องการดำเนินการทางคณิตศาสตร์แบบเมทริกซ์ ต้องใช้เครื่องหมายคณิตศาสตร์สำหรับเมทริกซ์โดยเฉพาะ (เช่น การคูณเมทริกซ์ %*%) ดังตัวอย่างต่อไปนี้

> A * B
     [,1] [,2]
[1,]    1    6
[2,]    6   16
> A %*% B
     [,1] [,2]
[1,]   10   14
[2,]   14   20

กรอบข้อมูล

กรอบข้อมูล (data.frame) คือข้อมูลชุดแบบตารางเช่นเดียวกับตารางในฐานข้อมูล กล่าวคือ แต่ละหลักของตารางจะบอกว่าหลักนี้ใช้เก็บข้อมูลเรื่องใด ส่วนแต่ละแถวของตารางก็คือข้อมูลหนึ่งระเบียน (record) นั่นเอง

วิธีสร้างกรอบข้อมูล เริ่มจากการเตรียมข้อมูลแต่ละหลักด้วยเวกเตอร์ โดยตรวจสอบให้แน่ใจว่าเวกเตอร์ทุกตัวมีความยาวเท่ากัน แล้วจึงนำมารวมกันด้วยฟังก์ชัน data.frame() ดังนี้

> handle <- c("Sheldon","Leonard","Penny")
> year <- c(1980,1980,1985)
> iq <- c(187,173,NA)
> big.bang <- data.frame(handle, yob=year, iq)
> big.bang
   handle  yob  iq
1 Sheldon 1980 187
2 Leonard 1980 173
3   Penny 1985  NA

เนื่องจากรูปแบบการเก็บข้อมูลนี้ คล้ายคลึงกับการเก็บโดยเมทริกซ์ การเข้าถึงข้อมูลแต่ละแถว สามารถทำได้ในทำนองเดียวกันกับที่ทำบนเมทริกซ์ คือ

> big.bang[3,]
  handle  yob iq
3  Penny 1985 NA

ส่วนการเข้าถึงข้อมูลแต่ละหลัก สามารถใช้เครื่องหมาย $ แล้วตามด้วยชื่อของเขตข้อมูลที่ต้องการได้เลย ซึ่งก็คือ

> big.bang$yob
[1] 1980 1980 1985

อนึ่ง หากข้อมูลในหลักซ้ายสุดของตารางมีค่าไม่ซ้ำกัน และเราต้องการค้นหาข้อมูลในแถวนั้นโดยใช้ค่าในหลักซ้ายสุดเป็นคำค้น (เทียบได้กับกุญแจหลักในฐานข้อมูล) ตอนสร้างกรอบข้อมูลให้กำหนดอาร์กิวเมนต์เพิ่มเข้าไปเล็กน้อย ดังนี้

> new.big.bang <- data.frame(row.names=handle, yob=year, iq)
> new.big.bang
         yob  iq
Sheldon 1980 187
Leonard 1980 173
Penny   1985  NA
> new.big.bang["Sheldon",]
         yob  iq
Sheldon 1980 187

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

> use <- new.big.bang$yob == 1980
> use
[1]  TRUE  TRUE FALSE
> new.big.bang[use,]
         yob  iq
Sheldon 1980 187
Leonard 1980 173

สถิติและความน่าจะเป็นอย่างรวบรัด

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

สิ่งสำคัญที่เรียกได้ว่าเป็นพระเอกของงานนี้ก็คือ "ข้อมูล" นั่นเอง หากขาดซึ่งข้อมูลแล้ว ไม่ว่าจะสร้างโมเดลทำนายความน่าจะเป็นมาดีขนาดไหนก็คงไร้ประโยชน์

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

นำเข้าข้อมูล

เนื่องจากการเข้าถึงไฟล์ข้อมูลทางสถิติต่างๆ ของประเทศไทยยังเป็นไปได้ยาก ตัวอย่างต่อไปนี้จะขอยืมข้อมูลจากต่างประเทศมาใช้ก่อน ซึ่งก็คือข้อมูลคะแนนเฉลี่ยของการสอบ SAT จากโรงเรียนระดับมัธยมในเมืองนิวยอร์ก (แนวคิดข้อสอบเทียบได้กับการสอบแอดมิชชั่นของไทย) โดยมีขั้นตอนดังนี้

เริ่มจากเข้าไปดาวน์โหลดข้อมูลดังกล่าวผ่าน Data.gov เลือกรูปแบบไฟล์ที่จะดาวน์โหลดเป็นแบบ CSV (comma separated values) เพื่อความสะดวกในการนำไปใช้ต่อ

เมื่อดาวน์โหลดไฟล์ดังกล่าวเสร็จสิ้น อาจทดสอบความถูกต้องของข้อมูลด้วยการเปิดไฟล์ดังกล่าวผ่านโปรแกรมจำพวกสเปรดชีต เช่น Microsoft Excel, Google Sheets, LibreOffice Calc หรือจะเปิดผ่านโปรแกรมแก้ไขข้อความทั่วไปก็ได้

ต่อไปจะอ่านข้อมูลเข้ามาใช้ใน R โดยคร่าวๆ แล้วสามารถทำได้ดังนี้ (สำหรับ Windows ใช้เครื่องหมาย / เพื่อคั่นระหว่างโฟลเดอร์เช่นเดียวกัน)

> data <- read.csv("PATH/TO/DOWNLOAD/SAT_Results.csv")

อย่างไรก็ตาม หากเราลองดูข้อมูลตัวเลขที่อ่านเข้ามา จะพบว่าในหลักเดียวกันนั้น บางแถวก็ยังมีตัวอักษร "s" ปนอยู่ด้วย หากยังพอจำกันได้ การมีข้อมูลตัวอักษรปนกับข้อมูลตัวเลขนั้น จะทำให้ข้อมูลตัวเลขถูกแปลงไปเป็นตัวอักษรทันที ซึ่งอาจส่งผลให้วิเคราะห์ผิดพลาดในภายหลัง นี่เป็นสิ่งที่เราสามารถหลีกเลี่ยงได้โดยระบุว่าตัวอักษร "s" หมายถึงข้อมูลในช่องนั้นหายไป (ข้อมูลชุดอื่นๆ อาจใช้ตัวอักษรระบุค่าที่หายไปแตกต่างกัน เช่น "-", "n/a" เป็นต้น)

> data <- read.csv("PATH/TO/DOWNLOAD/SAT_Results.csv",
                   na.strings="s")

นอกจากนี้แล้ว เรายังสามารถระบุเพิ่มเติมว่า ให้ใช้หลักแรกสุดเป็นกุญแจในการเข้าถึงข้อมูลในแถวนั้นๆ โดยเพิ่มอาร์กิวเมนต์ row.names เข้าไป

> data <- read.csv("PATH/TO/DOWNLOAD/SAT_Results.csv",
                   na.strings="s", row.names=1)

สำหรับข้อมูลชุดนี้ การระบุอาร์กิวเมนต์ตามข้างต้นก็ถือว่าเพียงพอแล้ว เพราะเมื่อไม่สนใจค่า NA ทั้งหมดที่พบ R จะพยายามแปลงข้อมูลแต่ละแถวให้เป็นตัวเลข เพื่อให้นำไปใช้งานต่อในเชิงสถิติได้ทันที อย่างไรก็ตาม หากเราไม่มั่นใจว่า R จะแปลงประเภทข้อมูลได้ถูกต้อง เรายังสามารถบังคับประเภทของตัวแปรในแต่ละแถวได้เช่นกัน

> data <- read.csv("PATH/TO/DOWNLOAD/SAT_Results.csv",
                   na.strings="s", row.names=1,
                   colClasses=c(rep("character",2), rep("numeric",4)))

ท้ายสุด เราอาจเลือกลบแถวที่ข้อมูลขาดหาย (มีข้อมูลเป็น NA) ทิ้งไป เพื่อความสะดวกในการคำนวณข้อมูลในภายหลัง ซึ่งทำได้โดย

> data <- na.omit(data)

ภาพรวมข้อมูลทางสถิติ

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

ตำแหน่งข้อมูล

ตำแหน่งข้อมูลจะแสดงว่าข้อมูลดังกล่าวมีตำแหน่งสำคัญๆ ตรงไหนบ้าง เช่น ค่ามากสุด/น้อยสุด ค่ากลางข้อมูล และควอร์ไทล์

ค่ากลางข้อมูลคือค่าที่แสดงว่าข้อมูลชุดนั้นมีค่าลู่เข้าสู่ตรงกลางที่เท่าใด ซึ่งอาจแบ่งย่อยได้เป็นอีก 3 ประเภท คือ

  1. มัชฌิม (mean) หรือบางที่ก็เรียกว่าค่าเฉลี่ย (average) หาได้จากการนำทุกค่าในข้อมูลมาบวกรวมกัน แล้วจึงหารด้วยจำนวนข้อมูลที่ใช้
  2. มัธยฐาน (median) หาได้จากการเรียงข้อมูลจากน้อยไปมากตามลำดับ แล้วดูว่าที่ตำแหน่งตรงกลางของข้อมูลมีค่าเป็นเท่าใด
  3. ฐานนิยม (mode) หาได้จากการนับว่าค่าใดปรากฏซ้ำมากที่สุดในข้อมูล

ค่าทั้งสามนี้ไม่จำเป็นต้องมีค่าเท่ากัน ซึ่งก็ถือเป็นเรื่องปรกติเนื่องจากข้อมูลมักมีการกระจายตัวไม่สม่ำเสมอ

ส่วนควอร์ไทล์จะใช้แนวคิดเดียวกันกับการหามัธยฐาน เพียงแต่แบ่งข้อมูลออกเป็นกลุ่มที่มีขนาดเท่ากันเพิ่มเป็น 4 กลุ่ม และสนใจค่าที่อยู่ตรงจุดเปลี่ยนระหว่างแต่ละกลุ่ม ดังนี้

  1. ควอร์ไทล์ที่ 1 (1st quartile) คือค่าที่มีตำแหน่งอยู่ตรงกลางระหว่างค่าน้อยสุดและค่ามัธยฐาน
  2. ควอร์ไทล์ที่ 2 (2nd quartile) คือมัธยฐานนั่นเอง (และเรามักไม่ค่อยเรียกว่า "ควอร์ไทล์ที่ 2" เท่าใดนักเพราะสามารถเรียกชื่อที่พื้นฐานกว่าได้)
  3. ควอร์ไทล์ที่ 3 (3rd quartile) คือค่าที่มีตำแหน่งอยู่ตรงกลางระหว่างค่ามากที่สุดและค่ามัธยฐาน

ใน R เราสามารถเรียกฟังก์ชัน summary() เพื่อดูภาพรวมตำแหน่งข้อมูลต่างๆ เหล่านี้ได้ทันที เช่น

> summary(data$SAT.Math.Avg..Score)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  312.0   371.0   395.0   413.4   437.0   735.0 

สังเกตว่าผลลัพธ์ดังกล่าว ไม่ได้นำข้อมูลฐานนิยมมาแสดงด้วย เพราะโดยทั่วไปข้อมูลมักมีความแม่นยำของตำแหน่งทศนิยมสูงจนไม่มีข้อมูลชิ้นใดซ้ำกัน การหาฐานนิยมด้วยวิธีพื้นฐานมักไม่ให้ข้อสรุปที่เกิดประโยชน์เท่าไร

เราอาจเลี่ยงไปหาฐานนิยมด้วยการแบ่งข้อมูลเป็นช่วงๆ ผ่านฮิสโตแกรม ซึ่งจะกล่าวถึงในหัวข้อถัดไป

การกระจายข้อมูล

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

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

  • พิสัย (range) บอกถึงขนาดของช่วงที่เล็กที่สุดที่สามารถครอบคลุมข้อมูลได้ทั้งหมด คำนวณจากการนำค่ามากที่สุดลบน้อยที่สุดได้เลย
  • พิสัยระหว่างควอร์ไทล์ (interquartile range) คำนวณจากการนำค่าของควอร์ไทล์ที่ 3 ลบด้วยค่าของควอร์ไทล์ที่ 1 หรือกล่าวอีกนัยหนึ่งได้ว่า วิธีนี้คือเป็นหาพิสัยที่ครอบคลุมข้อมูลจำนวนครึ่งหนึ่งที่กระจายรอบมัธยฐานนั่นเอง

นอกจากนี้ ยังมีการวัดการกระจายข้อมูลอีกวิธีหนึ่งที่เป็นที่นิยม ซึ่งก็คือส่วนเบี่ยงเบนมาตรฐาน (standard deviation, สัญลักษณ์ σ) จุดเด่นของวิธีนี้คือการใช้ข้อมูลทุกตัวมาคำนวณ แทนที่จะอ้างอิงจากค่าสรุปทางสถิติเพียงไม่กี่ค่า (ขอละการอธิบายสมการเนื่องจากมีรายละเอียดค่อนข้างมาก) การวัดการกระจายด้วยวิธีนี้จะใช้ได้ผลดีที่สุดเมื่อข้อมูลมีรูปร่างเป็นการแจกแจงปรกติ (normal distribution) ซึ่งบอกเป็นนัยว่ามีข้อมูลที่อยู่ห่างจากค่าเฉลี่ยไม่เกิน ±1σ อยู่ถึง 68% อย่างไรก็ตาม ข้อมูลที่มีการแจกแจงรูปแบบอื่นจะไม่สามารถสรุปขนาดของการแจกแจงเช่นนี้ได้

ฟังก์ชันสำหรับคำนวณการกระจายข้อมูลในภาษา R ได้แก่

> range(data$SAT.Math.Avg..Score)
[1] 312 735
> IQR(data$SAT.Math.Avg..Score)
[1] 66
> sd(data$SAT.Math.Avg..Score)
[1] 64.68466

พล็อตข้อมูล

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

เพื่อความรวดเร็วและถูกต้องของข้อมูล ในหัวข้อนี้เราจะใช้ข้อมูลตัวอย่างที่ภาษา R แถมมา สำหรับสร้างภาพการพล็อตทั้งหมด

พล็อตประชันทุกเขตข้อมูล

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

การพล็อตประชันทุกเขตข้อมูล คือการจับเอาข้อมูลทุกๆ คู่ในแต่ละหลักของกรอบข้อมูลมาประชันกัน แล้วพล็อตแต่ละคู่ของข้อมูลแบบกระจาย (scatter plot) การพล็อตนี้สามารถทำได้ผ่านฟังก์ชันง่ายๆ คือ plot() ตัวอย่างต่อไปนี้จะยืมข้อมูลดอกไอริสของ Edgar Anderson มาใช้ โดยข้อมูลดังกล่าวสามารถเรียกใช้งานได้ทันทีเลยในภาษา R โดยไม่ต้องโหลดไลบรารีใดเพิ่ม

> iris
    Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
1            5.1         3.5          1.4         0.2     setosa
2            4.9         3.0          1.4         0.2     setosa
...
150          5.9         3.0          5.1         1.8  virginica
> plot(iris)

ภาพที่ 1: พล็อตประชันทุกเขตข้อมูลของข้อมูลดอกไอริส

พล็อตกระจาย (Scatter Plot)

จากภาพที่ 1 เราอาจเริ่มต้นให้ความสนใจที่ความยาวกลีบดอก (Petal.Length) ต่อความกว้างกลีบดอก (Petal.Width) เนื่องจากเมื่อดูอย่างหยาบๆ แล้วน่าจะสร้างโมเดลได้ง่ายที่สุด เราจะเลือกพล็อตกระจายโดยใช้เขตข้อมูลเพียง 2 เขตนี้เท่านั้น เพื่อความสะดวกเราจะบอก R ก่อนว่ากำลังใช้ข้อมูลชุดใดเป็นหลักผ่านฟังก์ชัน attach() แล้วจึงสั่งพล็อตแบบเฉพาะเจาะจงด้วยสมการดังนี้

> attach(iris)
> plot(Petal.Width ~ Petal.Length)

ภาพที่ 2: พล็อตกระจายข้อมูลดอกไอริส โดยสนใจความกว้างต่อความยาวกลีบดอก

หมายเหตุว่า Petal.Width ~ Petal.Length ไม่ใช่การนำตัวแปรสองตัวมาดำเนินการกันแต่อย่างใด แต่มันคือการประกาศตัวแปรแบบสมการในภาษา R ที่มีความมหัศจรรย์ตรงที่ไม่ต้องใช้เครื่องหมายอัญประกาศมาครอบเพื่อบอกขอบเขตของสมการเฉกเช่นการประกาศข้อความ

อนึ่ง ในอนาคตเมื่อไม่ต้องการใช้ข้อมูลชุดนี้แล้ว (เช่น หลังจบหัวข้อนี้) ควรเรียกฟังก์ชัน detach() ในทำนองเดียวกันกับที่เรียก attach() ทุกครั้ง เพื่อไม่ให้เกิดความสับสนจากการที่มีข้อมูลจำนวนหลายชุดมากเกินกว่าที่ต้องการใช้งาน และเพื่อป้องกันกรณีที่มีข้อมูลต่างชุดกันแต่ใช้ชื่อเขตข้อมูลซ้ำกัน

ลากโมเดลเชิงเส้น

จากภาพที่ 2 เราอาจต้องการหาโมเดลเชิงเส้นของข้อมูลดังกล่าว เพื่อทำนายแนวโน้มว่าหากมีข้อมูลใหม่ๆ เพิ่มขึ้นมา ควรคาดหวังว่าข้อมูลเหล่านั้นจะเกิดบริเวณไหน การคำนวณดังกล่าวสามารถทำได้ผ่านฟังก์ชัน lm() ดังนี้

> lm(Petal.Width ~ Petal.Length)
Call:
lm(formula = Petal.Width ~ Petal.Length, data = iris)

Coefficients:
 (Intercept)  Petal.Length  
     -0.3631        0.4158  

หากต้องการลากเส้นดังกล่าวลงไปบนพล็อต ขอให้แน่ใจก่อนว่ามีภาพของพล็อตเดิมอยู่ก่อนแล้ว หลังจากนั้นจึงค่อยเรียกฟังก์ชัน abline() เพื่อลากเส้นตรงจากสัมประสิทธิ์ที่คำนวณได้ ดังนี้

> plot(Petal.Width ~ Petal.Length)
> abline(lm(Petal.Width ~ Petal.Length))

ภาพที่ 3: โมเดลเชิงเส้นของความกว้างต่อความยาวกลีบดอก

ลากโมเดลไม่เชิงเส้น

อย่างไรก็ตาม หากข้อมูลที่สนใจมีแนวโน้มว่าจะไม่เป็นเชิงเส้น ภาษา R ก็มีวิธีการคำนวณโมเดลแบบต่างๆ ให้เลือกใช้ได้หลายวิธี สำหรับวิธีที่ง่ายต่อการเรียกใช้งานที่สุด คือการประมาณค่าถดถอยแบบท้องถิ่น (local regression หรือ LOESS) ซึ่งจะสร้างโมเดลสมการพหุนามโดยอาศัยข้อมูลแต่ละส่วนในบริเวณใกล้เคียงมาปรับค่า เราสามารถเรียกดูผลลัพธ์จุดตัดต่างๆ บนเส้นโค้งของโมเดลที่คำนวณได้ดังนี้

> loess.smooth(Petal.Length, Petal.Width)
$x
 [1] 1.000000 1.120408 1.240816 1.361224 1.481633
...
$y
 [1] 0.06892099 0.11545407 0.16200259 0.20869061 0.25544166
...

ส่วนการพล็อตเส้นโค้งดังกล่าว จะเปลี่ยนมาเรียกผ่านฟังก์ชัน lines() ที่จะลากเส้นตรงเชื่อมระหว่างจุดตัดต่างๆ ตามที่ระบุ แต่เนื่องจากเรามีจุดตัดที่คำนวณไว้เป็นจำนวนมาก จึงได้ผลลัพธ์ออกมาเปรียบเสมือนเส้นโค้งนั่นเอง

> plot(Petal.Width ~ Petal.Length)
> lines(loess.smooth(Petal.Length, Petal.Width))

ภาพที่ 4: โมเดลไม่เชิงเส้นของความกว้างต่อความยาวกลีบดอก

ขอให้สังเกตการสลับที่ของตัวแปร สำหรับบรรทัดบนที่ระบุสมการผ่านเครื่องหมาย ~ นั้น จะมีความหมายว่าฝั่งซ้ายของ ~ คือข้อมูลในแกนตั้ง หรืออาจมองเป็นสมการคณิตศาสตร์ที่คุ้นตาโดยเปลี่ยนเครื่องหมาย ~ เป็น = ในทำนองเดียวกันกับ y=x นั่นเอง ส่วนในบรรทัดล่างเนื่องจากเราไม่สามารถระบุสมการด้วยเครื่องหมาย ~ ได้ จึงต้องส่งค่าเข้าไปเป็นข้อมูลในแกนนอน (x) แล้วจึงตามด้วยแกนตั้ง (y) ตามลำดับ

ลากโมเดลอิสระจากสมการที่กำหนดเอง

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

> plot(Petal.Width ~ Petal.Length)
> curve(exp(x-4/3*pi), add=TRUE)

ภาพที่ 5: โมเดลจากสมการ ex-(4/3)π

จุดที่น่าสนใจคือเราสามารถเขียนสมการที่ประกอบขึ้นมาจากพจน์ x แล้วส่งเป็นอาร์กิวเมนต์แรกของฟังก์ชัน curve() ได้ตรงๆ โดยที่เราไม่จำเป็นต้องมีตัวแปร x มาก่อน (หรือหากมีตัวแปรนี้อยู่ มันจะไม่ถูกใช้ในการคำนวณนี้แต่อย่างใด) นี่เป็นอีกหนึ่งในความมหัศจรรย์ของภาษา R ที่พยายามเอาใจผู้ใช้ที่มีพื้นฐานมาจากฝั่งคณิตศาสตร์/สถิติ ซึ่งอาจจะดูผิดปรกติไปบ้างเมื่อเทียบกับภาษาคอมพิวเตอร์อื่นๆ

แต้มสีแยกกลุ่มข้อมูล

อนึ่ง จากข้อมูลตั้งต้นของดอกไอริส นอกจากจะมีข้อมูลเชิงตัวเลขที่บ่งบอกลักษณะดอกไม้แล้ว ยังมีข้อมูลการแบ่งกลุ่มดอกไม้ตามสปีชีส์อีกด้วย ซึ่งข้อมูลการแบ่งกลุ่มนี้อาจไม่เหมาะสมในการพล็อตเทียบกับข้อมูลตัวเลขซักเท่าไร (ดังจะเห็นได้จากแถวล่างสุด/แถบขวาสุดในภาพที่ 1) แต่จะเหมาะสมกว่าหากพล็อตข้อมูลตัวเลขเทียบกันเช่นเดิม แล้วเพิ่มการแบ่งกลุ่มเข้าไปเป็นอีกแกนหนึ่ง เช่น แต้มสีจุดของแต่ละกลุ่มให้แตกต่างกัน ซึ่งสามารถสั่งได้ดังนี้

> plot(Petal.Width ~ Petal.Length, col=Species)

ภาพที่ 6: ข้อมูลดอกไอริสโดยแยกสีตามสปีชีส์

ทั้งนี้ทั้งนั้น หากข้อมูลตั้งต้นไม่ได้ถูกแบ่งกลุ่มไว้ก่อน แต่เรายังต้องการจัดกลุ่มข้อมูลอยู่ อาจเลือกใช้วิธี k-means ในการแบ่งกลุ่มข้อมูล โดยมีหลักการคร่าวๆ ดังนี้

  1. สุ่มเลือกจุดศูนย์กลางของแต่ละกลุ่มมาทั้งหมด k จุด
  2. กำหนดว่าจุดข้อมูลต่างๆ อยู่ในกลุ่มใด โดยพิจารณาจากจุดข้อมูลนั้นอยู่ใกล้จุดศูนย์กลางใดมากที่สุด
  3. คำนวณย้ายค่าจุดศูนย์กลางของแต่ละกลุ่มให้เป็นค่าเฉลี่ยของทุกจุดข้อมูลในกลุ่ม
  4. ทำซ้ำขั้นตอนที่ 2-3 จนกว่าการจัดกลุ่มจะเสถียร

เนื่องจาก R เตรียมฟังก์ชันดังกล่าวไว้ให้แล้ว วิธีเรียกใช้จึงไม่ยุ่งยากอะไร ขอเพียงแค่เตรียมข้อมูลสำหรับการจัดกลุ่ม และจำนวนกลุ่มที่ต้องการจัดไว้ให้เรียบร้อย แล้วจึงป้อนคำสั่งเหล่านี้ลงไป

> group <- kmeans(iris[3:4], 3)
> plot(Petal.Width ~ Petal.Length, col=group$cluster)

ภาพที่ 7: ข้อมูลดอกไอริสที่จัดกลุ่มแยกสีด้วยวิธี k-means เป็นจำนวน 3 กลุ่ม

หมายเหตุ เนื่องจากอัลกอริทึม k-means เริ่มต้นด้วยการสุ่ม อีกทั้งข้อมูลบางชุดก็ไม่สามารถแบ่งกลุ่มได้อย่างชัดเจน การแบ่งกลุ่มแต่ละครั้งด้วยวิธีดังกล่าวอาจให้ผลลัพธ์ที่แตกต่างกัน

พล็อตข้อสรุปการแจกแจงข้อมูล

เราได้เห็นการพล็อตกระจายที่พล็อตทุกๆ จุดจากข้อมูลที่มีไปแล้ว แต่บางครั้งเราก็ต้องการพล็อตแค่ภาพรวมของข้อมูลเท่านั้น วิธีการพล็อตที่ตอบโจทย์ดังกล่าวและเป็นที่นิยม คือ ฮิสโตแกรมและพล็อตกล่อง

ฮิสโตแกรม (histogram)

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

> hist(Sepal.Width)

ภาพที่ 8: ฮิสโตแกรมความกว้างกลีบเลี้ยงดอกไอริส

จากภาพที่ 8 จะเห็นว่าแท่งที่สูงที่สุดคือแท่งที่ 5 จากทางซ้าย หรือเมื่อดูเป็นช่วงจะได้ว่าคือช่วงที่ข้อมูลมีค่ามากกว่า 2.8 แต่ไม่เกิน 3.0 ซึ่งจะได้ว่าช่วงนี้คือฐานนิยมนั่นเอง

เราสามารถเปลี่ยนจำนวนรอยต่อระหว่างช่วงที่ต้องการได้ ด้วยการระบุอาร์กิวเมนต์ breaks เพิ่มเข้าไปดังนี้

> hist(Sepal.Width, breaks=4)

ภาพที่ 9: ฮิสโตแกรมความกว้างกลีบเลี้ยงดอกไอริส โดยขีดเส้นแบ่งช่วง 4 ครั้ง

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

> hist(Sepal.Width, breaks=c(2,2.1,2.4,2.7,3.0,3.3,3.6,3.9,4.4))

ภาพที่ 10: ฮิสโตแกรมความกว้างกลีบเลี้ยงดอกไอริส โดยแบ่งขนาดช่วงไม่เท่ากัน

หากแต่ละแท่งในฮิสโตแกรมมีความกว้างไม่เท่ากัน (เช่น ในภาพที่ 10) แกนแนวตั้งในพล็อตจะไม่ได้แสดงจำนวนการเกิดของข้อมูลอีกต่อไปแล้ว แต่มันคือค่าความหนาแน่นของข้อมูลในแต่ละช่วงแทน โดยใช้กฎว่าพื้นที่ของสี่เหลี่ยมทุกแท่ง (ขนาดช่วงคูณความหนาแน่น) รวมกันจะต้องได้เท่ากับหนึ่งหน่วยเสมอ ดังนั้นหากเราขยายขนาดของช่วงโดยที่มันยังครอบคลุมข้อมูลได้เป็นจำนวนเท่าเดิม แท่งข้อมูลแทนช่วงนั้นก็จะมีความสูงลดลงไปนั่นเอง (เช่น ขยายขนาดของช่วงสุดท้ายจาก 3.9-4.4 ไปเป็น 3.9-5.0)

พล็อตกล่อง (box plot)

พล็อตกล่องนั้นไม่ได้แสดงจำนวนการเกิดของข้อมูลเป็นช่วงๆ เหมือนอย่างฮิสโตแกรมแล้ว แต่จะแสดงข้อมูลด้วยค่าสรุปจากควอร์ไทล์แทน ลองพิจารณาตัวอย่างต่อไปนี้

> boxplot(Sepal.Length)

ภาพที่ 11: พล็อตกล่องความกว้างกลีบเลี้ยงดอกไอริส

ผลลัพธ์ที่ได้จากพล็อตกล่องในภาพที่ 11 มีลักษณะเป็นกล่องสี่เหลี่ยมที่ลอยอยู่และมีขายื่นออกมาข้างบนและล่าง เส้นหนาที่ลากผ่านกลางกล่องคือมัธยฐาน ขอบล่างของกล่องคือควอร์ไทล์ที่ 1 และขอบบนของกล่องคือควอร์ไทล์ที่ 3 สำหรับขาแต่ละข้างที่ยื่นออกมาจากตัวกล่องนั้น สุดปลายขาล่างคือค่าต่ำสุด และสุดปลายขาบนคือค่าสูงสุดนั่นเอง

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

> boxplot(iris[1:4])

ภาพที่ 12: พล็อตกล่องข้อมูลตัวเลขทั้งหมดของดอกไอริส

การเปรียบเทียบการกระจายในภาพที่ 12 แสดงให้เห็นชัดว่า ความกว้างกลีบเลี้ยง (Sepal.Width) มีการกระจายตัวต่ำที่สุด และในทางกลับกัน ความยาวกลีบดอก (Petal.Length) ก็มีการกระจายตัวมากที่สุด นอกจากนี้มันยังบอกตำแหน่งข้อมูลได้อีกด้วยว่า ความยาวกลีบเลี้ยง (Sepal.Length) มีค่ามากกว่าความกว้างกลีบดอก (Petal.Width) เสมอ

จุดเด่นอีกอย่างของพล็อตกล่อง คือมันสามารถแยกให้เห็นค่าผิดปรกติ (outlier) ได้ง่าย โดยแสดงเป็นจุดที่อยู่ไกลเลยขากล่องไปนั่นเอง หลักเกณฑ์สำหรับคัดแยกค่าผิดปรกติ คือ ค่านั้นมีค่าน้อยกว่า/มากกว่าค่าจากควอร์ไทล์ที่ 1/ควอร์ไทล์ที่ 3 อยู่ 1.5 เท่าของพิสัยระหว่างควอร์ไทล์ตามลำดับ ซึ่งอาจตีความหมายได้ว่า ค่านั้นเกิดจากการจดบันทึกข้อมูลผิดเพี้ยน และควรลบมันทิ้งก่อนนำข้อมูลไปประมวลผลต่อไป

เขียนโปรแกรมด้วย R

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

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

หมายเหตุว่าสำหรับหัวข้อนี้ โค้ดที่แสดงจะไม่มีสัญลักษณ์ > นำหน้า ซึ่งก็คือทุกคำสั่งต่อไปนี้ไม่ได้สั่งงานผ่าน REPL และรอดูคำตอบแล้ว แต่เป็นการเขียนคำสั่งต่างๆ เหล่านี้ลงไปในไฟล์สคริปต์แทน ใครที่ต้องการทดลองตามขอให้สร้างไฟล์ใหม่ชื่อ coupon.R แล้วคัดลอกโค้ดต่างๆ ที่กำลังจะปรากฏในหัวข้อนี้ลงไปยังไฟล์ดังกล่าว

ประกาศฟังก์ชัน

ฟังก์ชันในภาษา R นั้น เมื่อมองอย่างผิวเผินแล้วอาจดูไม่แตกต่างจากฟังก์ชันในภาษาอื่น การประกาศฟังก์ชันทำได้โดยใช้คำสำคัญว่า function ตามด้วยพารามิเตอร์ แล้วจบด้วยเนื้อหาในฟังก์ชันนั้นๆ สิ่งสำคัญที่ต่างออกไปจากภาษาอื่น คือการตั้งชื่อให้ฟังก์ชันจะต้องทำด้วยวิธีเดียวกันกับการประกาศตัวแปรเท่านั้น

random.int <- function(n) { sample.int(n, 1) }

โค้ดข้างต้นสร้างฟังก์ชัน random.int สำหรับสุ่มเลขจำนวนเต็มระหว่าง 1 ถึง n ขึ้นมาหนึ่งตัว

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

วนซ้ำจนกว่าจะผิดเงื่อนไข (while loop)

การวนซ้ำจนกว่าจะผิดเงื่อนไข ประกาศโดยคำสำคัญ while และมีโครงสร้างเฉกเช่นภาษาทั่วไป

random.coupon <- function(...) {
  count <- 0
  have.coupon <- logical(...)
  while (!all(have.coupon)) {
    have.coupon[random.int(...)] <- TRUE
    count <- count + 1
  }
  count
}

โค้ดข้างต้นสร้างฟังก์ชัน random.coupon สำหรับนับว่าต้องเปิดซองชิงโชคกี่ครั้ง ถึงจะได้คูปองครบ n แบบ โดยใช้เทคนิคการวนซ้ำแบบ while ในบรรทัดที่ 4 ถึง 7

ข้อสังเกตที่มาคู่กับการวนซ้ำเช่นนี้ คงหนีไม่พ้นการเพิ่มค่าตัวนับในแต่ละรอบที่วน ในภาษาทั่วไปอาจใช้เครื่องหมาย ++ หรือ += เพื่อเพิ่มค่านั้นก็ได้ แต่สำหรับภาษา R ที่ไม่มีตัวดำเนินการทั้งสองให้ใช้แล้ว จึงจำเป็นต้องเขียนเต็มยศ ดังเช่นที่เห็นได้จากบรรทัดที่ 6 ในโค้ดข้างต้น

ข้อสังเกตอื่นๆ อยู่ตรงการประกาศฟังก์ชันที่ระบุพารามิเตอร์ว่า ... ซึ่งมีความหมายว่าฟังก์ชันนี้สามารถรับอาร์กิวเมนต์ได้ไม่จำกัด และจะส่งต่อค่าในอาร์กิวเมนต์ที่รับเข้ามาไปยังฟังก์ชันอื่นๆ ในเนื้อหาฟังก์ชันนี้ที่เรียกใช้ ... เป็นอาร์กิวเมนต์ (ตัวอย่างเช่น ถ้าเรียกใช้ฟังก์ชัน random.coupon(42) ค่า 42 นี้จะถูกส่งไปเป็นเรียกใช้งานฟังก์ชัน logical(42) ต่อไป)

วนซ้ำสำหรับของแต่ละชิ้น (for loop)

การวนซ้ำสำหรับของแต่ละชิ้น ประกาศโดยใช้คำสำคัญ for ตามด้วยตัวแปรสำหรับรับสิ่งของในแต่ละรอบ แล้วตามด้วยเวกเตอร์ของสิ่งของทั้งหมดที่ต้องการวนซ้ำ (เช่นเดียวกับ foreach ในหลายภาษา)

sample.coupon <- function(n, size=10*n) {
  result <- NULL
  for (i in 1:size) {
    result <- c(result, random.coupon(n))
  }
  result
}

โค้ดข้างต้นสร้างฟังก์ชัน sample.coupon สำหรับทดลองหลายๆ ครั้งว่าแต่ละครั้งต้องสุ่มเปิดซองชิงโชคกี่ครั้ง โดยใช้เทคนิคการวนซ้ำแบบ for ในบรรทัดที่ 3 ถึง 5

จุดที่น่าสนใจอยู่ที่การประกาศพารามิเตอร์โดยกำหนดอาร์กิวเมนต์ปริยาย (default argument) ที่สามารถอ้างอิงไปยังอาร์กิวเมนต์อื่นของฟังก์ชันนี้ได้ทันที

ทำหรือไม่ตามแต่เงื่อนไขจะกำหนด (if-else)

การตรวจสอบถ้า-แล้ว สามารถใช้คำสำคัญได้เช่นเดียวกันกับภาษาทั่วไป คือ if else if และ else

if (!interactive()) {
  args <- commandArgs(TRUE)
  if (length(args) == 1) {
    filename <- "sample-coupon.png"
  } else if (length(args) == 2) {
    filename <- args[2]
  } else {
    stop("wrong number of argument!")
  }
  png(filename, width=800, height=800)
  arg.list <- list(x=as.numeric(args[1]))
  do.call(hist, list(substitute(sample.coupon(x), arg.list)))
  dev.off()
}

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

เรียกใช้โปรแกรม

ถึงตอนนี้หากใครพิมพ์ตามโค้ดข้างต้นทั้งหมด ก็จะได้ไฟล์สคริปต์ภาษา R มาหนึ่งโปรแกรมแล้ว (ส่วนใครไม่ได้พิมพ์ตาม แต่ยังอยากทดลองต่อ สามารถดาวน์โหลดโค้ดข้างต้นได้ที่นี่) เราสามารถเรียกใช้โปรแกรมดังกล่าวผ่าน terminal/cmd ได้ดังนี้

$ Rscript coupon.R 30

หรือจะนำเข้าฟังก์ชันจากไฟล์ดังกล่าวเข้ามายัง REPL เพื่อประยุกต์ใช้แบบโต้ตอบก็ย่อมได้

> source("PATH/TO/SCRIPT/coupon.R")
> hist(sample.coupon(30))

ไม่ว่าจะเรียกด้วยวิธีไหน ผลลัพธ์ที่ได้จะมีหน้าตาหนีไม่พ้นภาพที่ 13 ไปเท่าใดนัก (แม้ว่าอัลกอริทึมดังกล่าวจะอาศัยการสุ่มก็ตาม)

ภาพที่ 13: ฮิสโตแกรมคำตอบจากการทดลองปัญหานักสะสมคูปอง เมื่อมีคูปองแตกต่างกัน 30 แบบ

ดาวน์โหลดแพ็กเกจเสริมความสามารถ

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

โดยสถานที่จัดเก็บแพ็กเกจหลักอย่างเป็นทางการของภาษาดังกล่าวมีชื่อว่า CRAN (Comprehensive R Archive Network) ซึ่งปัจจุบันได้โฮสต์แพ็กเกจเสริมความสามารถกว่าหนึ่งหมื่นแพ็กเกจให้เลือกใช้งาน

วิธีการดาวน์โหลดแพ็กเกจเหล่านี้ก็ไม่ยาก เพียงแค่มีชื่อแพ็กเกจเหล่านั้นไว้ในใจ แล้วเปิด REPL ขึ้นมาเรียกฟังก์ชันต่อไปนี้

> install.pacakges("packageName")

โดยเปลี่ยน "packageName" เป็นชื่อแพ็กเกจที่ต้องการ หลังจากนั้นจะมีตัวเลือก mirror ของประเทศต่างๆ ขึ้นมา เลือกประเทศที่อยู่ใกล้ที่สุดเพื่อความเร็วในการดาวน์โหลด แล้วรอโปรแกรมดาวน์โหลดและติดตั้งแพ็กเกจเหล่านั้น

หลังจากติดตั้งเสร็จสิ้น เมื่อต้องการนำเข้าแพ็คเกจเหล่านั้นมาใช้งาน ก็ทำได้โดย

> library(packageName)

ต่อไปนี้จะขอแนะนำแพ็กเกจที่น่าสนใจจำนวนหนึ่ง (หากสั่ง library() แล้วพบข้อความแสดงความผิดพลาด อย่าลืมว่าต้องดาวน์โหลดแพ็กเกจเหล่านั้นก่อน)

กราฟเครือข่าย

กราฟเครือข่ายสามารถบ่งบอกความสัมพันธ์ในข้อมูลผ่านจุด (node) และเส้นเชื่อม (edge) ตัวอย่างข้อมูลที่เราคุ้นเคยกันดีคงหนีไม่พ้นความสัมพันธ์บนเครือข่ายสังคมออนไลน์ แต่ข้อมูลชนิดอื่นๆ ก็อาจถูกแปลงให้เป็นกราฟเครือข่ายได้ เช่น แผนที่ทางหลวง

> library(igraph)
> plot(make_graph("petersen"))

ภาพที่ 14: กราฟเครือข่ายที่มีการเชื่อมโยงแบบกราฟปีเตอร์เซน

ทำนายอนาคต

สำหรับข้อมูลที่มีแกนหนึ่งเป็นแกนเวลา เช่น ข้อมูลดินฟ้าอากาศ จำนวนประชากร หรือกระทั่งราคาหุ้น หากข้อมูลเหล่านั้นมีรูปแบบที่เกิดซ้ำมากพอ เราก็อาจทำนายอนาคตของข้อมูลนั้นได้

> library(forecast)
> plot(forecast(nottem))

ภาพที่ 15: พยากรณ์อุณหภูมิของเมืองนอตทิงแฮม (เส้นสีน้ำเงิน)

แผนที่โลก

นอกจากการพล็อตข้อมูลเชิงสถิติแล้ว R ยังสามารถพล็อตแผนที่โลกได้อีกด้วย

> library(maps)
> library(mapdata)
> map("world2Hires", xlim=c(110,190), ylim=c(-50,0))
> points(quakes[2:1], pch=".", col="red")

ภาพที่ 16: แผนที่โลกพร้อมตำแหน่งเกิดแผ่นดินไหว (จุดสีแดง) ใกล้ฟีจี

สรุป

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

อย่างไรก็ตาม บทความนี้ก็ไม่ได้กล่าวถึงทุกเรื่องที่ควรรู้ในภาษา R และตัวอย่างการคำนวณทางสถิติก็ยังอยู่ในระดับขั้นพื้นฐานเป็นอย่างมาก ใครที่ต้องการนำภาษา R ไปประยุกต์ใช้งานอย่างจริงจัง หรือวาดฝันไว้ว่าต้องการเป็นนักวิทยาศาสตร์ข้อมูล (data scientist) ก็คงต้องบอกว่าจงตั้งใจศึกษาตัวภาษาและวิชาสถิติเพิ่มเติม

เพราะการเรียนรู้ไม่มีวันสิ้นสุด และการเรียนรู้จะบรรลุผลสูงสุดเมื่อสามารถประยุกต์ใช้ความรู้นั้นเพื่อสร้างสรรค์ประโยชน์ได้

ภาคผนวก

ติดตั้งโปรแกรมบนเครื่อง

การติดตั้ง R นั้นสามารถทำได้อย่างง่ายดาย เพียงแค่เข้าไปยังเว็บไซต์หลักของภาษา R แล้วตามลิงก์ที่เขียนคำว่า "download R" จะพบกับรายชื่อ mirror ต่างๆ ทั่วโลกที่ทำสำเนาโครงการภาษา R ไว้ เลือกตัวเลือกที่อยู่ใกล้เคียงตำแหน่งปัจจุบันมากที่สุดเพื่อความเร็วในการดาวน์โหลด (สำหรับประเทศไทย มี mirror ของมหาวิทยาลัยสงขลานครินทร์สำหรับสำเนาดังกล่าว) เมื่อเข้าไปแล้ว จะพบกับตัวเลือกให้ดาวน์โหลดโปรแกรมได้ทั้งบน Windows, OS X และ Linux โดยมีรายละเอียดต่างกันเล็กน้อย ดังนี้

  • Windows เลือกดาวน์โหลดไฟล์ติดตั้ง .exe จากแฟ้ม "base" มาติดตั้งก็เพียงพอแล้วสำหรับบทความนี้
  • OS X ดาวน์โหลดไฟล์ติดตั้ง .pkg รุ่นใหม่ล่าสุดจากหน้าดาวน์โหลดของ OS X มาติดตั้งได้เลย
  • Linux เนื่องจากความหลากหลายทางดิสโทร การหาไฟล์ติดตั้งที่ถูกต้องจากหน้านี้อาจเป็นเรื่องยุ่งยากเกินจำเป็น เราอาจเลือกสั่งเพียงคำสั่งต่อไปนี้ผ่าน terminal แทน
    • apt install r-base สำหรับดิสโทร Debian/Ubuntu
    • yum install R สำหรับดิสโทร Red Hat/Fedora

หลังจากติดตั้งโปรแกรมสำเร็จแล้ว ผู้ใช้ OS X/Linux ไม่ต้องทำอะไรต่อ ส่วนผู้ใช้ Windows ควรแก้ไขตัวแปร PATH โดยเพิ่มตำแหน่งที่ติดตั้งโปรแกรม R (เช่น C:\Program Files\R\R-3.4.1\bin\x64) ต่อท้ายตัวแปรนั้น เพื่อให้สามารถเรียกโปรแกรม R ผ่าน cmd ได้ในภายหลัง

Hiring! บริษัทที่น่าสนใจ

Carmen Software company cover
Carmen Software
Hotel Financial Solutions
Next Innovation (Thailand) Co., Ltd. company cover
Next Innovation (Thailand) Co., Ltd.
We are web design with consulting & engineering services driven the future stronger and flexibility.
KKP Dime company cover
KKP Dime
KKP Dime บริษัทในเครือเกียรตินาคินภัทร
Kiatnakin Phatra Financial Group company cover
Kiatnakin Phatra Financial Group
Financial Service
Fastwork Technologies company cover
Fastwork Technologies
Fastwork.co เว็บไซต์ที่รวบรวม ฟรีแลนซ์ มืออาชีพจากหลากหลายสายงานไว้ในที่เดียวกัน
Thoughtworks Thailand company cover
Thoughtworks Thailand
Thoughtworks เป็นบริษัทที่ปรึกษาด้านเทคโนโยลีระดับโลกที่คว้า Great Place to Work 3 ปีซ้อน
Iron Software company cover
Iron Software
Iron Software is an American company providing a suite of .NET libraries by engineer for engineers.
CLEVERSE company cover
CLEVERSE
Cleverse is a Venture Builder. Our team builds several tech companies.
Nipa Cloud company cover
Nipa Cloud
#1 OpenStack cloud provider in Thailand with our own data center and software platform.
Bangmod Enterprise company cover
Bangmod Enterprise
The leader in Cloud Server and Hosting in Thailand.
CIMB THAI Bank company cover
CIMB THAI Bank
MOVING FORWARD WITH YOU - CIMB is the leading ASEAN Bank
Bangkok Bank company cover
Bangkok Bank
Bangkok Bank is one of Southeast Asia's largest regional banks, a market leader in business banking
MuvMi (Urban Mobility Tech Co.,Ltd.) company cover
MuvMi (Urban Mobility Tech Co.,Ltd.)
Shape the future of urban mobility towards affordable, clean, and safe solutions
T.N. Digital Solution Co., Ltd. company cover
T.N. Digital Solution Co., Ltd.
TNDS has been involving in every first move of banking’s major digital transformation.
KBTG - KASIKORN Business-Technology Group company cover
KBTG - KASIKORN Business-Technology Group
KBTG - "The Technology Company for Digital Business Innovation"
Siam Commercial Bank Public Company Limited company cover
Siam Commercial Bank Public Company Limited
"Let's start a brighter career future together"
Icon Framework co.,Ltd. company cover
Icon Framework co.,Ltd.
Global Standard Platform for Real Estate แพลตฟอร์มสำหรับธุรกิจอสังหาริมทรัพย์ครบวงจร มาตรฐานระดับโลก
REFINITIV company cover
REFINITIV
The Financial and Risk business of Thomson Reuters is now Refinitiv
H LAB company cover
H LAB
Re-engineering healthcare systems through intelligent platforms and system design.
The Gang Technology Co., Ltd. company cover
The Gang Technology Co., Ltd.
We're a Digital Agency that helps our customers transform their business into digital with ease.
LTMH company cover
LTMH
LTMH มุ่งเน้นการพัฒนาผลิตภัณฑ์ที่สามารถช่วยพันธมิตรของเราให้บรรลุเป้าหมาย
Seven Peaks company cover
Seven Peaks
We Drive Digital Transformation
Wisesight (Thailand) Co., Ltd. company cover
Wisesight (Thailand) Co., Ltd.
The Best Choice For Handling Social Media · High Expertise in Social Data · Most Advanced and Secure
MOLOG Tech company cover
MOLOG Tech
We are Modern Logistic Platform, Specialize in WMS, OMS and TMS.
Data Wow Co.,Ltd company cover
Data Wow Co.,Ltd
We enable our clients to realize increased productivity by solving their most complex issues by Data
LINE Company Thailand company cover
LINE Company Thailand
LINE, the world's hottest mobile messaging platform, offers free text and voice messaging + Call
LINE MAN Wongnai company cover
LINE MAN Wongnai
Join our journey to becoming No.1 food platform in Thailand

เราจะพบกับข้อความต้อนรับที่บอกรายระเอียด

รายระเอียด => รายละเอียด

ค่าผลลัพธ์ที่เห็นเป็นตัวแรกในแถวนี้เป็นผลลัพธ์ตัวที่เท่าไหร่จากผลลัพธ์ทั้งหมด

การหาฐานนิยมด้วยวิธีพื้นฐานมักไม่ให้ข้อสรุปที่เกิดประโยชน์เท่าไหร่

เท่าไหร่ => เท่าไร

ส่วนอีกร้านอาจขายตั้งแต่สากกระเบือยันเรือดำน้ำก็เป็นได้

สากกระเบือ => สากกะเบือ

Jedt3D Fri, 28/07/2017 - 19:03

login เข้ามาเพื่อของคุณโดยเฉพาะเลย ขอบคุณมากนะครับที่เขียนบทความสรุปเรื่องภาษา R มาเสียยาวเลยครับ เดี๋ยวมาอ่านต่อครับผม ตอนนี้เอาไปแชร์ก่อน :D

itpcc Fri, 28/07/2017 - 21:18

ขอบคุณครับ
เคยใช้ตอนเรียนวิชา TextMining ใช้งานสะดวกดีครับ ติดแต่ R ภาษามันออกประหลาดๆ ไปหน่อย แต่โดยรวมก็ถือว่าใช้สะดวกดีครับ Lib โหลดง่ายมาก

ปีที่แล้ว Google รับพนักงานมี requirement เรื่อง R โดยเฉพาะเลยล็อตนึง

วิทยากรของกูเกิ้ลเองก็ยังบอกว่าเขาใช้ R ในขั้นสุดท้ายของ Analytic อยู่ประมาณว่า Automate tool ยังไงยังต้องจบขั้นสุดท้ายใน R

หรือจะดีจะร้ายยังไง สุดท้ายความจริงที่ว่าเวลาเจอข้อมูลก้อนใหญ่ๆ มันไม่มีปัญหาเหมือน Spss แค่นี้ก็น่าสนใจแล้ว