สวัสดีทู๊กคนน จบไปแล้วกับคอร์สเรียน R for Data Analysis (R4DA) ครั้งแรกของเพจเราที่สอนแบบสองวัน 17 & 24 มีนาคม 2561 ที่ผ่านมา บล๊อกนี้เรามาสรุปโค้ดและเนื้อหาสำคัญๆให้เพื่อนๆได้ทบทวนอีกทีฮะ
สำหรับเพื่อนๆที่ยังไม่เคยเขียน R มาก่อน เรามีสอน R programming สำหรับผู้เริ่มต้น เรียนฟรี 2 ชั่วโมง (ก็ทำเป็นล๊าว!) ได้ที่คอร์สออนไลน์ของเราเลยฮะ สมัครเรียนฟรีที่ https://datarockie.teachable.com
Installation R, RStudio, Package

สำหรับเพื่อนๆที่อยากจะลองทำตาม tutorial ในบล๊อกนี้ด้วยต้องลงโปรแกรม R และ RStudio ก่อนนะฮะ สามารถดาวน์โหลดทั้งสองโปรแกรมได้ที่ลิ้งนี้เลย
- https://cran.r-project.org/ (เลือกลงได้เลย: Windows | Mac | Linux)
- https://www.rstudio.com/
พอลงโปรแกรมทั้งสองตัวเสร็จแล้ว ให้เราเปิด RStudio ขึ้นมา แล้ว copy โค้ดด้านล่างนี้แปะลงไปใน console ได้เลยฮะ
# install and load package install.packages("tidyverse") library(tidyverse)
package ที่เราใช้เรียนกันในคลาส R4DA ชื่อว่า tidyverse
ซึ่งเป็น package ที่สำคัญมากในการทำงานด้าน data analysis | data science สำหรับ R programmers ถ้าอยากรู้ว่า tidyverse
ทำอะไรได้บ้าง? ลองอ่านที่เว็บเค้าเลยฮะ (optional นะ)
สำหรับการ install packages ใหม่ๆใน RStudio ทำได้ง่ายมากๆ แค่พิมพ์ install.packages("package_name")
ลงไปใน console แล้วเด๋ว RStudio จะต่อกับ server และจัดการทุกอย่างให้เราโดยอัตโนมัติเลย
ปัจจุบัน (28 มีนาคม 2561) R community มีมากกว่า 14,xxx packages และมีฟังชั่นให้เลือกใช้งานมากกว่า 2 ล้านฟังชั่น เยอะอะไรเบอร์นี้ !! ส่วน tidyverse
ก็ติดอันดับ top 10 ที่มีการใช้งานมากที่สุดเลย อ้างอิงจากสถิติการใช้งานบนเว็บ R Documentation
TIP: RStudio คือ IDE ย่อมาจาก “Integrated Development Environment” เป็นโปรแกรมคล้ายๆ advanced text editor สำหรับเขียนภาษา R โดยเฉพาะเลย
Data Types in R
สำหรับ data types ใน R หลักๆจะมีอยู่ 5 แบบที่เราใช้กัน ประกอบด้วย
- numeric | double | integer
- logical (boolean)
- character (string)
- factor
- date & time
เราสามารถตรวจสอบ class หรือ type ของข้อมูลเราได้ด้วยฟังชั่น is.numeric(), is.logical(), is.character() ใน R ยังมีอีกหลายฟังชั่นเลยที่ใช้ในการตรวจสอบ data types ให้ลองพิมพ์ is.
ลงไปใน console แล้วเด๋ว R จะแนะนำฟังชั่นทั้งหมดที่ขึ้นต้นด้วย is.
ขึ้นมาให้เราเลือกใช้งาน
เราสามารถเปลี่ยน class หรือ type ด้วยฟังชั่น as.numeric(), as.logical(), as.character() ฯลฯ ตามโค้ดตัวอย่างนี้เลย
# integer x <- c(1:10) class(x) # logical y <- c(TRUE, FALSE) class(y) # character z <- c("Hello", "Hi", "Ni Hao") class(z) # convert logical to character y <- c(TRUE, FALSE) y <- as.character(y) class(y)
สำหรับ factor ใน R คือตัวแปร categorical ในทางสถิตินั่นเอง เช่น ชาย|หญิง, ซื้อ|ไม่ซื้อ ฯลฯ ซึ่ง factor แตกย่อยได้สองแบบตามหลักสถิติคือ nominal vs. ordinal ต่างกันนิดเดียวตรงที่ ordinal สามารถเรียงสูงกลางต่ำได้ เช่น รายได้ต่ำ|ปานกลาง|สูง ฯลฯ
# create factor (nominal) animals <- c("dog", "cat", "cat", "cat", "dog") factor(animals) # create factor (ordinal) household.income <- c("high", "medium", "low", "low", "medium") factor(household.income, levels = c("low", "medium", "high"), ordered = T)
ส่วนข้อมูลแบบ datetime เราสามารถใช้ package lubridate
ในการ extract ข้อมูลพวกวันที่ เดือน ปีออกมาจาก date object ได้ง่ายๆด้วยฟังชั่นตัวอย่างด้านล่าง
# download lubridate package install.packages("lubridate") library(lubridate) # lubridate key functions today <- Sys.time() year(today) month(today, label = T) day(today) wday(today, label = T)
TIP: เวลาเจอ function ใหม่ๆที่ไม่เคยใช้มาก่อน เราสามารถเรียก help file ขึ้นมาอ่านได้แค่กดปุ่ม F1 ที่ชื่อ function นั้นๆ หรือพิมพ์ ?function.name
หรือ help(function.name)
ใน console
DataFrame vs. Tibble

dataframe หรือที่เราเรียกกันว่า tabular table ถือว่าเป็นหัวใจสำคัญของการวิเคราะห์ข้อมูลด้วย R programming เลย เราสามารถ import ข้อมูลเข้า RStudio ได้ง่ายๆด้วยฟังชั่น read_csv
และใช้ฟังชั่น write_csv
ในการ export ข้อมูลออกจาก RStudio
โค้ดด้านล่าง แสดงตัวอย่างการนำเข้าข้อมูล iris.csv
จากเว็บไซต์ UCI machine learning repository อ่านรายละเอียดเพิ่มเติมเกี่ยวกับ iris dataset ได้ที่นี่
# import dataset from UCI ML website url <- "https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data" iris <- read_csv(url, col_names = FALSE) # export dataset as .csv file getwd() # check working directory write_csv(iris, "iris.csv")
ใน R จะมี dataframe พิเศษอีกรูปแบบหนึ่งที่เรียกว่า tibble
(พัฒนาโดยทีมงาน RStudio และ Hadley Wickham คนเดิม สาย R ไม่มีใครไม่รู้จักคนนี้) ซึ่งเป็น enhanced dataframe ที่มีประสิทธิภาพมากขึ้น เช่นการแสดง data type ของแต่ละคอลั่ม และการปริ้นผลใน console จะมีการจัดหน้าตาที่เป็นระเบียบเรียบร้อยมากขึ้น เช่น ปริ้นแค่ 10 แถวบนสุด (by default)
# change from tibble back to normal dataframe iris <- as.data.frame(iris) class(iris) # change from normal dataframe to tibble iris <- as_tibble(iris) class(iris)
เราสามารถ subset ข้อมูลใน dataframe เบื้องต้นด้วย [ ]
# basic subsetting iris[ ,1:2] # sub set all rows, columns 1-2 iris[1:10, ] # subset rows 1-10, all columns iris[1:10, 1:2] # subset rows 1-10, columns 1-2
TIP: เราสามารถใช้ฟังชั่น subset()
ของ base R ในการเลือก columns และ rows ที่เราต้องการได้ง่ายๆ เช่น subset(mtcars, hp > 200, select = c("wt", "hp", "mpg"))
หรือใช้ package ยอดนิยม dplyr
ที่เรากำลังจะสอนต่อไปในบล๊อกวันนี้
Load Built-in Dataset
R มาพร้อมกับ built-in dataset ให้เราได้ลองศึกษา พิมพ์ฟังชั่น data()
ลงไปใน console เพื่อเรียกดู data ทั้งหมดที่มีอยู่ใน base R ได้เลย เราสามารถโหลด dataset เข้ามาใน environment ของเราด้วยฟังชั่น data(dataframe)
ตามตัวอย่างด้านล่าง
# load data set data(mtcars) # change class to tibble mtcars <- as_tibble(mtcars) # review data structure & basic summary glimpse(mtcars) head(mtcars) # print first 6 rows tail(mtcars) # print last 6 rows summary(mtcars) # compute basic statistics e.g. min, max, mean, median
TIP: ทุกครั้งที่เราโหลด dataset ใหม่เข้าไปใน R เราควรจะต้องเช็คก่อนว่าข้อมูลของเรามีกี่ columns มีกี่ rows และพรีวิวข้อมูลเบื้องต้นด้วยฟังชั่น glimpse()
Basic Statistics
R เนี่ยเกิดมาเพื่อทำงานด้าน statistics โดยเฉพาะเลยรู้ไหม! แปลว่าฟังชั่นที่เราสามารถใช้ในการคำนวณค่าสถิติต่างๆ R มีเยอะมากๆ ด้านล่างเป็นแค่ส่วนหนึ่งที่เราใช้กันบ่อย ตั้งแต่หาค่า mean, median, mode, sd, var รวมถึงสรุปค่าสถิติแบบเทพๆด้วยแพ็คเกต psych
mean()
median()
modeest::mfv()
sd()
var()
mad()
max()
min()
quantile()
fivenum()
summary()
psych::describe()
สำหรับการใช้งานฟังชั่นพวกนี้ก็ตรงๆเลย ส่วนใหญ่มันจะ take dataframe หรือว่า vector ตัวเลขเป็น input แล้วก็ return ค่าสถิติต่างๆออกมา ตัวอย่างโค้ดด้านล่างเลย
# compute mean, sd, summary stats of column hp in mtcars mean(mtcars$hp) sd(mtcars$hp) summary(mtcars$hp)
ทวนความจำนิดนึง เราใช้ $
ในการเลือก column ที่เราต้องการจาก dataframe ส่วนโค้ดด้านล่างเราใช้ psych::describe
ในการคำนวณค่าสถิติของทุก columns ใน mtcars ทีเดียวเลย
# use package psych install.packages("psych") psych::describe(mtcars)
Data Transformation

มาถึง 5 verbs ที่สำคัญมากในการทำ data transformation ใน R (จริง dplyr คล้ายๆกับการใช้งาน SQL ที่หลายคนอาจจะเคยลองทำมาบ้างแล้ว)
select()
filter()
arrange()
mutate()
summarise()
สำหรับ select
ใช้สำหรับเลือก columns ที่เราต้องการ การเลือก columns ถือว่าเป็นการ subset ข้อมูลรูปแบบหนึ่งใน R
ปกติเราจะใช้ %>%
pipe operator ในการเชื่อมโค้ดต่างๆเข้าด้วยกันตามตัวอย่างด้านล่าง
# select columns mtcars %>% select(1:3) mtcars %>% select(wt, mpg, hp) mtcars %>% select(starts_with("m"))
filter
ใช้ในการสร้างเงื่อนไข (conditions) เพื่อเลือก rows ที่เราต้องการ (หรือ filter rows ที่ไม่ต้องการทิ้งไป) การสร้างเงื่อนไขสามารถสร้างได้มากกว่าหนึ่งข้อ โดยใช้ & (AND) และ | (OR) operators มาช่วย เช่น wt > 2 & gear == 4
# filter rows with conditions mtcars %>% filter(wt < 2) mtcars %>% filter(wt > 2 & gear == 4) mtcars %>% filter(hp %in% 100:150)
arrange
ใช้ในการ sort ข้อมูลจากค่าน้อยไปมาก (ascending order) หรือแบบมากไปน้อย (descending order) เราสามารถ sort ตัวแปรได้มากกว่าหนึ่งตัวพร้อมกัน
# arrange data (sorting) mtcars %>% arrange(hp) mtcars %>% arrange(desc(hp))
mutate
ใช้ในการสร้างตัวแปรใหม่ใน dataframe ของเรา
# create new variables mtcars %>% mutate(new.var = hp/100) mtcars %>% mutate(new.var = ifelse(hp >= 200, "High", "Low"))
summarise
ใช้ในการสรุปค่าสถิติต่างๆใน dataframe ของเรา ปกติเราจะใช้คู่กับ adverb function อีกหนึ่งตัวที่มีประโยชน์มากของ dplyr
ชื่อว่า group_by
ใช้ในการจับกลุ่มข้อมูลตามตัวแปร factor ที่อยู่ใน dataframe ของเราก่อนจะคำนวณค่าสถิติ
# summarise basic statistics mtcars %>% summarise(avg_hp = mean(hp), max_hp = max(hp), min_hp = min(hp), stdev_hp = sd(hp), n = n()) # group summary statistics by am variable (Auto|Manual) mtcars %>% group_by(factor(am)) %>% summarise(avg_hp = mean(hp))
TIP: การสร้างเงื่อนไขแบบ equality conditions ใน R ต้องใช้เครื่องหมาย ==
(เท่ากับ สองตัวติดกัน) เช่น 1+1 == 2 .. R จะตอบกลับมาใน console ว่า TRUE ส่วนเครื่องหมาย !=
อ่านว่าไม่เท่ากัน
Tidy Data

หลักการของ tidy data ถูกนำเสนอโดย Hadley Wickham (อีกแล้ว !!) ในปี 2014 โดยนิยามหลักๆของมันคือ “a variable forms a column” และ “an observation forms a row”
tidyr
เป็นอีกหนึ่ง package หลักใน tidyverse
ที่ใช้ในการ transform data ให้อยู่ในรูปของ tidy format เช่น การเปลี่ยนจาก wide → long format ด้วยคำสั่ง gather
หรือเปลี่ยนจาก long → wide format ด้วยคำสั่ง spread
(อ่านความแตกต่างระหว่าง wide vs. long ได้ที่นี่)
ส่วน separate
และ unite
อย่างที่ชื่อมันบอกเป็นนัยๆคือการแยกและ รวมคอลั่มตามลำดับ ลองดูตัวอย่างการใช้งาน และการเขียนโค้ดเบื้องต้นด้านล่างเลยฮะ
gather()
spread()
separate()
unite()
# prepare data for our tutorial data(WorldPhones) df <- as.data.frame(WorldPhones) df$Year <- rownames(df) rownames(df) <- NULL glimpse(df)
# transformation: wide to long format df.long <- df %>% gather(1:7, key = Region, value = Sales) print(df.long) # transformation: long to wide format df.long %>% spread(key = Region, value = Sales) # separate() and unite() columns table5 %>% separate(rate, into = c("infected", "population"), sep = "/") %>% unite(new.year, century, year, sep = "")
ถ้าเข้าใจฟังชั่นและทำได้ครบทั้ง dplyr
และ tidyr
ก็สุดยอดแล้วฮะ เรา transform data ได้หลายรูปแบบเลย ถ้าอยากเข้าใจเชิงลึกเรื่อง tidy data เราแนะนำให้อ่านเปเปอร์ของ Hadley Wickham ที่ลิ้งนี้เลย https://www.jstatsoft.org/article/view/v059i10/v59i10.pdf (2014)
TIP: R ชอบข้อมูลแบบ long format มากกว่าสำหรับการทำ exploratory data analysis ชีวิตเราจะง่ายมว๊าก ถ้า “a variable forms a column” และ “an observation forms a row” ตาม tidy data concept
Missing Values
tidy data ที่ดีควรจะมี data ที่สมบูรณ์เช่นกัน i.e. ไม่มี missing values หรือ NA มากวนใจเราตอนวิเคราะห์ผล ใน R เราสามารถตรวจสอบว่า dataframe ของเรามีค่า NA หรือเปล่าง่ายๆด้วยฟังชั่น complete.cases(dataframe)
โดยฟังชั่นนี้จะ return ค่า FALSE ถ้าเกิด row ไหนใน dataframe มีข้อมูลไม่ครบ (i.e NA presence)
เราสามารถ drop rows ที่มี missing value ทิ้งได้เลยด้วยคำสั่ง na.omit
# load data for this tutorial install.package("MASS") data(biopsy, package = "MASS") # check if dataframe has any missing values (row by row) complete.cases(biopsy) mean(complete.cases(biopsy)) # 97.7% complete, 2.3% missing # drop rows that have missing values biopsy <- na.omit(biopsy)
ถ้าเราตัดสินใจไม่ drop rows เนื่องจาก sample size (n) เราน้อย ให้เราทำ imputation ค่า missing value ในคอลั่มนั้นๆก็ได้ เช่น แทนที่ NA ด้วยค่า mean, median, หรือค่า mode ของคอลั่มนั้น
ตัวอย่างโค้ดด้านล่าง เราใช้ filter
เพื่อกรองเอา rows ที่มีค่า NA ออกมาดู แล้วค่อย impute NA ในคอลั่มนั้นด้วยค่า mode ของตัวแปร V6
# filter rows with missing value (NAs) biopsy %>% filter(!complete.cases(.)) # all NAs identified in column V6 # NA imputation table(biopsy$V6) # find mode in this column biopsy$V6[is.na(biopsy$V6)] <- 1
TIP: ฟังชั่นที่มีประโยชน์มากในการ impute NA คือ tidyr::replace_na()
ในตัวอย่าง biopsy ด้านบน เราสามารถพิมพ์ replace_na(biopsy$V6, 1)
เพื่อแทนที่ NA ด้วยเลข 1 (ค่า mode) ได้เลยง่ายๆ
Data Visualization

ggplot()
สร้าง plots เบื้องต้นggplot2
เป็นอีกหนึ่ง package ที่รวมอยู่ใน tidyverse
แล้วฮะ เราสามารถเรียกใช้งานฟังชั่น ggplot()
เพื่อสร้าง plots เบื้องต้นได้เลย
geom_point()
ใช้สร้าง scatter plotgeom_smooth()
ใช้สร้าง smooth line หรือ linear ก็ได้geom_histogram()
ใช้สร้าง histogramgeom_bar()
ใช้สร้างกราฟแท่งgeom_line()
ใช้สร้างไลน์ชาร์ทเพื่อดูเทรนด์ (พวก time series)geom_boxplot()
ใช้สร้าง boxplot เพื่อดู outliers
# scatter plot ggplot(data = mtcars, mapping = aes(x = wt, y = mpg)) + geom_point() # scatter plot + smoother ggplot(data = mtcars, mapping = aes(x = wt, y = mpg)) + geom_point() + geom_smooth() # histogram ggplot(data = mtcars, mapping = aes(x = mpg)) + geom_histogram(bins = 15) # bar plot data(diamonds) ggplot(data = diamonds, mapping = aes(x = clarity)) + geom_bar() # line plot data(economics) ggplot(data = economics, mapping = aes(x = date, y = pop)) + geom_line() # boxplot ggplot(data = diamonds, mapping = aes(x = cut, y = price)) + geom_boxplot()
อีกหนึ่งเทคนิคที่ทำให้เราชอบใช้ ggplot2
มากๆคือการทำ facet
แบ่ง plot ของเราเป็นกรุ๊ปตามตัวแปร factor | category ที่อยู่ใน dataframe ของเราตามตัวอย่างด้านล่าง

facet_wrap
ใน ggplot2# facet plots by factor variable in dataframe ggplot(df, aes(carat, price)) + geom_point(alpha = 0.3) + geom_smooth() + theme_minimal() + facet_wrap(~ cut, ncol = 5)
TIP: สำหรับ ggplot2
เป็น package
ที่ทำอะไรได้อีกเยอะมากๆ ที่เราสอนกันในคลาส R4DA แค่ประมาณ 20-30% ของฟังชั่นทั้งหมดใน ggplot2
เอง สำหรับเพื่อนๆที่สนใจอยากศึกษาเพิ่มเติม ลองดาวน์โหลด Cheat Sheet ggplot2 ได้ที่นี่เลย
Machine Learning in R
อีกหนึ่งสุดยอด package ขวัญใจโปรแกรมเมอร์สาย R สำหรับการทำ Machine Learning คือ caret
นั่นเองฮะ (พัฒนาและดูแลโค้ดทั้งหมดโดย Max Kuhn)
# install package caret install.packages("caret") library(caret)
สำหรับการสร้าง machine learning models เบื้องต้น กระบวนการทำงานจะมี 4 ขั้นตอน ประกอบด้วย
Data preparation
Train models
Tune models
Evaluate results
ตอนนี้สมมติว่าข้อมูลของเรา clean & prep มาเรียบร้อยแล้ว i.e. ไม่มี NA (missing values) หรือทำพวก feature engineering หรือ transformation มาเสร็จแล้ว เราจะข้ามไปสอนที่ step 2-4 เลย
โค้ดตัวอย่างด้านล่าง เราโหลดข้อมูล Sonar สำหรับปัญหา binary classification i.e. Class = R or M เพื่อที่จะใช้ predict ว่าวัตถุนั้นเป็นหินหรือว่าแร่ธาตุ
# load dataset SONAR data(Sonar) glimpse(Sonar) # split data into train | test sets set.seed(1) id <- sample(nrow(Sonar), 0.8*nrow(Sonar)) train <- Sonar[id, ] test <- Sonar[-id, ]
ลองโยน train data ของเราให้กับ Random Forest algorithm เรียนรู้และใช้ k-fold cross validation (k = 5) ในการเทรนโมเดลเพื่อให้ได้ Accuracy สูงที่สุด i.e. metric = “Accuracy” เสร็จแล้วก็ evaluate results ของ fit.rf ด้วย confusion matrix
# train RandomForest algorithm fit.rf <- train(Class ~ ., data = train, method = "rf", metric = "Accuracy", trControl = trainControl(method = "cv", number = 5)) # evaluate results print(fit.rf) predictions <- predict(fit.rf, test) tab1 <- table(predictions, test$Class) # confusion matrix sum(diag(tab1)) / nrow(test) # accuracy of test data
และนี่คือโค้ด template เบื้องต้นในการเทรนโมเดลของเราด้วย caret
package นั้นเอง ง่ายอะไรเบอร์นี้! ปกติเราจะเทรน algorithms หลายๆตัว เพื่อหาว่าตัวไหนดีที่สุด (เช่นได้ Accuracy สูงสุด) สำหรับปัญหานั้นๆของเรา
TIP: ถ้าเราต้องการเทรน algorithms แบบอื่นด้วย template ด้านบน แค่เปลี่ยน method = "rf"
เป็นชื่อ algorithms ตัวอื่นๆ เช่น naive bayes "nb"
หรือ decision tree "rpart"
เป็นต้น อ่านคู่มือการใช้งาน caret
ได้ทั้งหมดที่ link นี้เลย
Thank You for Joining R4DA Class

ขอบคุณเพื่อนๆทุกคนมาเรียน R4DA กับเราทั้งสองอาทิตย์ที่ผ่านมาครับ ขอบคุณเพื่อนๆที่ติดตามอ่านบล๊อกนี้ของเราจนจบเช่นกัน หากมีคำถามเกี่ยวกับบล๊อกวันนี้ ทักมาคุยเล่นกับเราได้ที่ m.me/datarockie
สำหรับเพื่อนๆที่สนใจอยากเรียน basic statistics | data science | R & Python Programming เบื้องต้น สามารถติดตามคอร์สเรียนออนไลน์ใหม่ๆของเพจเราได้ที่ https://datarockie.teachable.com
โปรแกรม R สามารถนำมาแสดงผลบนเว็บไซต์ที่เขียนขึ้ยเองได้มั้ยคะ
ได้ครับ ลองดู R Shiny ได้เลยครับ 🙂
โปรแกรม R สามารถอ่านข้อมูลจาก Database พวกที่เป็นแบบ No sql หรือ sql ได้ไหมครับ
ได้ครับ ลองดูการต่อ databases หลายๆแบบได้ที่นี่ครับ https://db.rstudio.com/databases/my-sql/
ตรงส่วนของ DataFrame vs Tibble ก่อนจะเริ่ม โค้ดตามตัวอย่างของการนำเข้าข้อมูล iris.csv
จะต้องติดตั้ง install.packages(“readr”) ก่อนครับ
ขอบคุณครับ tutorial นี้เราโหลด tidyverse ตั้งแต่แรกเลยครับ (readr จะถูกโหลดอัตโนมัติเลยคร้าบ)
มีคอร์สสอน regression model ด้วยโปรแกรม R มั้ยคะ