1 課程目標

本週上課將介紹R的資料型態與資料結構,也就是R可以讀取並進行運算的對象,例如我們用 c() 來表示數字、文字的集合:

A<-c("台北市","新北市", "桃園市", "台中市","台南市","高雄市")
print(A)
## [1] "台北市" "新北市" "桃園市" "台中市" "台南市" "高雄市"
B<-c(0,1,2,3,4,5,6,7,8,9)
print(B)
##  [1] 0 1 2 3 4 5 6 7 8 9

A是文字而B是數字的集合,另外還有邏輯以及日期等常用的資料型態。


R資料結構可分為一維、二維、多維:

  • 一維
  • 向量 (vector)
  • 因素 (factor)
  • 二維
  • 矩陣 (matrix)
  • 資料框 (data frame)
  • 資料表(data table)
  • 多維
  • 陣列 (array)
  • 列表 (list)
  • 表格 (table)

由此出發,了解R的資料型態以及運算。


介紹R的資料型態之前,先來認識R的函數。 函數類似一個黑盒子,把變數或者是資料放進去這個黑盒子,根據函數中的設定,回傳計算的結果。例如,我們想知道一個變數的平均值,R的平均值函數為:

?mean
mean(x, trim = 0, na.rm = FALSE)

x為變數,trim表示設定要去除多少百分比的變數中的資料。例如有一個變數型態為:

x<-c(100000, 10000000, c(1:10)); x
##  [1] 1e+05 1e+07 1e+00 2e+00 3e+00 4e+00 5e+00 6e+00 7e+00 8e+00 9e+00
## [12] 1e+01

可以看到這個變數有一些極端值,我們可以用trim=0.2去掉 \(0.2 \times 12=2.4\),等於從這一串數字前後拿掉2個數字。以下比較有無設定傳回的結果:

x<-c(100000, 10000000, c(1:10))
sort(x)
##  [1] 1e+00 2e+00 3e+00 4e+00 5e+00 6e+00 7e+00 8e+00 9e+00 1e+01 1e+05
## [12] 1e+07
mean(x)
## [1] 841671.2
mean(x, trim=0.2)
## [1] 6.5
mean(sort(x)[3:10])
## [1] 6.5

trim=0.2,x剩下第3到第10個資料,也就是x[3:10]。記得用sort()排序x,再取出正確的資料。

我們可以順便認識數字用科學符號表示的方式。e+01代表兩位數,e+05代表6位數。

Rousselet的部落格進一步介紹為何要去掉極端值。

大部份時候我們執行函數時,不會用到所有的設定,但是越了解每一個函數的設定的意義,越能發揮函數的功能。


2 資料型態

2.1 數值(numeric)

數值可分為數值(numeric)或者是整數(integer)。任意數例如:

X<-c(2, 4, 6, 8); X
## [1] 2 4 6 8
class(X)
## [1] "numeric"
str(X)
##  num [1:4] 2 4 6 8

class()函數告訴我們該資料型態或者是結構的屬性。

可以用科學符號表示比較大的數字:

y=c(1.1e+06); y
## [1] 1100000
class(y)
## [1] "numeric"

整數則為:

u<-as.integer(c(4)); class(u)
## [1] "integer"

整數是數值的子集合,因為整數的最大值是2147483647,遠小於數值的最大值。在一般運算或是統計上幾乎沒有差異,唯一的差別在於整數的儲存佔用空間比較小,而一般數值其實帶有小數點,只是沒有顯示,稱為浮點運算。由於電腦使用二進位制的運算,由一個有效數字加上冪數來表示,以這種表示法表示的數值,稱為浮點數。利用浮點進行運算,稱為浮點計算,也就是所有渉及小數的運算。。

請輸入

  • is.numeric(100)
  • is.integer(100)

乍看之下100應該是整數,但是其實是數值。 又例如:

a<-c(7, 8.5, 9); class(a)
## [1] "numeric"
b<-as.integer(a); b
## [1] 7 8 9

as.integer()傳回整數。 變數如果與另一個變數對應條件時,R會顯示變數性質與對應結果:

h<-c(100, 200, 500)
ok<-h>300
b[ok]
## [1] 9
ok<-h>1000
b[ok]
## integer(0)

2.2 字串(character)

變數可以是字串,例如受訪者的性別、學生的姓名、國家名稱等等。

請輸入

  • state.abb
  • class(state.abb)

文字對於資料使用者而言相對於數值容易理解,但是用途比較受限,無法進行數學運算,但是在資料視覺化時相當有用,例如:

df<-data.frame(state.abb, pop=state.x77[,2])
library(lattice)
dotplot(state.abb ~ pop, data=df)

state.x77是矩陣,所以取出這個矩陣中的人口此一欄位,然後與state.abb結合成一個資料框,再以dotplot指令畫成點狀圖。

數字也可以當成文字,例如:

char1<-c("1","2","Word"); char1
## [1] "1"    "2"    "Word"
char2<-c(1, 2, "文字"); char2
## [1] "1"    "2"    "文字"

數字都被視為字串,無法進行數學運算。字串無法用as.numeric轉換為數字,但是可以用語法進行轉換(請見因素一節)。

請嘗試

  • quakes
  • class(row.names(quakes))

quakes這筆資料的列名稱看起來是數字,卻被視為字串。

以及

  • state.x77
  • class(row.names(state.x77))

字串經常會被誤認為因素(factor),具有類別,例如1,000個受訪者中可能有500多個男或是女,因此R視為因素變數而非字串。 例如,我們到政府開放資料網站下載一筆資料:

library(foreign); library(tidyverse)
dat<-read.csv("opendata106N0101.csv", header=T, fileEncoding = 'UTF-8')
as.tibble(dat)
## # A tibble: 375 x 4
##    code         年底人口數 土地面積 人口密度
##    <fct>        <fct>         <dbl> <fct>   
##  1 新北市板橋區 551480        23.1  23835   
##  2 新北市三重區 387484        16.3  23747   
##  3 新北市中和區 413590        20.1  20532   
##  4 新北市永和區 222585         5.71 38956   
##  5 新北市新莊區 416524        19.7  21102   
##  6 新北市新店區 302089       120.   2513    
##  7 新北市樹林區 184149        33.1  5559    
##  8 新北市鶯歌區 86593         21.1  4099    
##  9 新北市三峽區 114926       191.   600     
## 10 新北市淡水區 169597        70.7  2400    
## # ... with 365 more rows

可以看出許多變數被視為因素。 加上stringsAsFactors = F避免把字串當做因素:

dat<-read.csv("opendata106N0101.csv", header=T, stringsAsFactors = F)
nrow(dat) #check how many rows; n=375
## [1] 375
dat <- dat[-c(369:375),] #delete the rows of small islands and notes
dat<-as.tibble(dat); head(dat, n=3)
## # A tibble: 3 x 4
##   code         年底人口數 土地面積 人口密度
##   <chr>        <chr>         <dbl> <chr>   
## 1 新北市板橋區 551480         23.1 23835   
## 2 新北市三重區 387484         16.3 23747   
## 3 新北市中和區 413590         20.1 20532

可以看到,新的資料中,變數code被認為是是字串,但是年底人口數、人口密度也被認為是字串。 我們創造一個新的數字變數來取代字串變數:

dat <- dat %>% mutate(popu=as.numeric(年底人口數))
str(dat)
## Classes 'tbl_df', 'tbl' and 'data.frame':    368 obs. of  5 variables:
##  $ code      : chr  "新北市板橋區" "新北市三重區" "新北市中和區" "新北市永和區" ...
##  $ 年底人口數: chr  "551480" "387484" "413590" "222585" ...
##  $ 土地面積  : num  23.14 16.32 20.14 5.71 19.74 ...
##  $ 人口密度  : chr  "23835" "23747" "20532" "38956" ...
##  $ popu      : num  551480 387484 413590 222585 416524 ...

str()函數可以顯示資料中的變數性質。

另一個方式為讀取時故意不讀第一列為欄位的標題,這樣所有欄位會被視為字串:

df<-read.csv("opendata106N0101.csv", header=F, stringsAsFactors = F)
colnames(df) <-df[1,]
df <- df[-c(1, 370:376),] #delete the first row and the rows of notes
df<-df%>% mutate(popu=as.numeric(年底人口數))
head(df, n=3)
##           code 年底人口數 土地面積 人口密度   popu
## 1 新北市板橋區     551480  23.1373    23835 551480
## 2 新北市三重區     387484   16.317    23747 387484
## 3 新北市中和區     413590   20.144    20532 413590
str(df)
## 'data.frame':    368 obs. of  5 variables:
##  $ code      : chr  "新北市板橋區" "新北市三重區" "新北市中和區" "新北市永和區" ...
##  $ 年底人口數: chr  "551480" "387484" "413590" "222585" ...
##  $ 土地面積  : chr  "23.1373" "16.317" "20.144" "5.7138" ...
##  $ 人口密度  : chr  "23835" "23747" "20532" "38956" ...
##  $ popu      : num  551480 387484 413590 222585 416524 ...
min(df$popu) #check if data has no missing value
## [1] 685

第三個方式為利用data.table這個套件,以及transform()的功能,直接轉換某一個變數的屬性,但是不創造新的變數:

library(data.table)
## 
## Attaching package: 'data.table'
## The following objects are masked from 'package:dplyr':
## 
##     between, first, last
## The following object is masked from 'package:purrr':
## 
##     transpose
DT <- read.csv("opendata106N0101.csv", header=F, stringsAsFactors = F)
colnames(DT) <-DT[1,]
nrow(DT) #check how many rows; n=376
## [1] 376
DT <- DT[-c(1, 370:376),] #delete the first row and the rows of notes
DT <- data.table(DT)
DT <- DT %>% transform(年底人口數=as.numeric(年底人口數))
head(DT, n=3)
##            code 年底人口數 土地面積 人口密度
## 1: 新北市板橋區     551480  23.1373    23835
## 2: 新北市三重區     387484   16.317    23747
## 3: 新北市中和區     413590   20.144    20532
str(DT)
## Classes 'data.table' and 'data.frame':   368 obs. of  4 variables:
##  $ code      : chr  "新北市板橋區" "新北市三重區" "新北市中和區" "新北市永和區" ...
##  $ 年底人口數: num  551480 387484 413590 222585 416524 ...
##  $ 土地面積  : chr  "23.1373" "16.317" "20.144" "5.7138" ...
##  $ 人口密度  : chr  "23835" "23747" "20532" "38956" ...
##  - attr(*, ".internal.selfref")=<externalptr>
min(DT$年底人口數) #check if data has no missing value
## [1] 685

請注意上述三組語法之中,我們去掉東沙群島、南沙群島的資料,以及一些資料的說明。

2.2.1 因素(factor)

有些資料具有類別,例如性別、是或否、地區等等。Verzani (p.10) 的例子:

x=c("Yes","No","No","Yes","Yes"); x
## [1] "Yes" "No"  "No"  "Yes" "Yes"
factor(x)
## [1] Yes No  No  Yes Yes
## Levels: No Yes
table(x)
## x
##  No Yes 
##   2   3

在這個例子中,x是字串資料,而factor()這個函數把x轉換為因素,有No, Yes兩類別。 常用的指令是table(),用途為統計向量的分佈。
因素在許多分析之中讓人容易理解,例如在交叉分析時:

library(car)
## Loading required package: carData
## 
## Attaching package: 'car'
## The following object is masked from 'package:dplyr':
## 
##     recode
## The following object is masked from 'package:purrr':
## 
##     some
table(Chile$sex, Chile$vote)
##    
##       A   N   U   Y
##   F 104 363 362 480
##   M  83 526 226 388

不論是字串或者是因素,比較容易讓人理解交叉分析的結果。例如我們的資料用數字代表地區:

Chile$ncode<-as.numeric(Chile$region) 
table(Chile$ncode, Chile$vote)
##    
##       A   N   U   Y
##   1  44 210 141 174
##   2   2  18  23  38
##   3  30 102  46 135
##   4  42 214 148 275
##   5  69 345 230 246

或者是繪圖:

library(lattice)
plot(Chile$sex, Chile$vote, xlab="Sex", ylab="Vote")

2.2.1.1 因素轉換

有時候我們需要把因素轉換成數值,例如教育程度從國小、國中、…轉換成1到6的尺度。或者性別從男、女轉換成0與1。可用as.numeric()函數:

gender<-as.numeric(Chile$sex) 
table(Chile$sex); table(gender)
## 
##    F    M 
## 1379 1321
## gender
##    1    2 
## 1379 1321

可以看到R按照類別的字母順序轉換類別為數字。 如果進一步要轉換數字就容易了:

sex <- c()
sex[gender==2]<-0
sex[gender==1]<-1
table(sex)
## sex
##    0    1 
## 1321 1379

也可以寫語法直接轉換因素為需要的數字:

ngender<-c()
ngender[Chile$sex=='F']<-1
ngender[Chile$sex=='M']<-0
table(ngender)
## ngender
##    0    1 
## 1321 1379

或是把因素轉換為字串:

Chile$gender[Chile$sex=="F"]<-"Female"
Chile$gender[Chile$sex=="M"]<-"Male"
class(Chile$gender)
## [1] "character"
table(Chile$gender)
## 
## Female   Male 
##   1379   1321

如果是字串,可以進行交叉分析,但是無法畫圖

table(Chile$gender, Chile$vote)
plot(Chile$gender, Chile$vote, xlab="Sex", ylab="Vote")

需要注意字串無法轉換為數字,因為R無法判斷哪一個字串應該被給予哪一個數字。

as.numeric(Chile$gender)

請嘗試練習AMSsurveycitizen等類別變數的轉換。 如果要避免讀取資料時把字串認定為因素,可以加上一個設定stringsAsFactors=FALSE

library(data.table)
X = data.table(A=sample(3, 6, TRUE), 
               B=sample(letters[1:3], 6, TRUE), 
               C=sample(6), stringsAsFactors=FALSE)
X
##    A B C
## 1: 2 c 1
## 2: 2 a 4
## 3: 1 a 5
## 4: 2 a 3
## 5: 2 b 6
## 6: 1 b 2
## Warning in (function (..., .x = ..1, .y = ..2, . = ..1) : 強制變更過程中產
## 生了 NA
## # A tibble: 6 x 4
##   name  birth height weight
##   <chr> <dbl>  <dbl>  <dbl>
## 1 Wang     NA    111    8.5
## 2 Lin      NA    113   10.6
## 3 Yang     NA    106    7.5
## 4 Huang    NA    114    9.6
## 5 Cheng    NA    102    9.4
## 6 Chao     NA    114   10.5

2.2.1.2 因素的順序

請輸入 - x<-c(“花蓮縣”,“臺北市”,“屏東縣”,“臺南市”,“高雄市”);x; - table(x)

x的排列方式為“花蓮縣”,“臺北市”,“屏東縣”,“臺南市”,“高雄市”,而分布的排列方式也是如此。
如果希望按照由北到南再到東排列觀察值,可以加上level指令 xf<-factor(x, levels=c(“臺北市”, “臺南市”,“高雄市”,“屏東縣”,“花蓮縣”)); xf
table(xf)

請練習把Chile裡面的region變數的類別重新排序,然後執行

table(Chile$sex,Chile$regionorder)

附帶一提,factor()這個函數裡面有ordered的邏輯選項,不過只要指定levels,有無ordered為真並不影響。但是ordered()這個函數會得到一個已經排序的因素,例如:

od<-ordered(1:20); class(od)
## [1] "ordered" "factor"

2.3 邏輯(logic)

資料可以是真(True)或是偽(False)的邏輯,對於篩選資料特別有用。例如我們先建立一筆資料以及邏輯:

a<-c(0:9); a
##  [1] 0 1 2 3 4 5 6 7 8 9
ok<-a>5; ok
##  [1] FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE

然後用這個邏輯篩選資料:

a[ok]
## [1] 6 7 8 9

請嘗試

head(Duncan)
ok<-Duncan$income>50  
Duncan$income[ok]

請問篩選後的變數剩下幾個觀察值? 附帶介紹一個指令length(),用途為顯示向量的長度。
有時候我們的資料裡面有遺漏值NA。可以用邏輯加上is.na()函數,剔除這些遺漏值。

H<-data.table(Age=c("40-49","30-39","40-49","20-29","20-29","60-69","60-69","30-39","60-69","30-39"), Vote=c("Ding", NA, "Ko", "Ko", "Ko", NA, "Ko", "Yao","Ding","Ko"), Income=c(NA,NA, "900-1200K", "600-900K", NA, "2000-3000K", NA, "600-900K", "2000-3000K", "900-1200K")); H
##       Age Vote     Income
##  1: 40-49 Ding       <NA>
##  2: 30-39 <NA>       <NA>
##  3: 40-49   Ko  900-1200K
##  4: 20-29   Ko   600-900K
##  5: 20-29   Ko       <NA>
##  6: 60-69 <NA> 2000-3000K
##  7: 60-69   Ko       <NA>
##  8: 30-39  Yao   600-900K
##  9: 60-69 Ding 2000-3000K
## 10: 30-39   Ko  900-1200K
ok <- !is.na(H$Vote)
table(H$Age[ok], H$Vote[ok])
##        
##         Ding Ko Yao
##   20-29    0  2   0
##   30-39    0  1   1
##   40-49    1  1   0
##   60-69    1  1   0

請嘗試用以上的技巧顯示收入與投票之間的關係。

##             
##              Ding Ko Yao
##   2000-3000K    1  0   0
##   600-900K      0  1   1
##   900-1200K     0  2   0

2.4 日期(date)

請輸入 Sys.Date()
今天的日期是一個日期變數。 as.Date()可以將字串轉變為日期資料

v<-c("2/27/2018", "6/26/2018", "12/31/2018"); class(v)
## [1] "character"
v.date<-as.Date(v, format='%m/%d/%Y'); class(v.date)
## [1] "Date"

或者是

v<-c("", "6/26/2018", "12/31/2018")
as.Date(v, format='%m/%d/%Y')
## [1] NA           "2018-06-26" "2018-12-31"

format()則轉換屬性為日期的資料為不同格式,例如:

today <- Sys.Date()
format(today, format='%m/%d/%Y')
## [1] "03/08/2019"

2.4.1 日期的格式

日期的格式如下:

符號 意義 例子
%d 01-31
%a 星期幾的縮寫 Mon
%A 星期幾 Monday
%m 月份(數字) 01-12
%b 月份的縮寫 Jan
%B 月份的完整寫法 January
%y 兩位數年份 18
%Y 年份 2018

format()這個函數可以轉換已經是日期格式的資料。

Today<-Sys.Date(); Today
## [1] "2019-03-08"
to_day<-format(Today, format='%Y-%b-%d'); to_day
## [1] "2019- 3-08"

2.4.2 日期的差距

請輸入

xi<-"1953-06-15" #Xi's birthday
tsai<-"1956-08-31" #Tsai's birthday

我們可以轉換字串為日期變數,然後計算兩個日期之間的差距:

as.Date(c(xi,tsai), origin="1904-01-01")
## [1] "1953-06-15" "1956-08-31"
difftime(tsai, xi)
## Time difference of 1173 days

在這個例子中,origin指令可設定也可不設定。但是計算某一個數字代表的日期時必須要有起始日:

as.Date(1100, origin="2018-08-01")
## [1] "2021-08-05"

介紹完資料型態之後,接下來介紹資料結構。


3 資料結構

3.1 一維

3.1.1 向量(vector)

向量是最常見的資料結構,可以寫成:

example<-c(0,1,2,3,4)
print(example)
## [1] 0 1 2 3 4

或者是

c(2,4,6,8)->A

英文字母的向量:

c(letters)
##  [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q"
## [18] "r" "s" "t" "u" "v" "w" "x" "y" "z"
c(LETTERS)
##  [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q"
## [18] "R" "S" "T" "U" "V" "W" "X" "Y" "Z"

有時候我們為向量中的元素加上名稱,方便繪圖,例如有兩個向量分別表示某位投資者的資金配置以及2016到2019的現金數量:

shares <- c(150, 40,  65)
names(shares) <- c('Finance','Techonolgy','Cash')
shares
##    Finance Techonolgy       Cash 
##        150         40         65
class(shares)
## [1] "numeric"
cash<-c(100, 120, 80, 65)
names(cash) <- c(2016, 2017, 2018, 2019)
par(mfrow=c(1,2), bg='lightgreen',mai=c(0.4,0.3,0.1,0.3))
pie(shares); barplot(cash, cex.axis = 0.8)

可以在向量內進行數學運算,例如:

j<-c(2*2, 2*9, 10-2, 3^3); j
## [1]  4 18  8 27

向量可以加、減、乘、除其他數字:

R<-c(100, 200, 300); R/5; sqrt(R)
## [1] 20 40 60
## [1] 10.00000 14.14214 17.32051

一個向量可以合併另一個向量:

c(j, R)
## [1]   4  18   8  27 100 200 300

或者是一個向量包含其他向量:

Y<-c(j, c(9:5), R[c(1,2)]); Y
##  [1]   4  18   8  27   9   8   7   6   5 100 200

因為R的向量可以連結,我們可以增加資料的數量。 用減號可以去除向量中的元素,例如:

Y[-c(8:12)]
## [1]  4 18  8 27  9  8  7

3.2 二維

3.2.1 矩陣 (matrix)

R的資料結構之一是矩陣,例如:

data("VADeaths"); VADeaths
##       Rural Male Rural Female Urban Male Urban Female
## 50-54       11.7          8.7       15.4          8.4
## 55-59       18.1         11.7       24.3         13.6
## 60-64       26.9         20.3       37.0         19.3
## 65-69       41.0         30.9       54.6         35.1
## 70-74       66.0         54.3       71.1         50.0
class(VADeaths)
## [1] "matrix"

數學的矩陣與R的矩陣類似。矩陣的讀法是先列再行。例如我們需要一個\(3\times 3\)的矩陣可寫成:

m<-matrix(c(1:9), nrow=3, ncol=3); m
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9

再寫一個\(3\times 2\)

n<-matrix(c(1:6), nrow=3, ncol=2)

兩個矩陣相乘可寫成:

m<-matrix(c(1:9), nrow=3, ncol=3); n<-matrix(c(1:6), nrow=3, ncol=2); m%*%n
##      [,1] [,2]
## [1,]   30   66
## [2,]   36   81
## [3,]   42   96

矩陣的乘法需要第一個矩陣的行(column)等於第二個矩陣的列(row)。
矩陣的對角向量為:

diag(m)
## [1] 1 5 9

轉置矩陣為:

t(m)
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]    4    5    6
## [3,]    7    8    9

如果要替代或者是選取部分的矩陣資料,例如要選取m矩陣的第二列第三行的資料,並且命它為0:

m[2,3]; m[2,3]<-0
## [1] 8

請嘗試(1)轉置n矩陣(2)輸入以下指令:n<-matrix(c(1:6), nrow=3, ncol=2, byrow=T)

矩陣的列與行命名方式為用dimnames的指令分別對列與行指定名稱,例如:

n<-matrix(c(1:6), nrow=3, ncol=2, dimnames = list(c("a","b","c"),c("A","B"))); n
##   A B
## a 1 4
## b 2 5
## c 3 6

3.2.2 資料框 (data frame)

資料框是向量組合起來成為一個類似矩陣的資料,然後指定變數名稱。例如:

R1<-c(170, 175, 166, 172, 165, 157, 167, 167, 
        156, 160)
R2<-c("F","M","M","M","F","F","F","F","M","F")
R3<-R1/10 + 42
R123<-data.frame(height=R1,gender=R2,weight=R3, 
                 stringsAsFactors = FALSE)
R123
##    height gender weight
## 1     170      F   59.0
## 2     175      M   59.5
## 3     166      M   58.6
## 4     172      M   59.2
## 5     165      F   58.5
## 6     157      F   57.7
## 7     167      F   58.7
## 8     167      F   58.7
## 9     156      M   57.6
## 10    160      F   58.0

資料框的每一行必須有相同的長度,每一列也必須要有同樣數目的數字、文字等。 如果沒有特別指定資料框,R會當做矩陣。例如:

H<-cbind(LETTERS[1:6], seq(10,60, 10))
class(H)
## [1] "matrix"

因為矩陣無法設定stringAsFactor=F,所以資料框比較好用。

有幾個資料框與矩陣的相關指令:

  • nrow(x):顯示x資料框或矩陣的列數量,也等於是觀察值數目
  • ncol(x):顯示x資料框或矩陣的行數量,也等於是變數數目
  • dim(x):同時顯示x資料框或矩陣的行列的數量
  • str(x):顯示x資料框或矩陣的性質以及變數名稱與性質
  • head(x):顯示x資料框或矩陣的前6列
  • head(x, n=a):顯示x資料框或矩陣的前a列
  • colnames(x):顯示或設定x資料框或矩陣的變數或欄位名稱
  • rownames(x):顯示或設定x資料框或矩陣每一列的名稱

有關rownames的更多說明,請參考這個部落格

例如我們想知道AMSsurvey有幾個觀察值:

nrow(AMSsurvey)
## [1] 24

如果想要改變欄位名稱,可以這麼做:

colnames(R123)<-c("v1","v2","v3"); R123
##     v1 v2   v3
## 1  170  F 59.0
## 2  175  M 59.5
## 3  166  M 58.6
## 4  172  M 59.2
## 5  165  F 58.5
## 6  157  F 57.7
## 7  167  F 58.7
## 8  167  F 58.7
## 9  156  M 57.6
## 10 160  F 58.0

有的資料框的最左邊是流水號,有的資料框沒有,前者可能是因為從csv等工作表讀取而來,被賦予流水號,但是並不是第一行,真正的第一行應該有欄位的名稱。有的資料框則用字串當做列的名稱:

library(ISLR)
head(College, n=3)
##                              Private Apps Accept Enroll Top10perc
## Abilene Christian University     Yes 1660   1232    721        23
## Adelphi University               Yes 2186   1924    512        16
## Adrian College                   Yes 1428   1097    336        22
##                              Top25perc F.Undergrad P.Undergrad Outstate
## Abilene Christian University        52        2885         537     7440
## Adelphi University                  29        2683        1227    12280
## Adrian College                      50        1036          99    11250
##                              Room.Board Books Personal PhD Terminal
## Abilene Christian University       3300   450     2200  70       78
## Adelphi University                 6450   750     1500  29       30
## Adrian College                     3750   400     1165  53       66
##                              S.F.Ratio perc.alumni Expend Grad.Rate
## Abilene Christian University      18.1          12   7041        60
## Adelphi University                12.2          16  10527        56
## Adrian College                    12.9          30   8735        54

rownames 可以幫助我們刪掉不需要的資料。例如我們有一筆美國各州的資料:

head(state.x77, n=5)
##            Population Income Illiteracy Life Exp Murder HS Grad Frost
## Alabama          3615   3624        2.1    69.05   15.1    41.3    20
## Alaska            365   6315        1.5    69.31   11.3    66.7   152
## Arizona          2212   4530        1.8    70.55    7.8    58.1    15
## Arkansas         2110   3378        1.9    70.66   10.1    39.9    65
## California      21198   5114        1.1    71.71   10.3    62.6    20
##              Area
## Alabama     50708
## Alaska     566432
## Arizona    113417
## Arkansas    51945
## California 156361

我們想刪掉Alabama, Alaska, Arkansas三個州的資料,先成立一個矩陣:

names.to.delete<-c('Alabama', 'Alaska', 'Arkansas')

再用which(rownames(data) %in% vector)傳回所要選出的列:

rows.to.delete<-which(rownames(state.x77) %in% names.to.delete) 

最後用data[-c(), ]刪掉所選的列:

newstate <- state.x77[-c(rows.to.delete),]
head(newstate, n=5)
##             Population Income Illiteracy Life Exp Murder HS Grad Frost
## Arizona           2212   4530        1.8    70.55    7.8    58.1    15
## California       21198   5114        1.1    71.71   10.3    62.6    20
## Colorado          2541   4884        0.7    72.06    6.8    63.9   166
## Connecticut       3100   5348        1.1    72.48    3.1    56.0   139
## Delaware           579   4809        0.9    70.06    6.2    54.6   103
##               Area
## Arizona     113417
## California  156361
## Colorado    103766
## Connecticut   4862
## Delaware      1982

更進一步的篩選資料方法將會在後面課程介紹。


3.3 多維

3.3.1 陣列 (array)

陣列容納一個以上的矩陣,只有一個矩陣的陣列相當於矩陣:

Array1 <- array(1:12, dim = c(2, 6, 1)); Array1
## , , 1
## 
##      [,1] [,2] [,3] [,4] [,5] [,6]
## [1,]    1    3    5    7    9   11
## [2,]    2    4    6    8   10   12

而有多個矩陣的陣列如:

Array2 <- array(1:12, dim = c(2, 3, 2)); Array2
## , , 1
## 
##      [,1] [,2] [,3]
## [1,]    1    3    5
## [2,]    2    4    6
## 
## , , 2
## 
##      [,1] [,2] [,3]
## [1,]    7    9   11
## [2,]    8   10   12

陣列的優點是同時容納一個以上的矩陣,如果只需要某一個矩陣,可以這樣取出:

A12<-Array2[,,2]; A12
##      [,1] [,2] [,3]
## [1,]    7    9   11
## [2,]    8   10   12

3.3.2 列表 (list)

列表的特性為資料的長度、結構沒有限制,例如:

listA<-list(R123, H, c(xi,tsai)); listA
## [[1]]
##     v1 v2   v3
## 1  170  F 59.0
## 2  175  M 59.5
## 3  166  M 58.6
## 4  172  M 59.2
## 5  165  F 58.5
## 6  157  F 57.7
## 7  167  F 58.7
## 8  167  F 58.7
## 9  156  M 57.6
## 10 160  F 58.0
## 
## [[2]]
##      [,1] [,2]
## [1,] "A"  "10"
## [2,] "B"  "20"
## [3,] "C"  "30"
## [4,] "D"  "40"
## [5,] "E"  "50"
## [6,] "F"  "60"
## 
## [[3]]
## [1] "1953-06-15" "1956-08-31"

又例如我們在一個列表中,創造兩個資料框並給定名稱:

list(A=data.frame(x=c(1:5),y=c(101:105)), 
     B=data.frame(v1=rep(NA,6)))
## $A
##   x   y
## 1 1 101
## 2 2 102
## 3 3 103
## 4 4 104
## 5 5 105
## 
## $B
##   v1
## 1 NA
## 2 NA
## 3 NA
## 4 NA
## 5 NA
## 6 NA

如果要取出列表中的某一個部分資料,可以寫成:

listA[[3]]
## [1] "1953-06-15" "1956-08-31"

列表的優點是儲存尚未格式化的資料,但是資料相當龐大,矩陣與陣列的資料分散為一個個元素,不容易取出,如果事先命名,就比較容易了解哪些元素來自於什麼資料。例如:

listB<-list(data=R123, vec=m, char=c(tsai, xi)); 
listB[["data"]]
##     v1 v2   v3
## 1  170  F 59.0
## 2  175  M 59.5
## 3  166  M 58.6
## 4  172  M 59.2
## 5  165  F 58.5
## 6  157  F 57.7
## 7  167  F 58.7
## 8  167  F 58.7
## 9  156  M 57.6
## 10 160  F 58.0

如果列表中的變數有同樣的長度,可以用setDT()轉換列表為data.table。例如:

X = list(1:5, letters[1:5], c('Y','Y','N','Y','N'), c("2/27/2018", "6/26/2018", "12/31/2018","1/20/2019","4/8/2019")); X
## [[1]]
## [1] 1 2 3 4 5
## 
## [[2]]
## [1] "a" "b" "c" "d" "e"
## 
## [[3]]
## [1] "Y" "Y" "N" "Y" "N"
## 
## [[4]]
## [1] "2/27/2018"  "6/26/2018"  "12/31/2018" "1/20/2019"  "4/8/2019"
X.dt<-setDT(X); X.dt
##    V1 V2 V3         V4
## 1:  1  a  Y  2/27/2018
## 2:  2  b  Y  6/26/2018
## 3:  3  c  N 12/31/2018
## 4:  4  d  Y  1/20/2019
## 5:  5  e  N   4/8/2019
請嘗試把`c('a','b','c')``c(1,2,3,4)`以及`c('2018-01-01', '2018-04-04', '2018-04-05', '2018-06-18', '2018-10-10')`結合成為一個列表。  

3.3.3 表格 (table)

Titanic這筆資料為表格的型態,同時也是四個陣列,

class(Titanic); Titanic
## [1] "table"
## , , Age = Child, Survived = No
## 
##       Sex
## Class  Male Female
##   1st     0      0
##   2nd     0      0
##   3rd    35     17
##   Crew    0      0
## 
## , , Age = Adult, Survived = No
## 
##       Sex
## Class  Male Female
##   1st   118      4
##   2nd   154     13
##   3rd   387     89
##   Crew  670      3
## 
## , , Age = Child, Survived = Yes
## 
##       Sex
## Class  Male Female
##   1st     5      1
##   2nd    11     13
##   3rd    13     14
##   Crew    0      0
## 
## , , Age = Adult, Survived = Yes
## 
##       Sex
## Class  Male Female
##   1st    57    140
##   2nd    14     80
##   3rd    75     76
##   Crew  192     20

可以看到這筆資料有四個變數:艙等、性別、年齡、是否存活。 因為有四個陣列,所以我們取出其中一個表格時需要給定兩個條件,如果設定三個條件,就是一個向量,如果設定四個就是一個元素。 例如我們想知道沒有生還的兒童搭的艙等與性別,也就是第一個表格,可以這樣輸入:

T1<-Titanic[, , 1, 1]
class(T1); T1
## [1] "table"
##       Sex
## Class  Male Female
##   1st     0      0
##   2nd     0      0
##   3rd    35     17
##   Crew    0      0

顯示沒有生還的兒童都是搭三等艙,男童為女童一倍。如果我們想知道艙等與生還的關係,可以先試著呈現:

Titanic[, 1, 1,]
##       Survived
## Class  No Yes
##   1st   0   5
##   2nd   0  11
##   3rd  35  13
##   Crew  0   0
Titanic[, 1, 2,]
##       Survived
## Class   No Yes
##   1st  118  57
##   2nd  154  14
##   3rd  387  75
##   Crew 670 192
Titanic[, 2, 1,]
##       Survived
## Class  No Yes
##   1st   0   1
##   2nd   0  13
##   3rd  17  14
##   Crew  0   0
Titanic[, 2, 2,]
##       Survived
## Class   No Yes
##   1st    4 140
##   2nd   13  80
##   3rd   89  76
##   Crew   3  20

3.3.4 資料表

資料表(data.table)是資料框的延伸,可以直接在資料中計算特定的列或是行。例如:

library(data.table)
DT = data.table(a = 1:3, b = c(10,20,30))
DT
##    a  b
## 1: 1 10
## 2: 2 20
## 3: 3 30
DT[1:3, sum(a)]
## [1] 6
DT[1:2, mean(b)]
## [1] 15

在創造一個資料表之後,先計算a變數的總和,然後算b變數前兩個值的平均。 也可以直接繪圖,例如我們先建立一個常態分佈的變數,然後畫出機率密度圖:

DT <-data.table(x=rnorm(1000, 0, 1))
DT[, plot(density(x), type='l', xlab='x', ylab='', lwd=3, col='lightblue')]

## NULL

資料表的功能非常多,相較於資料框來得複雜,不過這門課程主要用資料框來處理資料。對於資料表有興趣的同學可以參考該套件的網站

3.4 小結

資料框在各種資料結構之中,是最常被用到的。如果要把資料提出,最好把各種資料結構轉成資料框。例如我們想知道一筆資料的變數性質:

g<-Titanic[ , , 2, 2]; class(g)
## [1] "table"

請輸入 g$Class結果發生錯誤,無法顯示。改為:

g<-data.frame(g)

請輸入 g$Class則會顯示變數的性質。

4 基本運算

4.1 向量的運算

因為向量具有方位的性質,所以數字具有先後順序,與另一個有同樣數目的向量相加減乘除時,將會依照順序進行運算。我們以一個純量 (scalar) Sca 為例:

X<-c(10,20,30,40,50,60); Sca<-10
X+Sca
## [1] 20 30 40 50 60 70

如果是乘或是除,就是每個元素同時乘或除某個數:

X/Sca
## [1] 1 2 3 4 5 6

如果是乘或是除另一個矩陣向量,就是兩個向量對應的每個元素進行乘或除:

Y<-c(5,10,6,8,25,6)
X/Y; X*Y
## [1]  2  2  5  5  2 10
## [1]   50  200  180  320 1250  360

也可以運算平方與開根號:

a<-c(2,3,4); b<-a^2; print(b)
## [1]  4  9 16
c<-sqrt(b); print(c)
## [1] 2 3 4

4.2 進位

進位的指令有:

  • round:四捨五入
  • floor:強制捨去
  • ceiling:強制進位

我們用以下例子顯示進位的指令功能:

a1<-c(2.54, 3.111, 10.999)
round(a1, digits=2)
## [1]  2.54  3.11 11.00
floor(a1)
## [1]  2  3 10
ceiling(a1)
## [1]  3  4 11

5 資料型態作業

  1. 使用orange資料,把Tree變數換成A, B, C, D, E,然後顯示每一個類型的數量。
  2. 請用weekdays()指令顯示今天上課日期是星期二。

  3. 請問在mtcars資料裡面,mpg高於或等於21的資料有幾筆?

  4. 請嘗試建立一個包含流水號序號、一個數字變數、一個類別變數的資料框或資料表。

  5. 請創造一個對角向量為{1,1,1}的矩陣

  6. 請用data.table計算Titanic男性與女性生還的人數。

  7. 請問faithful這筆資料有多少個觀察值?

  8. 請建立三個\(3\times 2\)的陣列

  9. 請把Arrests資料裡面的employed變數改成0, 1

  10. 請用三種格式表示今天的日期

6 基本運算作業

  1. 請問 \(\text{log}(\frac{14}{5})=\)?
  2. 請問 \(1\times 2\times 3\times , \dots ,\times 8=\)?
  3. 請計算英文有幾個字母。

  4. 請寫一段語法把今天的氣溫轉換成華氏

  5. 請問在您寫作業的這一天,今年已經過了幾天?