1 匯入資料

1.1 CSV 資料

RStudio(1.1.423)可以從File–>Import Dataset開啟Text, Excel, SPSS, Stata, SAS等格式的資料。其中Text檔案又分為base以及rdr,前者比較容易,後者則需要用到套件,但是可以控制分隔符號,大致上效果一樣。
如果要用語法。首先,R可以讀取用csv格式儲存的資料,例如:

setwd("~/Library/Mobile Documents/com~apple~CloudDocs/eastasia")
csv1<-read.csv("councilor.csv", header=TRUE, sep=",", fileEncoding = 'BIG5')
head(csv1)
##   Year budget       unit contracter open
## 1 2015    676     水利處       台球  Yes
## 2 2016    673 新建工程處       茂盛  Yes
## 3 2016    270 新建工程處       冠君  Yes
## 4 2016    255 新建工程處       金煌  Yes
## 5 2016    235 新建工程處       聖鋒  Yes
## 6 2016    190 新建工程處       福呈   No

這筆台北市中山區的陳炳甫議員的議員配合款部分資料來自於議員投票指南
指令中的header=TRUE表示第一列被認為是變數名稱,而sep規範分隔的符號,fileEncoding=BIG5則是將文字編碼為中文。 R讓使用者控制資料中的字串是否視為因素資料,也就是用stringAsFactors控制:

setwd("~/Library/Mobile Documents/com~apple~CloudDocs/eastasia")
csv2<-read.csv("councilor.csv", header=TRUE, sep=",", fileEncoding = 'BIG5', stringsAsFactors = F)

比較資料中的變數屬性,請輸入

class(csv1$unit)
## [1] "factor"
class(csv2$unit)
## [1] "character"

字串可以轉換成數字,但是因素無法轉換成數字。
因為資料裡面的中文常常無法顯示在圖形。請先輸入以下兩行指令列出目前可以使用的字體:
install.packages(‘extrafont’); library(extrafont)
font_import(); fonts()

然後選擇其中的中文字型,例如明體,即可顯示中文字型於圖形中:

par(family='MingLiU'); 
barplot(table(csv1$unit))

或者選擇其他中文字型,例如粗明體,利用ggplot2的繪圖功能:

library(ggplot2)
p<-ggplot(data=csv1, aes(x=factor(unit))) +
  geom_bar(stat="count") +
  theme(text=element_text(family="HanWangMingBold", size=14))
p

1.2 文字資料(txt)

read.table()可以讀取用txt格式儲存的表格資料,該資料的欄位用空白區隔,例如:

setwd("~/Library/Mobile Documents/com~apple~CloudDocs/eastasia")
students<-read.table("Studentsfull.txt", header=TRUE, sep="")
head(students)
##         ID     Name Department Score Gender
## 1 10322011    Ariel  Aerospace    78      F
## 2 10325023    Becky    Physics    86      F
## 3 10430101     Carl Journalism    69      M
## 4 10401032  Dimitri    English    83      M
## 5 10307120  Enrique  Chemistry    80      M
## 6 10207005 Fernando  Chemistry    66      M

scan()可以讀取向量型態的外部資料,但是無法讀取表格,是一個處理簡單資料的指令,首先以數值資料舉例:

scan('voteshare', comment.char = '#', dec='.')
##  [1] 55.6 66.1 36.8 65.1 50.9 44.9 48.7 52.4 48.5 53.0 51.9

其次以字串與數值資料舉例:

scan('latticegraph', what=c('',''), comment.char = '#', sep=',')
##  [1] "barchart"    "bwplot"      "cloud"       "contourplot" "densityplot"
##  [6] "dotplot"     "histogram"   "levelplot"   "parallel"    "splom"      
## [11] "stripplot"   "xyplot"      "wireframe"   "1"           "1"          
## [16] "3"           "3"           "2"           "1"           "1"          
## [21] "2"           "4"           "4"           "2"           "2"          
## [26] "3"

從以上例子可以看出,scan()的功能比較簡單,而read.table()或是read.csv()的功能比較完備。

1.3 統計資料

1.3.1 Stata

Stata本身可以儲存資料為csv檔或其他檔案,但是R有套件可以直接讀取。Stata的12版以前資料則可以用foreign這個套件。例如UCLA的Institue for Digital Research and Education(idre)的資料:

library(foreign)
udata1<-read.dta("https://stats.idre.ucla.edu/stat/data/test.dta")
head(udata1)
##    make   model mpg weight price
## 1   AMC Concord  22   2930  4099
## 2   AMC   Pacer  17   3350  4749
## 3   AMC  Spirit  22   2640  3799
## 4 Buick Century  20   3250  4816
## 5 Buick Electra  15   4080  7827

如果讀取Stata 的13版以後的資料需要readstata13這個套件:

library(readstata13)
udata2<-read.dta13("Mystata.dta")
## Warning in read.dta13("Mystata.dta"): 
##   experience:
##   Factor codes of type double or float detected - no labels assigned.
##   Set option nonint.factors to TRUE to assign labels anyway.
## Warning in read.dta13("Mystata.dta"): 
##   tondu3_new:
##   Factor codes of type double or float detected - no labels assigned.
##   Set option nonint.factors to TRUE to assign labels anyway.
## Warning in read.dta13("Mystata.dta"): 
##   consensus:
##   Factor codes of type double or float detected - no labels assigned.
##   Set option nonint.factors to TRUE to assign labels anyway.
head(udata2)
##   Q1 Q2 Q3 Q4 Q5 SEX AGE EDU TOWNID AREAR SENGI T_Cidentity     partyid
## 1  0  1  1  2  2   2   2   5   6305     1     2           1         DPP
## 2  0  1  1  2  3   2   4   3   6608     4     3           2 Independent
## 3 12  2  1  1  2   1   5   2   6302     1     2           1         KMT
## 4  1  2  1  3  2   2   5   3    911     5     2           1         KMT
## 5  0  2  1  1  2   1   4   3    904     5     2           3         KMT
## 6  0  2  1  4  2   2   4   3   6628     4     2           3         KMT
##   PARTY tondu tondu3 peace visit experience tondu3_new consensus
## 1     5     3      2     8     0          1          1         2
## 2    99     4      2     4     0          1          1         4
## 3     2     2      1     5    12          0          2         4
## 4     3     4      2     4     1          0          1         3
## 5     2     4      2     4     0          0          1         4
## 6     2     2      1     6     0          0          2         3

convert.factors這個參數控制是否將變數的值轉為因素,如果不轉為因素,則維持為整數或者數值。

udata3<-read.dta13("Mystata.dta", convert.factors=F)
class(udata2$partyid); class(udata3$partyid)
## [1] "factor"
## [1] "integer"
table(udata2$partyid)
## 
##         KMT         DPP          NP         PFP         TSU         NPP 
##         287         246           4          21           2          54 
## Independent          DK 
##         557          73

1.3.2 SPSS

foreign的套件也可以讀取SPSS的資料:

library(foreign)
setwd("~/Library/Mobile Documents/com~apple~CloudDocs/eastasia")
dv<-read.spss('PP0797B2.sav', use.value.labels=F, to.data.frame=TRUE)
## Warning in read.spss("PP0797B2.sav", use.value.labels = F, to.data.frame =
## TRUE): PP0797B2.sav: Unrecognized record type 7, subtype 18 encountered in
## system file
table(dv$Q1)
## 
##   1   2   3   4  95  96  97  98 
## 617 684 443  91  10  57  52 104

程式中 use.value.labels=F表示讀取資料時並不會使用資料中原有的變數標記,例如低、中、高教育程度會變成 1、2、3。這樣做的好處是不必把類別變數轉換成數字,壞處則是需要對照原有的資料才能得知每一個值的意義。如果沒有設定 to.data.frame=T,讀取的資料會轉換成列表。請嘗試去掉use.value.labels=F,也就是read.spss()的內建值。
另一個讀取 SPSS 資料的方法是先下載memisc這個套件:

library(memisc)
## Warning: package 'memisc' was built under R version 3.4.3
## Loading required package: lattice
## Loading required package: MASS
## 
## Attaching package: 'memisc'
## The following objects are masked from 'package:stats':
## 
##     contr.sum, contr.treatment, contrasts
## The following object is masked from 'package:base':
## 
##     as.array
udata4<-as.data.set(spss.system.file('pp0797B2.sav'))
udata4[1:4, 1:5]
## 
## Data set with 4 observations and 5 variables
## 
##           q1       q2         q3       q4     q5
## 1     很難說     同意     不同意     同意   同意
## 2 非常不同意 非常同意     不同意     同意 很難說
## 3 非常不同意 非常同意 非常不同意 非常同意   同意
## 4       同意     同意     不同意     同意 不同意

1.4 網路連結資料

R可以讀取網路的連結資料,讓使用者方便下載分析。例如idre的資料:

test.missing <- read.table("https://stats.idre.ucla.edu/stat/data/test_missing_comma.txt",
    header = TRUE, sep = ",")
head(test.missing)
##     prgtype gender  id ses schtyp level
## 1   general      0  70   4      1     1
## 2    vocati      1 121   4     NA     1
## 3   general      0  86  NA     NA     1
## 4    vocati      0 141   4      3     1
## 5  academic      0 172   4      2     1
## 6  academic      0 113   4      2     1

也請到DSP資料中心的資料集找尋感興趣的資料,例如美元匯率,請問有幾筆匯率的資料?

2 資料匯出

write.table()可以匯出資料成為txt或是csv格式到指定的目錄,例如載入一個現有的檔案:

setwd("~/Library/Mobile Documents/com~apple~CloudDocs/eastasia")
vs<-scan('voteshare', comment.char = '#', dec='.')
vs
##  [1] 55.6 66.1 36.8 65.1 50.9 44.9 48.7 52.4 48.5 53.0 51.9

增加新的觀察值在vs資料中,然後匯出資料成為txt檔:

scan('voteshare', comment.char = '#', dec='.')
##  [1] 55.6 66.1 36.8 65.1 50.9 44.9 48.7 52.4 48.5 53.0 51.9
vsnew<-c(vs, 61.9, 31.8, 44.5)
vsnew
##  [1] 55.6 66.1 36.8 65.1 50.9 44.9 48.7 52.4 48.5 53.0 51.9 61.9 31.8 44.5
write.table(vsnew,'vsnew.txt')
read.table('vsnew.txt')
##       x
## 1  55.6
## 2  66.1
## 3  36.8
## 4  65.1
## 5  50.9
## 6  44.9
## 7  48.7
## 8  52.4
## 9  48.5
## 10 53.0
## 11 51.9
## 12 61.9
## 13 31.8
## 14 44.5

或者合併資料,並匯出資料為csv檔:

de<-data.frame(name=state.abb, region=state.region, area=state.area)
head(de)
##   name region   area
## 1   AL  South  51609
## 2   AK   West 589757
## 3   AZ   West 113909
## 4   AR  South  53104
## 5   CA   West 158693
## 6   CO   West 104247
write.csv(de, 'state.csv')
state<-read.csv('state.csv', header=TRUE)
head(state)
##   X name region   area
## 1 1   AL  South  51609
## 2 2   AK   West 589757
## 3 3   AZ   West 113909
## 4 4   AR  South  53104
## 5 5   CA   West 158693
## 6 6   CO   West 104247

在合併變數成為一個資料框時,最好給定每一個欄位一個變數名稱,以方便日後分析。而在執行write.csv()時,不需要指定分隔的符號,在重新讀取時,也不需要刻意指定,仍然可以匯入正確的資料。

3 常用指令

3.1 管理環境空間

R有 global 這個環境空間中儲存命令列中所建立的任何變數,若要了解 global 環境空間有哪些物件,可以使用globalenv() 這個函數,:

globalenv()
## <environment: R_GlobalEnv>
ls(envir = globalenv(),10)
##  [1] "csv1"         "csv2"         "de"           "df"          
##  [5] "dv"           "p"            "state"        "students"    
##  [9] "test.missing" "udata1"       "udata2"       "udata3"      
## [13] "udata4"       "vs"           "vsnew"

ls()指令回傳在特定環境空間內的物件。
以下介紹與環境空間有關的指令:

    1. attach():在工作環境中,可以把資料框、向量附加到搜尋的路徑,使得變數對R是直接可見的。但是attach無法儲存更改後的資料,因此要記得匯出資料,或者是用語法紀錄。例如:
head(csv2)
##   Year budget       unit contracter open
## 1 2015    676     水利處       台球  Yes
## 2 2016    673 新建工程處       茂盛  Yes
## 3 2016    270 新建工程處       冠君  Yes
## 4 2016    255 新建工程處       金煌  Yes
## 5 2016    235 新建工程處       聖鋒  Yes
## 6 2016    190 新建工程處       福呈   No
attach(csv2)
contracter
##  [1] "台球"   "茂盛"   "冠君"   "金煌"   "聖鋒"   "福呈"   "盛吉"  
##  [8] "茂盛"   "冠君"   "未發包"
contracter[1]<-"未發包"
csv2$contracter[10]<-"台球"
csv2
##    Year budget       unit contracter open
## 1  2015    676     水利處       台球  Yes
## 2  2016    673 新建工程處       茂盛  Yes
## 3  2016    270 新建工程處       冠君  Yes
## 4  2016    255 新建工程處       金煌  Yes
## 5  2016    235 新建工程處       聖鋒  Yes
## 6  2016    190 新建工程處       福呈   No
## 7  2015    155     公園處       盛吉  Yes
## 8  2016    154 新建工程處       茂盛  Yes
## 9  2016    142 新建工程處       冠君  Yes
## 10 2016    123 新建工程處       台球  Yes
detach(csv2)
csv2
##    Year budget       unit contracter open
## 1  2015    676     水利處       台球  Yes
## 2  2016    673 新建工程處       茂盛  Yes
## 3  2016    270 新建工程處       冠君  Yes
## 4  2016    255 新建工程處       金煌  Yes
## 5  2016    235 新建工程處       聖鋒  Yes
## 6  2016    190 新建工程處       福呈   No
## 7  2015    155     公園處       盛吉  Yes
## 8  2016    154 新建工程處       茂盛  Yes
## 9  2016    142 新建工程處       冠君  Yes
## 10 2016    123 新建工程處       台球  Yes

上面的例子顯示,如果只是更改向量的元素,而不是更改資料框加上向量的元素,那麼並不會真正改變資料框的內容,而一旦更動,即使detach()該資料集,也會維持其變動。

    1. detach():從工作環境移除已經附加的資料框、向量,以避免混淆。
    1. rm(list=ls()):從工作環境移除所有的向量、列表、資料框等等。
    1. rm():刪除特定的向量、列表、資料框等等。
    1. save.image():儲存環境空間內所有的資料與結果。
    1. load():下載所有資料與結果。
rm(list=ls()) #remove all data
data(mtcars) #suppose we analyze mtcars
m1<-lm(mpg ~ cyl, data=mtcars) #regression
summary(m1) #results
## 
## Call:
## lm(formula = mpg ~ cyl, data = mtcars)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -4.9814 -2.1185  0.2217  1.0717  7.5186 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  37.8846     2.0738   18.27  < 2e-16 ***
## cyl          -2.8758     0.3224   -8.92 6.11e-10 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 3.206 on 30 degrees of freedom
## Multiple R-squared:  0.7262, Adjusted R-squared:  0.7171 
## F-statistic: 79.56 on 1 and 30 DF,  p-value: 6.113e-10
mydata<-data.frame(date=as.Date(c("2018-03-13","2018-03-14","2018-03-15"), format='%Y-%m-%d'), workinghours=c(4, 3, 4)) #create your own data
## Warning in strptime(x, format, tz = "GMT"): unknown timezone 'zone/tz/
## 2018c.1.0/zoneinfo/Asia/Taipei'
setwd("~/Library/Mobile Documents/com~apple~CloudDocs/eastasia") #working directory
save.image("test.Rdata") #save all results to Rdata
rm(list=ls()) #remove all data
load("test.Rdata") #load Rdata
ls(envir = globalenv(),10) #display objects in this environment
## [1] "m1"     "mtcars" "mydata"
mydata #diplay your data
##         date workinghours
## 1 2018-03-13            4
## 2 2018-03-14            3
## 3 2018-03-15            4
    1. saveRds():儲存成RDS
      如果只有單一的物件,可以考慮saveRDS()。如果不想儲存原來的物件名稱,也可以考慮saveRDS()
setwd("~/Library/Mobile Documents/com~apple~CloudDocs/eastasia")
vs<-scan('voteshare', comment.char = '#', dec='.')
vs
##  [1] 55.6 66.1 36.8 65.1 50.9 44.9 48.7 52.4 48.5 53.0 51.9
vs2<-vs/100
saveRDS(vs, "vs.rds")
saveRDS(vs2, 'vs2.rds')
rm(vs); rm(vs2)
vs<-readRDS('vs.rds')
vs2<-readRDS('vs2.rds')
vs; vs2
##  [1] 55.6 66.1 36.8 65.1 50.9 44.9 48.7 52.4 48.5 53.0 51.9
##  [1] 0.556 0.661 0.368 0.651 0.509 0.449 0.487 0.524 0.485 0.530 0.519

saveRDS()的優點是雖然一次只儲存一個物件,但是藉由儲存,可以避免新的物件蓋過舊的物件,新舊物件可以並存。

3.2 程式相關

  • cat():顯示向量以及運算結果,並可以加上文字,並且用“斜線n”參數換行:
x<-c(2,4,6)
cat(x, "\n");
## 2 4 6
cat("summation:", sum(x), "\n", "average:", mean(x))
## summation: 12 
##  average: 4
  • print():顯示資料框、向量、列表等等,但是無法附加上文字。
  • source()R可以讀取既有指令的檔案,在不必開啟命令稿的情況下直接執行多行程式,可節省許多篇幅以及時間。例如我們寫一個自訂函數,語法很長,我們先存成一個語法檔,未來可以直接執行。

    sink("twohistograms.R") #define a new script file
    cat("set.seed(02138)") #input a function that sets starting number for random number
    cat("\n") #end of line
    cat("#write R script to a file without opening a document")
    cat("\n")  #end of line
     cat("fnorm<-function(mu){            #create a function with a parameter: mu
      sample.o<-rnorm(20,mu,1/sqrt(mu))  #define the 1st vector that generates random numbers
      sample.i<-sample.o+runif(1,0,10)  #define the 2nd vector that generates random numbers
      par(mfrow=c(1,2))                 #set parameter of graphic for 1*2 graphics
      hist(sample.o, col=1, main='',    #histogram with Basic R
                xlab='Original sample')
             hist(sample.i, col=4, main='', #another histogram
              xlab='Original sample + random number')
      }")
     cat("\n")  #end of function
     sink()     #save the script in the specified file
    file.show("twohistograms.R") #Opening an editor to show the script

    我們建立 fnorm()這個函數,並且存成一個語法檔(“twohistograms.R”),並且用file.show()顯示出來。以後就可以執行它。
    使用source()函數,執行“twohistograms.R”此一語法檔,產生一個自訂函數,然後輸入參數便可顯示結果。請執行上面的指令之後,自行輸入以下兩行語法:

source("twohistograms.R")
fnorm(1)

如果執行成功會看到以下圖形:

確定一下工作目錄的確多了“twohistograms.R”此一語法檔。

  • with():當環境空間有一個以上的資料框,為了避免混淆,可以使用該指令進行分析:
library(car)
## 
## Attaching package: 'car'
## The following object is masked from 'package:memisc':
## 
##     recode
with(Duncan, histogram(income, col=2))

with(Salaries, histogram(salary, col=6))

注意,該指令不適用於矩陣,例如state.x77。

3.3 資料相關

  • names():顯示資料框的變數名稱,例如:
names(mtcars)
##  [1] "mpg"  "cyl"  "disp" "hp"   "drat" "wt"   "qsec" "vs"   "am"   "gear"
## [11] "carb"

注意,該指令不適用於矩陣,例如state.x77。

  • which():顯示特定變數。例如,哪些樹的圓周符合條件:
which(Orange$circumference>100)
##  [1]  4  5  6  7 10 11 12 13 14 18 19 20 21 24 25 26 27 28 32 33 34 35

看起來有相當多的樹木胸圍超過100公釐(10公分),但是到底有哪些樹符合這個條件?可應用which()函數加以篩選:

oc<-which(Orange$circumference>100) #create a vector of data that meets a condition
oc
##  [1]  4  5  6  7 10 11 12 13 14 18 19 20 21 24 25 26 27 28 32 33 34 35
Orange[oc,] #match data with the vector
## Grouped Data: circumference ~ age | Tree
##    Tree  age circumference
## 4     1 1004           115
## 5     1 1231           120
## 6     1 1372           142
## 7     1 1582           145
## 10    2  664           111
## 11    2 1004           156
## 12    2 1231           172
## 13    2 1372           203
## 14    2 1582           203
## 18    3 1004           108
## 19    3 1231           115
## 20    3 1372           139
## 21    3 1582           140
## 24    4  664           112
## 25    4 1004           167
## 26    4 1231           179
## 27    4 1372           209
## 28    4 1582           214
## 32    5 1004           125
## 33    5 1231           142
## 34    5 1372           174
## 35    5 1582           177

oc是滿足樹的圓周超過100公釐的觀察值,而以該資料框配對這些觀察值,只留下可以配對的每一列觀察值。

  • rep(A, n):重複A數值或者字串n次
rep(3, 5)
## [1] 3 3 3 3 3
c(rep("大", 3), rep("中", 1), rep("小",2))
## [1] "大" "大" "大" "中" "小" "小"
  • seq(i,j):傳回i到j的連續數字
seq(1,10)
##  [1]  1  2  3  4  5  6  7  8  9 10
seq(100,110, by=2)
## [1] 100 102 104 106 108 110
  • seq(i:j):傳回i到j的順位數字
seq(5:10)
## [1] 1 2 3 4 5 6
seq(100:110)
##  [1]  1  2  3  4  5  6  7  8  9 10 11

4 作業

  1. 請匯入這筆ire的資料hsb2_small(“https://stats.idre.ucla.edu/stat/data/hsb2_small.csv”),並且顯示該資料的變數名稱。

  2. 請使用site=“http://faculty.gvsu.edu/kilburnw/nes2008.RData” 以及load(file=url(site))。由以上指令讀取資料後,請先列出V083097的分佈。然後把這個變數重新編碼為「民主黨」(Democrat)、「共和黨」(Republican)、「獨立」(Independent)、「其他政黨」(Other party (SPECIFY)),然後列出這個變數的次數分配。

  3. 請匯出hsb2_small的資料為Text格式以及rds格式。

  4. 請匯入2008年的總統選舉資料(2008Election.csv),並且找出國民黨得票率最高的town.id。(提示:最大值的函數為max())

  5. 請嘗試匯入本週課程所使用的studentsfull檔案,但是這一次用read.csv()