1 課程目標

在統計分析中,我們經常需要處理大批資料,其中有許多變數,當我們對符合某些條件的資料感興趣時,除了比照過去的作法針對資料中的變數進行統計,也可以考慮轉換資料。又例如我們進行實驗研究,受訪者分配到實驗組與控制組,我們可以參考 Hadley Wickham (http://www.jstatsoft.org/v59/i10/paper) 將結果紀錄為:

Subject treatment result
1001 a 20
1002 a 25
1003 a 10
1001 b 18
1002 b 31
1003 b 16

Table 1可以很快地分析a, b兩組實驗結果的平均值,進而比較差異。

tmp <- tibble(Subject=c(1001,1002,1003,1001,1002,1003),
              treatment=c('a','a','a','b','b','b'),
             result=c(20,25,10,18,31,16))
tmp %>% 
     group_by(treatment) %>%
     summarize(outcome=mean(result))
## # A tibble: 2 x 2
##   treatment outcome
##   <chr>       <dbl>
## 1 a            18.3
## 2 b            21.7

相反的,如果是以下的Table 2,很難分析兩組實驗之間的差異:

Subject 1001 1002 1003
treatmenta 20 25 10
treatmentb 18 31 16

配合上述的資料轉置,本週上課將介紹Rdplyr的套件中的指令,包括selectfiltermutate等函數,協助研究者統計資料。例如建立一個新的變數:

library(dplyr)
students<-read.table('studentsfull.txt', sep='', header=TRUE)
students.part<-mutate(students, sex=as.numeric(Gender)-1)
students.part
##          ID     Name Department Score Gender sex
## 1  10322011    Ariel  Aerospace    78      F   0
## 2  10325023    Becky    Physics    86      F   0
## 3  10430101     Carl Journalism    69      M   1
## 4  10401032  Dimitri    English    83      M   1
## 5  10307120  Enrique  Chemistry    80      M   1
## 6  10207005 Fernando  Chemistry    66      M   1
## 7  10305019   George  Mechanics    75      F   0
## 8  10305022   Howell  Mechanics    81      M   1
## 9  10305029      Ian  Mechanics    60      M   1
## 10 10305031    Julio  Mechanics    89      M   1
## 11 10322014    Kaori  Aerospace    82      F   0
## 12 10425026     Luke    Physics    88      M   1
## 13 10401022   Miguel    English    92      M   1
## 14 10501006      Neo    English    77      M   1
## 15 10321010   Olivia  Economics    85      F   0
## 16 10321011    Peter  Economics    88      M   1
## 17 10405017     Qing  Mechanics    88      F   0
## 18 10422007    Ricky  Aerospace    91      M   1
## 19 10422008    Seiko  Aerospace    80      F   0
## 20 10430005  Terresa Journalism    62      F   0
## 21 10530009     Usla Journalism    87      F   0
## 22 10421001   Vivian  Economics    70      F   0
## 23 10307018    Wendy  Chemistry    85      F   0
## 24 10425003     Xing    Physics    93      M   1
## 25 10221030     Yoko  Economics    66      F   0
## 26 10430015      Zoe Journalism    92      F   0

2 資料的型態

之前我們學習R的基礎指令,而dplyr提供許多指令幫我們整理資料。Hadley Wickman 發展了plyr套件,然後又發展dplyr套件。為了節省時間,我們直接討論dplyr的幾個實用的函數。

2.1 tibble

在下載dplyr套件之後,請嘗試這個指令:

library(dplyr)
tibble(
  s=c("all","at","air","age", "angle"),
  x = 1:5, 
  y = 1, 
  z = x  + y,
  )
## # A tibble: 5 x 4
##   s         x     y     z
##   <chr> <int> <dbl> <dbl>
## 1 all       1     1     2
## 2 at        2     1     3
## 3 air       3     1     4
## 4 age       4     1     5
## 5 angle     5     1     6

或者是:

data_frame(s=c("all","at","air","age", "angle"), x = 1:5, y = 1, z = x  + y)
## # A tibble: 5 x 4
##   s         x     y     z
##   <chr> <int> <dbl> <dbl>
## 1 all       1     1     2
## 2 at        2     1     3
## 3 air       3     1     4
## 4 age       4     1     5
## 5 angle     5     1     6

這兩個表格顯示tibble表格的彈性,不需要像資料框(data.frame)需要那麼多向量。

tibble是一個新的資料型態,比資料框多了變數的資訊,而且會顯示前面十個觀察值的資訊,以及螢幕剛好足夠容納的下的變數。例如打開TEDS2016_indQE(CSES).sav這個檔案,但是把它視為tibble而不是data.frame:

library(foreign)
teds2016<-read.spss('TEDS2016_indQE(CSES).sav', to.data.frame=TRUE)
## re-encoding from CP950
as_tibble(teds2016)
## # A tibble: 1,690 x 80
##         A1     A2 A3    A4a   A4b   A4c      A5 A6    Q1    Q2    Q3   
##      <dbl>  <dbl> <fct> <fct> <fct> <fct> <dbl> <fct> <fct> <fct> <fct>
##  1 1.02e12 1.61e5 Male  Feb   20    2016  1.04  Mand… Not … Fair… Disa…
##  2 1.02e12 1.61e5 Male  Feb   22    2016  1.16  Mand… Not … Fair… Neit…
##  3 1.02e12 1.61e5 Male  Jan   31    2016  0.643 Mand… Not … Very… Agree
##  4 1.02e12 1.61e5 Male  Feb   2     2016  1.20  Mand… Not … Fair… Disa…
##  5 1.02e12 1.61e5 Male  Feb   3     2016  0.768 Mand… Not … Not … Don'…
##  6 1.02e12 1.61e5 Male  Feb   2     2016  1.25  Mand… Not … Not … Disa…
##  7 1.02e12 1.61e5 Male  Feb   19    2016  0.676 Taiw… Some… Not … Don'…
##  8 1.02e12 1.61e5 Male  Feb   3     2016  0.793 Mand… Some… Fair… Agree
##  9 1.02e12 1.60e6 Male  Jan   21    2016  0.768 Taiw… Not … Not … Don'…
## 10 1.02e12 1.60e6 Male  Jan   21    2016  0.734 Mand… Not … Not … Disa…
## # ... with 1,680 more rows, and 69 more variables: Q4a <fct>, Q4b <fct>,
## #   Q4c <fct>, Q4d <fct>, Q4e <fct>, Q4f <fct>, Q4g <fct>, Q4h <fct>,
## #   Q5a <fct>, Q5b <fct>, Q5c <fct>, Q6a <fct>, Q6b <fct>, Q6c <fct>,
## #   Q6d <fct>, Q6e <fct>, Q6f <fct>, Q6g <fct>, Q7 <fct>, Q8 <fct>,
## #   Q9 <fct>, Q10a <fct>, Q10b <fct>, Q11 <fct>, Q12P1a <fct>,
## #   Q12P1b <fct>, Q12LHa <fct>, Q12LHb <fct>, Q12LHc <fct>, Q13a <fct>,
## #   Q13b <fct>, Q13c <fct>, Q14 <fct>, Q15a <fct>, Q15b <fct>, Q15c <fct>,
## #   Q15d <fct>, Q15e <fct>, Q16a <fct>, Q16b <fct>, Q16c <fct>,
## #   Q19a <fct>, Q19b <fct>, Q19c <fct>, Q19d <fct>, Q19e <fct>, Q20 <fct>,
## #   Q21 <fct>, Q22a <fct>, Q22b <fct>, Q22c <fct>, Q22d <fct>, D1b <fct>,
## #   D2 <fct>, D3 <fct>, D4 <fct>, D5 <fct>, D6 <fct>, D7 <fct>, D8 <fct>,
## #   D9 <fct>, D10 <fct>, D11 <fct>, D13 <fct>, D14 <fct>, D15 <fct>,
## #   D16 <fct>, D17 <fct>, D18 <fct>

這筆資料來自於台灣選舉與民主化調查(http://teds.nccu.edu.tw/main.php)。可以看出tibble比較適用於大量的資料,讓資料分析更加容易。

而tibble格式的資料子集合可以是該變數的格式,也可以是資料框,可以用參數drop加以控制。例如:

class(teds2016[,1])
## [1] "numeric"
class(teds2016[,1, drop=TRUE])
## [1] "numeric"

2.1.1 簡潔數據(tidy dataset)

那麼,tibble的用處是什麼?tibble 來自於Hadley Wickham 發展的簡潔數據(tidy dataset)概念,簡潔數據的目標是讓每一個變數都有一個欄位(每一欄都是一個變數),而且每一筆觀察值都有一列,而且每一個值都有一儲存格(也就是每一個儲存格只有一個值,沒有例如\(a/b\)是由兩個值所構成)。詳見Garrett Grolemund & Hadley Wicham (http://r4ds.had.co.nz/index.html)。 tidy dataset也希望資料在同一個表,而非來自於不同的表。
雖然以下的指令適用於資料框以及整潔數據,但是整潔數據方便大數據分析。例如我們想要pp0797b2這筆資料加權之後的性別統計:

teds2016 %>% 
  count(D2)
## # A tibble: 2 x 2
##   D2         n
##   <fct>  <int>
## 1 Male     868
## 2 Female   822

Hadley Wickham也是ggplot2的作者,因此tibble資料適合於ggplot2的視覺化,例如我們想呈現性別的分佈,不一定用得到tibble:

library(ggplot2)
ggplot(teds2016, aes(x=D2)) +
  geom_bar(stat='count', fill='steelblue') +
  theme(text=element_text(family="HanWangMingBold", size=14))

但是要呈現兩個變數之間的聯合機率的次數,我們需要計算兩個變數的每一個類別的交叉,然後可以更容易使用ggplot2。例如我們想知道不同性別的受訪者是否參與工會:

df.union<-teds2016 %>%
      group_by(D2) %>%
      count(D5)
df.union
## # A tibble: 6 x 3
## # Groups:   D2 [2]
##   D2     D5                               n
##   <fct>  <fct>                        <int>
## 1 Male   R is member of a union         200
## 2 Male   R is not a member of a union   664
## 3 Male   Don't know                       4
## 4 Female R is member of a union         164
## 5 Female R is not a member of a union   651
## 6 Female Don't know                       7

在這個例子中: - 就性別分組,然後計算有無加入工會的個案數 - 上述指令中的%>%被稱為pipeline或者是pipe operator,有點像是兩行指令之間的連結,可執行多行指令,讓語法看起來更簡潔。

接下來用tibble格式的df.union 畫直方圖:

g<-ggplot(df.union, aes(D2, n, fill=D5)) +
  geom_bar(stat='identity') +
  theme(text=element_text(size=14))
g

由此可以看出,tibble資料以及dplyr的指令可以直覺式地處理資料。

我們也可以計算每一個交叉細格的條件機率:

df.union<-teds2016 %>%
      group_by(D2) %>%
      count(D5) %>%
      mutate(N=sum(n)) %>%
      mutate(pct=100*n/N)
df.union
## # A tibble: 6 x 5
## # Groups:   D2 [2]
##   D2     D5                               n     N    pct
##   <fct>  <fct>                        <int> <int>  <dbl>
## 1 Male   R is member of a union         200   868 23.0  
## 2 Male   R is not a member of a union   664   868 76.5  
## 3 Male   Don't know                       4   868  0.461
## 4 Female R is member of a union         164   822 20.0  
## 5 Female R is not a member of a union   651   822 79.2  
## 6 Female Don't know                       7   822  0.852

然後按照上述方式畫圖,即可得到性別與參與工會的堆疊圖:

g<-ggplot(df.union, aes(D2, pct, fill=D5)) +
  geom_bar(stat='identity') +
  theme(text=element_text(size=14))
g

2.2 資料子集合

tibble的子集合跟資料框有一些不同,例如:

df <- tibble(
  x = runif(5),
  y = rnorm(5),
  z = 4
)
df
## # A tibble: 5 x 3
##       x      y     z
##   <dbl>  <dbl> <dbl>
## 1 0.624  0.621     4
## 2 0.254 -0.492     4
## 3 0.176 -0.258     4
## 4 0.704 -0.893     4
## 5 0.749 -0.209     4

子集合的方式有好幾種:

  df$x
## [1] 0.6239356 0.2536799 0.1756172 0.7038229 0.7491670
  df[['x']]
## [1] 0.6239356 0.2536799 0.1756172 0.7038229 0.7491670
  df[,"z"]
## # A tibble: 5 x 1
##       z
##   <dbl>
## 1     4
## 2     4
## 3     4
## 4     4
## 5     4

重新命名變數名稱,新的變數名稱在前面:

df2 <- df %>%
  rename(
    v1=x, v2=y, 'group'=z
  )
df2
## # A tibble: 5 x 3
##      v1     v2 group
##   <dbl>  <dbl> <dbl>
## 1 0.624  0.621     4
## 2 0.254 -0.492     4
## 3 0.176 -0.258     4
## 4 0.704 -0.893     4
## 5 0.749 -0.209     4

以下我們運用tibble來處理資料。

3 非摘要式指令

dplyr指令可以產生新的變數,也可以產生統計的結果。首先介紹轉換資料但是不產生統計摘要(例如平均值、最小值、最大值等等)結果的指令。

3.1 挑選特定欄位(select)

在一個二維的資料型態,假設我們想留下部分欄位的資料,捨棄其他欄位,可以用select這個函數。例如:

library(dplyr)
dt <- tibble(
  s=c("B", "B", "A","B","A","C", "B", "B","B", "B", "A","B","A","C", "B", "B"),
  x = 1:16, 
  y = 1, 
  z = x  + 2*y,
  )
dt %>% select(z, s)
## # A tibble: 16 x 2
##        z s    
##    <dbl> <chr>
##  1     3 B    
##  2     4 B    
##  3     5 A    
##  4     6 B    
##  5     7 A    
##  6     8 C    
##  7     9 B    
##  8    10 B    
##  9    11 B    
## 10    12 B    
## 11    13 A    
## 12    14 B    
## 13    15 A    
## 14    16 C    
## 15    17 B    
## 16    18 B

3.2 過濾(filter)

filter可以篩選符合條件的變數的觀察值,篩選的變數可以超過一個,例如:

Orange %>% filter (age >1000, circumference > 100)
##    Tree  age circumference
## 1     1 1004           115
## 2     1 1231           120
## 3     1 1372           142
## 4     1 1582           145
## 5     2 1004           156
## 6     2 1231           172
## 7     2 1372           203
## 8     2 1582           203
## 9     3 1004           108
## 10    3 1231           115
## 11    3 1372           139
## 12    3 1582           140
## 13    4 1004           167
## 14    4 1231           179
## 15    4 1372           209
## 16    4 1582           214
## 17    5 1004           125
## 18    5 1231           142
## 19    5 1372           174
## 20    5 1582           177

類別變數或者是數字變數都可以篩選觀察值。

3.3 創造新變數(mutate)

我們可以直接在資料中創造一個新變數,不需要再用錢字符號($),並且轉換資料型態,例如:

dt_mutate <- mutate(dt, S=as.factor(s), X=x*100)
dt_mutate <- mutate(dt_mutate, sn=as.numeric(S))
dt_mutate
## # A tibble: 16 x 7
##    s         x     y     z S         X    sn
##    <chr> <int> <dbl> <dbl> <fct> <dbl> <dbl>
##  1 B         1     1     3 B       100     2
##  2 B         2     1     4 B       200     2
##  3 A         3     1     5 A       300     1
##  4 B         4     1     6 B       400     2
##  5 A         5     1     7 A       500     1
##  6 C         6     1     8 C       600     3
##  7 B         7     1     9 B       700     2
##  8 B         8     1    10 B       800     2
##  9 B         9     1    11 B       900     2
## 10 B        10     1    12 B      1000     2
## 11 A        11     1    13 A      1100     1
## 12 B        12     1    14 B      1200     2
## 13 A        13     1    15 A      1300     1
## 14 C        14     1    16 C      1400     3
## 15 B        15     1    17 B      1500     2
## 16 B        16     1    18 B      1600     2

3.4 排序(arrange)

我們可以根據某一個或者一個以上的變數遞增或是遞減排序資料,例如:

dt_arrange = arrange(dt, s, desc(z))
dt_arrange
## # A tibble: 16 x 4
##    s         x     y     z
##    <chr> <int> <dbl> <dbl>
##  1 A        13     1    15
##  2 A        11     1    13
##  3 A         5     1     7
##  4 A         3     1     5
##  5 B        16     1    18
##  6 B        15     1    17
##  7 B        12     1    14
##  8 B        10     1    12
##  9 B         9     1    11
## 10 B         8     1    10
## 11 B         7     1     9
## 12 B         4     1     6
## 13 B         2     1     4
## 14 B         1     1     3
## 15 C        14     1    16
## 16 C         6     1     8

排序的時候需要注意該變數是否已經設定順序。例如Orange資料中的Tree已經排序過,得到的排序結果不會如我們預期:

class(Orange$Tree)
## [1] "ordered" "factor"
Orange %>% arrange (Tree, age)
##    Tree  age circumference
## 1     3  118            30
## 2     3  484            51
## 3     3  664            75
## 4     3 1004           108
## 5     3 1231           115
## 6     3 1372           139
## 7     3 1582           140
## 8     1  118            30
## 9     1  484            58
## 10    1  664            87
## 11    1 1004           115
## 12    1 1231           120
## 13    1 1372           142
## 14    1 1582           145
## 15    5  118            30
## 16    5  484            49
## 17    5  664            81
## 18    5 1004           125
## 19    5 1231           142
## 20    5 1372           174
## 21    5 1582           177
## 22    2  118            33
## 23    2  484            69
## 24    2  664           111
## 25    2 1004           156
## 26    2 1231           172
## 27    2 1372           203
## 28    2 1582           203
## 29    4  118            32
## 30    4  484            62
## 31    4  664           112
## 32    4 1004           167
## 33    4 1231           179
## 34    4 1372           209
## 35    4 1582           214
Orange %>% mutate(tree=factor(Tree, levels=c('1','2','3','4','5'))) %>%
                    arrange (desc(tree), age)
##    Tree  age circumference tree
## 1     5  118            30    5
## 2     5  484            49    5
## 3     5  664            81    5
## 4     5 1004           125    5
## 5     5 1231           142    5
## 6     5 1372           174    5
## 7     5 1582           177    5
## 8     4  118            32    4
## 9     4  484            62    4
## 10    4  664           112    4
## 11    4 1004           167    4
## 12    4 1231           179    4
## 13    4 1372           209    4
## 14    4 1582           214    4
## 15    3  118            30    3
## 16    3  484            51    3
## 17    3  664            75    3
## 18    3 1004           108    3
## 19    3 1231           115    3
## 20    3 1372           139    3
## 21    3 1582           140    3
## 22    2  118            33    2
## 23    2  484            69    2
## 24    2  664           111    2
## 25    2 1004           156    2
## 26    2 1231           172    2
## 27    2 1372           203    2
## 28    2 1582           203    2
## 29    1  118            30    1
## 30    1  484            58    1
## 31    1  664            87    1
## 32    1 1004           115    1
## 33    1 1231           120    1
## 34    1 1372           142    1
## 35    1 1582           145    1

4 摘要式指令

4.1 摘要(summarize)

我們可以直接輸出某一個變數的統計結果:

summarize(dt, mean(x))
## # A tibble: 1 x 1
##   `mean(x)`
##       <dbl>
## 1       8.5

或者是轉成另一個變數,方便後續的分析,但是dplyr會存成一個tibble資料,所以需要再取出:

dt.sze=summarize(dt, x.avg=mean(x), z.avg=mean(z))
dt.sze[,1]
## # A tibble: 1 x 1
##   x.avg
##   <dbl>
## 1   8.5
dt.sze[,2]
## # A tibble: 1 x 1
##   z.avg
##   <dbl>
## 1  10.5

summarize可以計算的統計有:

  • mean,平均值
  • median,中位數
  • sum,總數
  • min,最小值
  • max,最大值
  • n(),個數,也就是資料筆數
  • n_distinct,類別的個數

(請見DSC2014tutorial)
例如我們想要知道mtcars這筆資料中cyl的個數、平均數跟類別的數目:

mtcars_n<-summarize(mtcars, n(), mean(cyl), n_distinct(cyl))

4.2 資料彙總(group_by)

我們可以根據資料內的類別變數對另一個變數進行統計,例如計算平均值,使用group_by()這個函數:

summarize(group_by(dt, s),  mean(z))
## # A tibble: 3 x 2
##   s     `mean(z)`
##   <chr>     <dbl>
## 1 A          10  
## 2 B          10.4
## 3 C          12

又例如我們想分析不同科系的學生成績:

st <- read.table('studentsfull.txt', header=T)
score.report <-  st %>%
          group_by(Department) %>%
          summarize(Avg=mean(Score)) %>%
          arrange (Department)
score.report
## # A tibble: 7 x 2
##   Department   Avg
##   <fct>      <dbl>
## 1 Aerospace   82.8
## 2 Chemistry   77  
## 3 Economics   77.2
## 4 English     84  
## 5 Journalism  77.5
## 6 Mechanics   78.6
## 7 Physics     89

在上面例子中:

  • 創造一個新的資料score.report
  • 創造一個變數Avg代表平均成績
  • 按照系名排列成績

如果資料內有遺漏值,可以設定na.rm這個參數為真,去除遺漏值,再進行統計,例如以flights這筆資料為例,根據tailnum也就是班機號碼,彙總計算班機次數以及距離:

library(nycflights13)
by_tailnum <- group_by(flights, tailnum)
delay <- summarise(by_tailnum,
  count = n(),
  dist = mean(distance, na.rm = TRUE))
delay
## # A tibble: 4,044 x 3
##    tailnum count  dist
##    <chr>   <int> <dbl>
##  1 D942DN      4  854.
##  2 N0EGMQ    371  676.
##  3 N10156    153  758.
##  4 N102UW     48  536.
##  5 N103US     46  535.
##  6 N104UW     47  535.
##  7 N10575    289  520.
##  8 N105UW     45  525.
##  9 N107US     41  529.
## 10 N108UW     60  534.
## # ... with 4,034 more rows

或者是(參考:https://dplyr.tidyverse.org/articles/dplyr.html ):

flights %>% group_by(tailnum) %>%
  summarize(count=n(), avgdist=mean(distance, na.rm=TRUE))
## # A tibble: 4,044 x 3
##    tailnum count avgdist
##    <chr>   <int>   <dbl>
##  1 D942DN      4    854.
##  2 N0EGMQ    371    676.
##  3 N10156    153    758.
##  4 N102UW     48    536.
##  5 N103US     46    535.
##  6 N104UW     47    535.
##  7 N10575    289    520.
##  8 N105UW     45    525.
##  9 N107US     41    529.
## 10 N108UW     60    534.
## # ... with 4,034 more rows

以上的說明希望大家活用dplyr,進行統計,並且結合資料視覺化。


5 資料的寬表與長表(reshape2)

dplyr提供了許多轉換資料以及彙總計算的功能,而針對資料的轉換,reshape2套件有很大的幫助。reshape2也是由 Hadley Wickham所寫,該套件裡最重要的兩個函數便是 melt() 與 dcast(),如同字面上的意思,melt 是熔化的意思,也就是將資料由多變數熔成較少變數且較長的資料,可以想像資料變長;cast 是鑄造的意思,也就是將資料由較少變數鑄造成較多變數且較寬的資料,可以想像資料變短。cast 有分 dcast 與 acast,只差在要輸出的形式是 data.frame 或是 array。(以上文字參考:https://blog.stranity.com.tw/2016/12/12/r語言reshape2套件/

5.1 寬表(dcast)

將資料由少變數變形為較寬的資料,在過程中可以加上函數。例如有一筆資料表示銀行的房貸金額,我們先讀取資料,過程中擷取年份與月份:

library(DSC2014Tutorial)
ETL_file("cl_info_other.csv")
## [1] "/Library/Frameworks/R.framework/Versions/3.5/Resources/library/DSC2014Tutorial/ETL/cl_info_other_unix.csv"
bank.info = read.table(file=ETL_file("cl_info_other.csv"),sep=",",stringsAsFactors=F,header=T)
bank.part=mutate(bank.info,
                 bank_code = as.factor(bank_code),
                 etl_dt = substr(etl_dt, 1, 7))

bank.part=mutate(bank.part, yearmonth=format(etl_dt, format='%Y-%m'))
    稍微選取變數方便觀察資料
bank.part<-select(bank.part, bank_nm, yearmonth, mortgage_bal)
head(bank.part)
##                    bank_nm yearmonth mortgage_bal
## 1         日商瑞穗實業銀行   2013-11   0.0000e+00
## 2 台北縣淡水第一信用合作社   2013-11   1.6873e+10
## 3             萬泰商業銀行   2013-11   5.6240e+09
## 4     台中市第二信用合作社   2013-11   1.8949e+10
## 5     基隆市第二信用合作社   2013-11   3.7730e+09
## 6       高雄第三信用合作社   2013-11   2.4760e+09
    (指令參考:DSC2014Tutorial套件的說明,請先安裝該套件,並且輸入slides(‘ETL1’)。如果有問題請參考授課大綱。)

然後就銀行名稱(bank_nm)以及年度月份(yearmonth)轉形為寬表,可顯示銀行名稱、每一個時間點的銀行貸款總額(為了顯示方便,銀行貸款一律除以10億):

library(reshape2)
bank.part$mortgage_bal.new=bank.part$mortgage_bal/10e+9
wtable<-dcast(bank.part, bank_nm ~ yearmonth,  value.var=c('mortgage_bal.new'), sum)
wtable
##                      bank_nm   2013-11  2013-12  2014-01  2014-04 2014-05
## 1               安泰商業銀行  455.8923  20.3757  15.2651  10.1400  5.0763
## 2               澳商澳盛銀行   39.6716   0.0000   4.7207   0.0000  0.0000
## 3         澳商澳洲紐西蘭銀行    0.0154   0.0000   0.0000   0.0000  0.0000
## 4                       澳盛    8.6770  12.9826   3.4501   7.1376  3.5712
## 5               板信商業銀行  330.0505  10.2763   8.2238   5.1035  2.5702
## 6               寶華商業銀行   52.4839   0.0000   0.0000   0.0000  0.0000
## 7     比利時商比利時聯合銀行    0.1566   0.0000   0.0000   0.0000  0.0000
## 8           比利時商富通銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 9             大陸商交通銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 10        大陸商中國建設銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 11            大陸商中國銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 12            大台北商業銀行   52.8824   3.0092   2.5724   0.0000  0.0000
## 13              大眾商業銀行  671.4575  37.2538  28.5782  18.7963  9.4068
## 14        淡水第一信用合作社   64.7933   9.7628   7.1920   5.1138  2.5813
## 15              稻江商業銀行   14.9729   0.0000   0.0000   0.0000  0.0000
## 16            德商德意志銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 17              第七商業銀行   12.9705   0.0000   0.0000   0.0000  0.0000
## 18              第一商業銀行 2164.1011 116.9979  86.9194  58.4418 29.2921
## 19          法國東方匯理銀行    0.0858   0.0000   0.0000   0.0000  0.0000
## 20              法國興業銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 21          法商法國巴黎銀行    0.6860   0.0024   0.0018   0.0012  0.0006
## 22              法商佳信銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 23            菲律賓首都銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 24              斐商標準銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 25        高雄第二信用合作社   17.3308   0.0000   0.0000   0.0000  0.0000
## 26        高雄第三信用合作社   55.6903   0.0000   0.0000   0.0000  0.0000
## 27      高雄市第三信用合作社   24.8881   2.8013   2.1591   1.6027  0.7962
## 28                  高雄銀行  292.3132  12.5998   9.2073   6.6557  3.3527
## 29          國泰世華商業銀行 2223.2194 102.0286  78.8050  51.0160 25.5519
## 30          合作金庫商業銀行 3767.5942 169.3300 134.3408  88.9293 44.6074
## 31              合作金庫銀行  111.2887   0.0000   0.0000   0.0000  0.0000
## 32            荷蘭商安智銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 33              荷商安銀銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 34        花蓮第二信用合作社  121.8997   4.8504   3.5344   2.4755  1.2451
## 35        花蓮第一信用合作社   61.0537   3.8185   2.7883   1.8716  0.9289
## 36                      花旗  390.1259  32.9079  24.3761  17.1927  8.5963
## 37              華南商業銀行 2576.4859 158.3480 118.3445  79.1740 39.6014
## 38              華泰商業銀行  120.0937   5.5938   3.9813   2.5195  1.2510
## 39        基隆第一信用合作社   23.5140   3.6329   2.6218   1.9136  0.9598
## 40      基隆市第二信用合作社   44.7062   3.0869   2.3235   1.7251  0.8534
## 41      基隆市第一信用合作社   42.0648   0.0000   0.0000   0.0000  0.0000
## 42          加拿大商豐業銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 43      嘉義巿第四信用合作社    1.0601   0.0000   0.0000   0.0000  0.0000
## 44      嘉義市第三信用合作社   15.8956   1.4514   1.0487   0.7396  0.3728
## 45              建華商業銀行  172.4026   0.0000   0.0000   0.0000  0.0000
## 46                  交通銀行   35.9057   0.0000   0.0000   0.0000  0.0000
## 47          金門縣信用合作社    3.1091   0.3467   0.2311   0.1838  0.0928
## 48              京城商業銀行  184.8479   6.1705   4.4346   3.3029  1.6557
## 49              聯邦商業銀行  562.6416  23.2065  17.1469  11.7545  5.8939
## 50              美國運通銀行    0.0005   0.0000   0.0000   0.0000  0.0000
## 51              美商道富銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 52              美商富國銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 53              美商花旗銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 54          美商加州聯合銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 55      美商美國紐約梅隆銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 56          美商美國紐約銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 57              美商美國銀行    0.0314   0.0000   0.0000   0.0000  0.0000
## 58              美商美聯銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 59          美商摩根大通銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 60      苗栗縣竹南信用合作社   21.3096   0.0000   0.0000   0.0000  0.0000
## 61        澎湖第二信用合作社    5.1287   0.8407   0.6071   0.4191  0.2132
## 62      澎湖縣第二信用合作社    5.7510   0.0000   0.0000   0.0000  0.0000
## 63      澎湖縣第一信用合作社    2.8879   0.1763   0.1185   0.0907  0.0455
## 64          日商瑞穗實業銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 65              日商瑞穗銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 66          日商三井住友銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 67      日商三菱東京日聯銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 68          日盛國際商業銀行  414.1284  16.4723  12.2290   8.4252  4.2223
## 69        瑞士商瑞士信貸銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 70            瑞士商瑞士銀行    0.6944   0.0424   0.0330   0.0212  0.0106
## 71              瑞興商業銀行    0.0000   1.0222   1.0179   2.0400  1.0211
## 72              三信商業銀行  156.5468   7.4360   5.5540   3.7230  1.8631
## 73          上海商業儲蓄銀行  854.4311  45.8736  34.0033  23.7441 11.8944
## 74              台北富邦銀行 2162.6112 112.9597  84.0778  57.5957 28.7917
## 75      台北市第九信用合作社   26.2689   2.5787   1.8887   1.2268  0.6156
## 76      台北市第五信用合作社   26.4813   1.6851   1.2204   0.8773  0.4431
## 77      台北市第一信用合作社   15.9363   0.0000   0.0000   0.0000  0.0000
## 78  台北縣淡水第一信用合作社  111.7306   0.0000   0.0000   0.0000  0.0000
## 79      台北縣淡水信用合作社   20.4316   0.4531   0.4405   0.0000  0.0000
## 80        台南第六信用合作社    0.0000   0.0000   0.0000   0.0000  0.0000
## 81        台南第三信用合作社   37.0272   2.8486   2.0862   1.4591  0.7347
## 82          台新國際商業銀行 1797.0183  86.2433  65.5713  43.9081 22.0041
## 83              台中商業銀行  225.6101  20.8217  14.8320  11.0376  5.5510
## 84      台中市第二信用合作社  137.3252   5.1242   3.7208   2.6652  1.3267
## 85        臺南區中小企業銀行   10.6257   0.0000   0.0000   0.0000  0.0000
## 86              臺灣工業銀行    0.0239   0.0000   0.0000   0.0000  0.0000
## 87              臺灣土地銀行 4726.7059 246.4167 184.5319 127.5156 64.0046
## 88          臺灣新光商業銀行  593.9176  40.1682  29.7785  21.0930 10.5613
## 89                  臺灣銀行 2738.6589 171.2308 123.4089  89.4212 44.7856
## 90          臺灣中小企業銀行 1245.4765  55.6679  41.1375  27.9560 14.0726
## 91              臺中商業銀行  168.1371   0.0000   0.0000   0.0000  0.0000
## 92              泰國盤谷銀行    0.0048   0.0000   0.0000   0.0000  0.0000
## 93            桃園信用合作社   21.6680   1.0406   0.6054   0.5628  0.2889
## 94              萬泰商業銀行   78.5559   9.5962   6.7137   4.8711  2.4440
## 95    西班牙商西班牙對外銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 96              香港東亞銀行    0.0096   0.0000   0.0000   0.0000  0.0000
## 97          香港上海匯豐銀行  338.4479   0.0000   0.0000   0.0000  0.0000
## 98      新北市淡水信用合作社    0.0000   0.4412   0.2242   0.4570  0.2283
## 99            新加坡大華銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 100   新加坡商新加坡華僑銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 101         新加坡商星展銀行   76.7716   0.0000   0.0000   0.0000  0.0000
## 102       新竹第三信用合作社   17.5981   2.8885   2.0264   1.4001  0.7017
## 103       新竹第一信用合作社   28.7734   4.8625   3.6611   2.5519  1.3054
## 104         新竹國際商業銀行  163.9289   0.0000   0.0000   0.0000  0.0000
## 105     新竹市第三信用合作社   30.3709   0.0000   0.0000   0.0000  0.0000
## 106     新竹市第一信用合作社   47.3216   0.0000   0.0000   0.0000  0.0000
## 107                     星展   54.7337  16.3461  11.4036   8.4414  4.2310
## 108             陽信商業銀行  434.9034  16.7865  12.8226   7.9943  4.0000
## 109             宜蘭信用合社   10.0521   0.0000   0.1415   0.0000  0.0000
## 110           宜蘭信用合作社    0.9360   0.8064   0.3497   0.4507  0.2309
## 111           英商巴克萊銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 112             英商渣打銀行   16.4841   0.0000   0.0000   0.0000  0.0000
## 113             永豐商業銀行 2068.4916  90.6752  67.6777  44.2109 22.0346
## 114             玉山商業銀行 1514.4453  83.4300  61.3086  40.9703 20.4765
## 115             元大商業銀行  449.6893  35.2202  24.8519  18.1559  9.1095
## 116         遠東國際商業銀行  820.8375  44.3036  32.6891  21.8612 10.9321
## 117         渣打國際商業銀行  990.2054  64.2683  47.9260  32.0244 16.1259
## 118       彰化第六信用合作社   49.2319   2.9499   2.1565   1.5759  0.7850
## 119       彰化第十信用合作社   12.1791   1.1159   0.7626   0.5754  0.2882
## 120       彰化第五信用合作社    8.0686   0.6685   0.4041   0.3725  0.1880
## 121       彰化第一信用合作社   13.5215   1.2920   0.9367   0.6600  0.3250
## 122             彰化商業銀行 1526.2329  94.9249  72.1288  48.6897 24.3888
## 123     彰化縣鹿港信用合作社   26.2948   2.4027   1.7475   1.2220  0.6130
## 124         兆豐國際商業銀行 1368.9686  74.8504  52.3233  41.5007 20.8362
## 125         中國國際商業銀行   57.8369   0.0000   0.0000   0.0000  0.0000
## 126           中國輸出入銀行    0.0000   0.0000   0.0000   0.0000  0.0000
## 127         中國信託商業銀行 2483.0095 126.2968  90.6653  65.1645 32.7264
## 128         中華開發工業銀行    0.0338   0.0000   0.0000   0.0000  0.0000
## 129           竹南信用合作社    2.4617   0.0000   0.0000   0.0000  0.0000

sum可以替代為length()以及mean()。雖然寬表提供一些統計功能,也方便我們閱讀,但是無法視覺化寬表的資料。所以我們用melt轉形資料。

5.2 長表(melt)

長表無法彙總資料,但是可以轉置資料,讓每一筆資料對應一個觀察值,而不是對應超過一個觀察值。我們先用上述的寬表,轉置為長表:

colnames(wtable)<-c("bank_nm","time1","time2","time3","time4","time5")
bank.melt=melt(wtable, id.vars=c('bank_nm'))

接下來用ggplot2進行視覺化,目標是顯示每一個銀行在五個時間點的貸款總額變化:

library(ggplot2)
#complete
p=ggplot(bank.melt, aes(x=variable, y=value, group=bank_nm, color=bank_nm)) +
  geom_line(stat="identity") +
  theme(axis.text.x=element_text(family="msjh", size=10)) +
  scale_x_discrete(labels = c("2013-11", "2013-12", "2014-01", "2014-04", "2014-05")) +
    theme_bw()

因為原始資料之中有100多家銀行在五個時間點的資料,為了容易觀察起見,我們只繪圖三家銀行,首先隨機抽出三家銀行:

#-------------------------------------------------
#partial: 3 banks
set.seed(02139)
bankname<-unique(bank.melt$bank_nm)
r<-sample(c(1:length(bankname)), size=3, replace=F)
bankname.r <- bankname[r]
bankname.r
## [1] "大台北商業銀行"     "大陸商交通銀行"     "新竹第三信用合作社"

接下來畫圖:

bank.r<-bank.melt[which(bank.melt$bank_nm==bankname.r[1]|
                          bank.melt$bank_nm==bankname.r[2]|
                          bank.melt$bank_nm==bankname.r[3]),]
p=ggplot(bank.r, aes(x=variable, y=value, group=bank_nm, color=bank_nm)) +
  geom_line(stat="identity") +
  theme(legend.text=element_text(family="微軟正黑體", size=10)) +
  scale_x_discrete(labels = c("2013-11", "2013-12", "2014-01", "2014-04", "2014-05")) +
    theme_bw()
p
    可以看出有的銀行一開始貸款總額相當大,然後突然下降,有的則是一直缺少房貸。

接下來我們看另一個範例。還記得介紹迴圈時所示範的清理主計處數據:

library(foreign)
stat.dat<-read.csv("CS3171D1A.csv",header=TRUE,sep=";",dec=".",fileEncoding="BIG5")

我們將要多擷取兩個年度的老年人口比率資料,以及擷取三個年度的失業率資料,對每一項資料我們需要一個迴圈,每一個迴圈裡面有兩個變數,也就是從哪一列跟哪一行開始讀取資料:

tempold<-data.frame()
      for (i in 1:3){
       for (u in 1:23){    
         tempold[u,i]<-stat.dat[i+1, u+1]
 }
   print(i)
      }
## [1] 1
## [1] 2
## [1] 3
tempunemploy<-data.frame()
      for (i in 1:3){
       for (u in 1:23){    
         tempunemploy[u,i]<-stat.dat[i+13, u+1]
 }
   print(i)
      }
## [1] 1
## [1] 2
## [1] 3

結合成為資料框,但是用tibble格式觀察資料:

countyname<-colnames(stat.dat)[-1]
temp.df <- data.frame(countyname, tempold, tempunemploy)
temp.df.t <-as_tibble(temp.df); temp.df.t
## # A tibble: 23 x 7
##    countyname    V1    V2    V3  V1.1  V2.1  V3.1
##  * <fct>      <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
##  1 臺北縣      6.37  6.44  6.55   3     4.9   5.5
##  2 宜蘭縣     10.2  10.5  10.8    3.6   5     5.4
##  3 桃園縣      7.46  7.49  7.51   2     4.3   5.1
##  4 新竹縣      9.69  9.91 10.2    1.7   3.8   4.4
##  5 苗栗縣     11.0  11.2  11.6    2.7   4.5   4.9
##  6 臺中縣      7.16  7.32  7.5    3.5   5     5.4
##  7 彰化縣      9.42  9.73 10.0    1.7   4     5.2
##  8 南投縣     10.6  10.9  11.2    3.8   4.9   5.3
##  9 雲林縣     11.6  12.0  12.4    2.6   4.1   4.7
## 10 嘉義縣     12.4  12.8  13.1    2.8   4     5.2
## # ... with 13 more rows

在這個資料框中,V1代表2000年的老年人口,所以它有

  1. 年代
  2. 老年人口

這兩個性質,而V1.1代表2000年的失業率,也是有兩個性質,為了區隔這兩個特性,我們再結合一次,這次把失業率放在老年人口比率底下:

info <- rep('old', 23)
temp.df1<-cbind(countyname, info, tempold)
info <- rep('unemploy', 23)
temp.df2<-cbind(countyname, info, tempunemploy)
temp.df<-data.frame(rbind(temp.df1, temp.df2))

接下來用melt指令轉置資料,並且把其中的年度資料轉換為字串資料,以方便後面的分析:

new.df<-melt(temp.df, id=c('countyname', 'info'), 
             variable.name=c("Time"),
measure.vars = c("V1","V2","V3"))
new.df$Year<-c()
new.df$Year[new.df$Time=='V1']<-2000
new.df$Year[new.df$Time=='V2']<-2001
new.df$Year[new.df$Time=='V3']<-2002
new.df$Year<-as.character(new.df$Year)

如果以縣市為單位,而歸納這三年的兩個變數分別的總和,可以用以下的程式畫圖:

g1<-ggplot(new.df, aes(x=countyname, y=value, fill=info)) +
  geom_bar(stat='identity') +
  theme(axis.text.x=element_text(family="HanWangMingBold", size=10))
g1

如果以縣市為單位,而歸納這兩個變數的每一年總和,可以用以下的程式畫圖:

g2<-ggplot(new.df, aes(x=countyname, y=value, fill=Year)) +
  geom_bar(stat='identity') +
  theme(axis.text.x=element_text(family="YouYuan", size=10))
g2

以上兩種統計方式都是以縣市為單位,而選擇年度(三個類別)或者是統計資料(兩個類別)做為歸納單位,但是有沒有可能同時統計這兩者?也就是每一個縣市、每一個年度、老年人口比率與失業率的數字?

g3<-ggplot(new.df, aes(x=countyname, y=value, fill=info)) +
  geom_bar(stat='identity') +
  facet_wrap( ~ Year) +
  theme(axis.text.x=element_text(family="HanWangMingBold", size=6))
g3

以上程式使用facet_wrap()納入第二個類別變數,繪出三個直方圖,分別代表三個年度的兩個變數的比率。
以上說明寬表、長表的用途,希望能有助於資料轉置以及後續分析。


6 作業

  1. 請下載nycflights13這個套件,然後分析flights這筆資料,並且建立新變數「速度」,公式為距離(distance)除以飛行時間(air_time)乘以60。請問平均速度多少?最高速多少?可以用filter篩選沒有遺漏值的觀察值,例如:
tibble1<-tibble(A=c(NA, NA, NA, 100, 200, 600, NA, 100, 0, 200),
                B=200,
                C=c(rep(300, 5), rep(400, 5)))
tibble1 = filter(tibble1, !is.na(A))
       summarize(tibble1, sum(A,B,C), mean(C))
## # A tibble: 1 x 2
##   `sum(A, B, C)` `mean(C)`
##            <dbl>     <dbl>
## 1           4600      367.
  1. 請讀取studentsfull.txt這個檔案,然後計算不同科系同學的平均分數,再根據平均分數排序資料表:

  2. 請統計mtcars這筆資料中cyl的各類的平均馬力(hp) 以及每加侖可以行駛的英里數(mpg):

  3. 請統計flights資料中每年的最後一天的平均出發以及抵達的遲到分鐘

  4. 請從bank.info資料挑出other_cl_bal大於100億的銀行資料,並且列出銀行的名稱。