ETL on R

Cheng Yu Lin (aha) and Jia Wei Chen (jiawei)

故事的起源

  1. 房價真的太高了嗎?

故事的起源

  1. 房價真的太高了嗎?
  2. 大熊被抓了

故事的起源

  1. 房價真的太高了嗎?
  2. 大熊被抓了
  3. 台灣房市真的要崩盤了嗎?

在論述台灣房市之前,身為一個資料科學家,第一步是了解問題

本次,我們的問題是房價真的太高了嗎?

還記得這個新聞吧? 就從這裡開始

資料在哪裡

從上面新聞所述,所以我們想要:

資料在哪裡

從上面新聞所述,所以我們想要:

你想知道什麼資料?

  1. GDP
  2. 房貸餘額
  3. 股價
  4. 新聞
  5. 地價資訊

資料在哪裡

從上面新聞所述,所以我們想要:

你想知道什麼資料?

  1. GDP
  2. 房貸餘額
  3. 股價
  4. 新聞
  5. 地價資訊

可能的來源?

  1. 政府公開資料
    • 主計處
    • 央行
  2. 新聞
    • 紙本報紙
    • 電視新聞
    • 電子新聞
  3. 股市
    • Yahoo Stock API

即便知道資料在哪,可是資料還是如同一盤散沙

看看Raw Data

我們ETL會用到的有

  • dplyr 可用類似SQL方法操作data frome
  • xts 處理時間格式好用的套件
  • gdata 可以處理Excel 2007以上的文件
  • quantmod 可以處理股市資料
  • stringr 字串相關處理

來上課的,有

DSC的One Piece

  • DSC2014Tutorial R社群為了這次Tutorial製作的套件,所有的教材都在這了
deps <- available.packages("http://taiwanrusergroup.github.io/R/src/contrib")[1,"Imports"]
pkgs <- strsplit(gsub("\\s", "", deps), ",")[[1]]
for(i in seq_along(pkgs)) {
  # You can change your favorite repository
  if (require(pkgs[i], character.only = TRUE)) next
  install.packages(pkgs[i], repo = "http://cran.csie.ntu.edu.tw")
}
install.packages('DSC2014Tutorial', 
    repo = 'http://taiwanrusergroup.github.io/R', type = 'source')
library(DSC2014Tutorial)

安裝之後, 輸入以下指令就可以打開投影片:

slides("ETL")

解決資料散亂的方法 - ETL

ETL 的主要內容

今日解決的問題流程 - ETL

今日課程的目標

學會extraction, cleaning, transformation

  • 用R整理結構化資料 STEP1 房貸餘額1 , STEP2 GDP
  • 用R整理非結構化資料 STEP3新聞分析

學會 load

  • 整併全部的資料 STEP4

邁向 其他有意思的主題

學習,實作,觀察 STEP1

ETL 第一步

開始收集資料(房貸餘額)

請連線到 https://survey.banking.gov.tw/statis/stmain.jsp?sys=100&funid=r100

開始收集資料

讀入資料 - read.table

至少要記得的 read.table

Cl_info = read.table(file=ETL_file("cl_info_other.csv"),sep=",",stringsAsFactors=F,header=T)
  • 輸出形態為Data Frame
  • file 就是指讀入的檔案路徑
  • sep 指的是欄位分割用的符號,通常csv檔案格式是透過,做分割
  • stringsAsFactors 預設是True, 會讓讀入的字串都用Factor形態儲存,那麼資料就會轉為整數儲存與額外的對照表
  • header 預設是False,表示第一行是不是表格標頭,作為輸出的dataframe欄位名的colnames

看看讀入結果

View(Cl_info)
str(Cl_info)

直接讀入是否覺得怪怪的?

再看一次

  • etl_dt data_dt文字但應該是時間
  • bank_code 也是文字但應該是factor

Transformation - 資料處理

將資料讀入

library(DSC2014Tutorial)
library(dplyr)
Cl_info = read.table(file=ETL_file('cl_info_other.csv'),header=T,sep=",",stringsAsFactors=F)
Cl_info_part = mutate(Cl_info,data_dt = as.POSIXct(data_dt),
                 bank_code = as.factor(bank_code),etl_dt = as.POSIXct(etl_dt))
View(Cl_info_part)
str(Cl_info_part)


  • 到這裡已經完成第一次的資料ExtractionTransformation了!

看見資料了!但是剛剛處理過程中的mutate是什麼?

看見資料了!但是剛剛處理過程中的mutate是什麼?

R中用來做資料清理資料處理好用的套件dplyr其中之一的函式

接下來我們將介紹三個基本函式

練習-挑選欄位(1/2)

dplyr select 函式,用來挑選欄位

Cl_demo1 = select(資料表,欄位1,欄位2,欄位3)
  • 第一個參數為輸入的data frame
  • 後續參數為選取的欄位名稱


給熟悉SQL的使用者

select data_dt,bank_nm,mortgage_bal from Cl_info;

練習-挑選欄位(2/2)

dplyr select 函式,用來挑選欄位

Cl_demo1 = select(Cl_info,data_dt,bank_nm,mortgage_bal)
  • 第一個參數為輸入的data frame
  • 後續參數為選取的欄位名稱


給熟悉SQL的使用者

select data_dt,bank_nm,mortgage_bal from Cl_info;

練習-挑選資料

dplyr filter 函式,用來保留要留下的資料列

Cl_demo2 = filter(Cl_info,mortgage_bal>1000000)
  • 第一個參數為輸入的data frame
  • 第二個參數為邏輯運算式,可用data frame裡的欄位,當結果為True時,該筆資料列保留


給熟悉SQL的使用者

select * from Cl_info where mortgage>1000000;

練習-增加特徵欄位(1/2)

dplyr mutate 用來增加非彙總計算欄位

Cl_demo3 = mutate(資料表,新欄位名 = 運算式)
  • 第一個參數為輸入的 data frame
  • 第二參數為計算式,也可以用來當做轉換資料形態變更欄位為名稱使用
  • 例如: bank_code = as.numeric(bank_code)


給熟悉SQL的使用者

select mortgage_bal/1000000 as mortage from Cl_info;

練習-增加特徵欄位(2/2)

dplyr mutate 用來增加非彙總計算欄位

Cl_demo3 = mutate(Cl_info,mortage = mortgage_bal/1000000)
  • 第一個參數為輸入的 data frame
  • 第二參數為計算式,也可以用來當做轉換資料形態變更欄位為名稱使用


給熟悉SQL的使用者

select mmortgage_bal/1000000 as mortage from Cl_info;

練習-排序資料(1/2)

dplyr arrange 用來重新排序

Cl_demo4 = arrange(資料表,欄位1,desc(欄位2)))
  • 第一個參數為輸入的 data frame
  • 後續參數為排序用欄位,預設遞增,可以透過desc()變成遞減排序


給熟悉SQL的使用者

select * from Cl_info order by mortage,data_dt desc ;

練習-排序資料(2/2)

dplyr arrange 用來重新排序

Cl_demo4 = arrange(Cl_info,mortgage_bal,desc(data_dt))
  • 輸出data frame
  • 第一個參數為輸入的 data frame
  • 後續參數為排序用欄位,預設遞增,可以透過desc()變成遞減排序


給熟悉SQL的使用者

select * from Cl_info order by mortage,data_dt desc ;

練習時間

  1. 請幫忙從Cl_info_part找出data_dt,bank_nm,mortgage_bal
  2. 請幫忙從Cl_info_part挑選出mortgage_bal大於1千萬的銀行資料
  3. 請幫忙排序Cl_info_part出mortgage_bal由小到大,但資料時間data_dt從大到小
  4. 請執行下面程式碼,我們後續會利用Cl_info_part2
Cl_info_part2 = mutate(Cl_info_part,time= as.POSIXct(data_dt))

學習,實作,觀察 STEP2

讓我們來練習抓下一個資料GDP

ETL 第二步

開始收集資料(GDP)

請連線到 http://ebas1.ebas.gov.tw/pxweb/Dialog/NI.asp

開始收集資料(GDP)

  1. GDP從直接下載國民生產毛額之處分
  2. 季(1980之後)
  3. 全部的日期
  4. 全部的計價方式
  5. 項目選GDP
  6. 總類選原始值
  7. 按繼續後,選從螢幕顯示Excel檔
  8. 開啟後,另存新檔成csv檔
  9. 開回RStudio 開始處理資料

或是ETL_file("GDP.txt")

練習讀入與創建一個GDP的 data frame

答案

GDP = read.table(file=ETL_file("GDP.txt"),sep=",",stringsAsFactors=F,header=F)

輸入View(GDP)觀察GDP會發現怎麼前後有很多列的資料是不要的

好亂,我想整理好這個data frome

資料清理

要處理的標的物有

  1. 去除前後不相干的資料列
  2. 轉換欄位的格式
    • 將單位轉換,從百萬元變成元
    • 將不應該出現的,去除
  3. 抽離年份

去除前後不相干的資料列

GDP_part = GDP[5:136,]

別忘了改上欄位名稱

colnames(GDP_part) = c("time","GDP","GDP_yoy","GDP_2006","GDP_2006_yoy",
                        "GDP_minus","GDP_minus_yoy")

去除rownames

rownames(GDP_part) = NULL
View(GDP_part)

另外一個簡單的例子

iris
iris_part <- iris[4:6,]
rownames(iris_part) <- c('a','c','d')
View(iris_part)

轉移文字格式

# 去除中間不合理的,在數字欄位上與補上百萬
GDP_part2= mutate(GDP_part,GDP = as.numeric(gsub(",", "",GDP))*1000000)

  1. 我們利用了 gsub, 替換字元,將原先有問題的,去除
  2. 而後利用了as.numeric 將原來的文字形態改成數字

抽離年份與季

GDP_part3 = mutate(GDP_part2,year=as.numeric(substr(time,0,4)),
                            season=as.numeric(substr(time,6,6)))
GDP_part4 = select(GDP_part3,year,season,GDP)
  1. 我們利用了 substr, 取出特定位置的資料
  2. 再次利用as.numeric, 將文字轉成數字

練習時間

  1. 去除頭尾不合理的資料列
  2. 去除GDP的 , , 然後將它轉成數字
  3. year,season抽離出來並轉成數字,同時最後資料只保留GDP,year,season

擁有了GDP房貸餘額,那接下來呢?

非結構化的新聞與股市資料!

學習,實作,觀察 STEP3

ETL 第三步

學習,實作,觀察 STEP4

ETL 最後一步

資料整併

要處理的標的物有

  1. 房貸餘額匯總到每個月的資料
  2. GDP匯總到每年的資料
  3. 透過年份房貸餘額GDP的表結合起來

資料整併流程

資料彙總

將介紹 group_by, summarize

練習-資料彙總(1/2)

group_by 用來將資料包裝成一組,做後續的彙總

summarise則用來做後續的各類彙總操作

Cl_info_part3 = group_by(Cl_info_part2,time)  #先匯總
Cl_info_part4 = summarise(Cl_info_part3,
        mortage_total_bal = sum(mortgage_bal, na.rm = TRUE))

  • 第一個參數為輸入的 data frame
  • 第二個欄位之後都是用來group by/summarise 的欄位

給熟悉SQL的使用者

select sum(mortgage_bal) as mortage_total_bal 
                        from Cl_info group by time ;

group by 可加先下也可不下,不下的情況是直對接全部資料做集匯總運算

練習-資料彙總(2/2)

  1. 將房貸餘額每個月的值算出來
  2. 將GDP每年的值算出來
GDP_part5 = filter(summarise(group_by(GDP_part4,year),GDP=sum(GDP)),is.na(year)==F)        

彙總函數 summarise

可以使用的函數如下所列

  • mean 平均值
  • sum 加總
  • n 計算個數 例如: A B B C 輸出4
  • n_distinct 計算不同物件的個數 例: A B B C 輸出3
  • max, min 最大或最小值
  • median 中位數

mean

請計算每月全體銀行餘額平均值(eg1)

n

請計算每個月有多少家銀行有房貸餘額(eg2)

n_distinct

請計算每年有多少家銀行有房貸餘額(eg3)

max

請計算每月單一銀行擁有的最多房貸餘額(eg4)

first, last

請計算每月房貸餘額排名第ㄧ的銀行(eg5)

複雜一點的函數

  • first 該群體第一個,可配合order_by 使用; first(x,order_by=y)
  • last 該群體最後一個,可配合order_by 使用; last(x,order_by=y)
  • nth 該群體的第n個,可配合order_by 使用; nth(x,10))

nth

請計算每月房貸餘額排名第2的銀行 (eg6)

練習題目- 解答(1/2)



eg1 =  summarise(group_by(Cl_info_part2,time) , 
         mortage_mean_bal = mean(mortgage_bal, na.rm = TRUE))

eg2_1 = filter(Cl_info_part2,mortgage_bal >0)
eg2_2 = summarise(group_by(eg2_1,time),count = n())

eg3_1 = filter(Cl_info_part2,mortgage_bal >0)
eg3_2 = mutate(eg3_1,year = format(time,"%Y"))
eg3_3 = summarise(group_by(eg3_2,year),count = n_distinct(bank_nm))

練習題目- 解答(2/2)

eg4 = summarise(group_by(Cl_info_part2,time),
       val = max(mortgage_bal))



eg5_1 = arrange(Cl_info_part2,time,desc(mortgage_bal))
eg5_2 =summarise(group_by(eg5_1,time),val = first(bank_nm))


eg6_1 = arrange(Cl_info_part2,time,desc(mortgage_bal))
eg6_2 = summarise(group_by(eg6_1,time),
          val = nth(bank_nm,2))

接下來比較難,真的!!!!

結合表格

  1. cbind 用來做 1-1 水平結合
  2. rbind 用來做 垂直結合
  3. left_join 用來做多對多 水平結合
  4. inner_join 用來做多對多 水平結合

看得懂在幹嘛嗎?

圖解結合表格

join講解前資料準備

接下來先從各類join開始說明

建立資料集

x=data.frame(c1 = c(1,1,2,3,4,5,5),
             c2 = c('A','B','C','D','E','F','G'))
y=data.frame(c1 = c(1,2,2,3,4,6,6),
             c2 = c('A','B','C','D','E','F','G'))

join講解前資料準備

接下來先從各類join開始說明

建立資料集

x=data.frame(c1 = c(1,1,2,3,4,5,5),
             c2 = c('A','B','C','D','E','F','G'))
y=data.frame(c1 = c(1,2,2,3,4,6,6),
             c2 = c('A','B','C','D','E','F','G'))

打入 View(x)View(y)應該會看見

dplyr 介紹 - left_join

參數by 指出以何欄位作為對照鍵值

透過先前創建的xy,以及交集的鍵值c1

ljxy = left_join(x,y,by="c1") #以X為主
ljyx = left_join(y,x,by="c1") #以Y為主

dplyr 介紹 - inner_join

inner_join 取出共有的鍵值

inner_join(x,y,by="c1")
##   c1 c2.x c2.y
## 1  1    A    A
## 2  1    B    A
## 3  2    C    B
## 4  2    C    C
## 5  3    D    D
## 6  4    E    E

實際問題 - 練習題

請問,這兩張表該怎麼結合比較好?

請問,這兩張表該怎麼結合比較好?用誰當第一參數?

  1. left_join Cl_Info_part4
  2. semi_join Cl_Info_part4
  3. left_join GDP_part5
  4. inner_join GDP_part5
  5. 其他

因為GDP_part5_所俱有的時間點較少,用這個當作主鍵是比較好的.

練習

  1. 將GDP與房貸餘額,透過1月的資訊整理起來
GDP_part6 = select(mutate(GDP_part5 ,                    
                   time = as.POSIXct(paste(year,'1','1',sep='-'))),time,GDP)
t1 = left_join(GDP_part6,Cl_info_part4,by="time")
t2 = filter(t1,is.na(mortage_total_bal)==FALSE)

看一下資料 View(t2)

最後一里路

接下來我們應該做(1/3) - 畫圖

see1 = filter(mutate(t2,ratio =mortage_total_bal/GDP),is.na(ratio)==FALSE)
  1. 畫圖
library(ggplot2)
ggplot(see1, aes(time, ratio))+geom_smooth(method="loess") +
  scale_size_area() +geom_point(aes(size = 20), alpha = 1/2) 

plot of chunk plotChunk

接下來我們應該做(2/3) - 解釋

利用解釋將圖想要表達的意思更清楚地傳達給觀眾

  1. 畫圖
  2. 解釋
  1. 09達到高峰,但之後房貸與GDP的比值平穩維持在37.5%
  2. GDP成長比率與房貸餘額幾乎成正比
  3. 從新聞顯示
    • 09年遺產稅調降, 許多人回來投資?炒房?
    • 10年開始打房政策
    • 如果加上房價所得比,還可以說什麼呢?

接下來我們應該做(3/3) - 報告

將所有的解釋與圖表包裝成一個故事,展現出來

  1. 畫圖
  2. 解釋
  3. 報告

Review

我們做了什麼?

  • 設定問題
  • 下載與讀入與整理
  • 整合資料
  • 畫圖
  • 解釋
  • 報告

額外延伸主題

自動化

  • 建立R Script
iris
iris_part <- iris[4:6,]
rownames(iris_part) <- c('a','c','d')
write.csv(iris_part,file="[想要的目錄]/GG.csv")
  • 儲存到特定位置下 假定叫做Script.R
  • 在terminal執行
R CMD BATCH [該檔案儲存位置]/Script.R
  • 可透過crontab定期執行

從網路讀檔案

  • 安裝套件
install.packages("RCurl")
library(RCurl)
  • 讀檔案 (非Windows)
DF = read.table(sep=",", header=TRUE,            
file= textConnection(
getURL("https://raw.githubusercontent.com/ntuaha/TWFS/master/db/cl_info_other.csv")
))
  • 讀檔案 (Windows)
DF = read.csv(sep=",", header=TRUE, 
file="https://raw.githubusercontent.com/ntuaha/TWFS/master/db/cl_info_other.csv",
fileEncoding="UTF-8")

Speical

Topics

  1. 自動化排程
  2. 與資料庫溝通
  3. 其他的資料源
    • 結構化資料
    • 非結構化資料
  4. 培養對資料的品味

Reference