1 資料的子集合 (Subsetting)

  • 從一筆資料取出部分資料,稱為資料的子集合動作(Subsetting)。子集合可幫助 後續的資料分析,因為很多資料裡面只有一部分是我們所需要的。

  • 在DSC2014Tutorial的套件中,輸入slides(‘Basic’),就可以學習到許多資料子集合的技巧。

1.1 向量子集合

  • 向量的子集合方式可以分成用索引以及which()函數方式:

1.1.1 索引

  • 向量的數學表示方式為 \(x_{i}\),其中下標i表示向量的第幾個元素,我們稱之為索引。從向量取出部分元素的方法就是以括號的方式,例如:
state.name[1]
## [1] "Alabama"
state.abb[1:4]
## [1] "AL" "AK" "AZ" "AR"
sleep$extra[nrow(sleep)]
## [1] 3.4

1.1.2 which()

  • 利用which()設定條件篩選向量內的元素。例如我們想找出哪些美國的州名是以B跟C開頭,可寫語法如下:
state.abb[1:10]
##  [1] "AL" "AK" "AZ" "AR" "CA" "CO" "CT" "DE" "FL" "GA"
state.abb.abb<-substr(state.abb, 1,1)
state.abb[which(state.abb.abb=="B")]
## character(0)
state.abb[which(state.abb.abb=="C")]
## [1] "CA" "CO" "CT"
  • 這裡使用到substr(A, i, j)這個指令,A是字串向量,i是開始擷取向量內的文字的順位,j是結束擷取的位置,我們擷取每一個州名稱的第一個字母,然後存成用state.abb.abb這個向量,再用which()函數,對原本的state.abb向量配對。
  • 請嘗試找出有幾個州的面積大於10萬平方英哩

1.2 列表子集合

  • 請先建立一個列表:
ListA<-list(height=90, width=120, string=state.abb[1:2], data=state.area)
class(ListA)
## [1] "list"

1.2.1 索引

  • 從列表中以索引方式取出資料,格式可以是列表或者是數值、字串:
ListA[c(1,2)]
## $height
## [1] 90
## 
## $width
## [1] 120
ListA[[3]]
## [1] "AL" "AK"
ListA[4]
## $data
##  [1]  51609 589757 113909  53104 158693 104247   5009   2057  58560  58876
## [11]   6450  83557  56400  36291  56290  82264  40395  48523  33215  10577
## [21]   8257  58216  84068  47716  69686 147138  77227 110540   9304   7836
## [31] 121666  49576  52586  70665  41222  69919  96981  45333   1214  31055
## [41]  77047  42244 267339  84916   9609  40815  68192  24181  56154  97914
  • 或者直接使用列表中的名稱:
ListA["height"]
## $height
## [1] 90
ListA[["width"]]
## [1] 120

1.2.2 which()

  • 使用which()篩選列表的資料之前,需要先轉換列表為資料框,然後把因素轉換為數值,而R會按照因素的層級排序,從1開始:
dfA<-data.frame(value=unlist(ListA))
dfA$value
##  [1] "90"     "120"    "AL"     "AK"     "51609"  "589757" "113909" "53104" 
##  [9] "158693" "104247" "5009"   "2057"   "58560"  "58876"  "6450"   "83557" 
## [17] "56400"  "36291"  "56290"  "82264"  "40395"  "48523"  "33215"  "10577" 
## [25] "8257"   "58216"  "84068"  "47716"  "69686"  "147138" "77227"  "110540"
## [33] "9304"   "7836"   "121666" "49576"  "52586"  "70665"  "41222"  "69919" 
## [41] "96981"  "45333"  "1214"   "31055"  "77047"  "42244"  "267339" "84916" 
## [49] "9609"   "40815"  "68192"  "24181"  "56154"  "97914"
dfA$data<-as.numeric(dfA$value)
dfA$data[1:6]
## [1]     90    120     NA     NA  51609 589757
dfA[which(dfA$data<10),]
## [1] value data 
## <0 rows> (or 0-length row.names)
  • 以上是一維的資料,接下來介紹二維的資料子集合。

1.3 矩陣、陣列子集合

1.3.1 索引

  • 矩陣可以表示為:

    \[\begin{bmatrix} x_{11} & x_{12} & x_{13} & \dots & x_{1c} \\ x_{21} & x_{22} & x_{23} & \dots & x_{2c} \\ \ldots \\ x_{r1} & x_{r2} & x_{r3} & \dots & x_{rc} \end{bmatrix}\]
  • \(x_{11},\ldots, x_{r1}\)來自同樣的行(column),而\(x_{11},\ldots, x_{1c}\)來自同樣的列,所以前者可以用\(x_{,1}\)表示,後者\(x_{1,}\)表示。

  • 假設有一個\(3\times 3\)的矩陣,我們用括號來取出其中的一個或是多個數值,或者加以替換:

m1<-matrix(c(1:9), 3, 3)
m1
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9
print(m1[2,2]) #1
## [1] 5
print(m1[c(1:2)]) #2
## [1] 1 2
print(m1[c(1,2),c(1,2)]) #3
##      [,1] [,2]
## [1,]    1    4
## [2,]    2    5
print(m1[c(1,3),c(1,3)]) #4
##      [,1] [,2]
## [1,]    1    7
## [2,]    3    9
print(m1[,1]) #5
## [1] 1 2 3
m1[3,3]<-"Hello" #6
m1
##      [,1] [,2] [,3]   
## [1,] "1"  "4"  "7"    
## [2,] "2"  "5"  "8"    
## [3,] "3"  "6"  "Hello"
  • 以上面語法中第3題的[c(1,2),c(1,2)]為例,矩陣對應索引的方式為(1,1),(2,1),(1,2),(2,2),因此得到:
\[\begin{bmatrix} 1 & 4 \\ 2 & 5 \end{bmatrix}\]

1.3.2 which()

  • 對於矩陣或是陣列,R可以傳回每一個符合條件的行與列的對應資料,例如:
T <- array(1:20, dim=c(5, 4))
T1 <-which(T >= 17)
arrayInd(T1, .dim = dim(T))
##      [,1] [,2]
## [1,]    2    4
## [2,]    3    4
## [3,]    4    4
## [4,]    5    4
  • ’arrayInd’在多重陣列的資料特別有用,因為可以找出特定的元素,例如資料儲存在三個陣列中,我們要找出介於10到20之間的元素位置:
# Create a 3-dimensional array
arr <- array(sample(1:30, 24), dim = c(2, 2, 3))
# Print the array
print(arr)
## , , 1
## 
##      [,1] [,2]
## [1,]    1   14
## [2,]    7   11
## 
## , , 2
## 
##      [,1] [,2]
## [1,]   30   12
## [2,]    2   23
## 
## , , 3
## 
##      [,1] [,2]
## [1,]    8    9
## [2,]   26   15
#Indices
arrayInd(which(arr>10 & arr<20), .dim = c(2, 2, 3))
##      [,1] [,2] [,3]
## [1,]    1    2    1
## [2,]    2    2    1
## [3,]    1    2    2
## [4,]    2    2    3
  • 在上述例子中,陣列中符合條件的元素落在第一張表的(1,1)、第二張表的(2,1),依此類推。
  • 找到這些元素之後,可以進一步分析哪些表出現我們所要的元素。

1.4 資料框子集合

  • 資料框與矩陣類似,都有兩個象限,所以子集合的方法相近。

1.4.1 索引

  • 索引對象可以是資料框的行或是列的編號,也可以是欄位名稱,注意逗號前面是列,後面是行:
data(sleep)
names(sleep)
## [1] "extra" "group" "ID"
sleep[1:3, ]
##   extra group ID
## 1   0.7     1  1
## 2  -1.6     1  2
## 3  -0.2     1  3
sleep[, "extra"]
##  [1]  0.7 -1.6 -0.2 -1.2 -0.1  3.4  3.7  0.8  0.0  2.0  1.9  0.8  1.1  0.1 -0.1
## [16]  4.4  5.5  1.6  4.6  3.4

1.4.2 %in%

  • 當資料有一欄編號,可以用\(\%\textrm{in}\%\)方式擷取特定列的資料:
head(sleep)
##   extra group ID
## 1   0.7     1  1
## 2  -1.6     1  2
## 3  -0.2     1  3
## 4  -1.2     1  4
## 5  -0.1     1  5
## 6   3.4     1  6
sleep[sleep$ID %in% c(1,2,3), ] #select by ID
##    extra group ID
## 1    0.7     1  1
## 2   -1.6     1  2
## 3   -0.2     1  3
## 11   1.9     2  1
## 12   0.8     2  2
## 13   1.1     2  3
sleep[sleep$ID %in% c(1,2,3) & sleep$group %in% c(1), ] # two conditions
##   extra group ID
## 1   0.7     1  1
## 2  -1.6     1  2
## 3  -0.2     1  3
  • \(\%\textrm{in}\%\)的意義是「屬於」,例如:
A<-c(0:5); B<-c(1:20)
A%in%B
## [1] FALSE  TRUE  TRUE  TRUE  TRUE  TRUE
  • 應用到資料框的子集合,則是列的序號對應為真則留下,為偽則不留下。

1.4.3 which()

  • which()可容納超過一個以上的條件,而且可以用「且」或是「或」連結條件與條件。針對資料框,可以比對出符合每一個條件的「列」,並且傳回向量。研究者可以由此取出對應的列。
cond <- which(sleep$extra>0.5 & sleep$group==1)
sleep[cond, ]
##    extra group ID
## 1    0.7     1  1
## 6    3.4     1  6
## 7    3.7     1  7
## 8    0.8     1  8
## 10   2.0     1 10
  • 比較\(\%\textrm{in}\%\)以及which(),可得到相同結果:
mtcars[mtcars$cyl %in% c(4,8), ]
##                      mpg cyl  disp  hp drat    wt  qsec vs am gear carb
## Datsun 710          22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
## Hornet Sportabout   18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
## Duster 360          14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
## Merc 240D           24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
## Merc 230            22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
## Merc 450SE          16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
## Merc 450SL          17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
## Merc 450SLC         15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
## Cadillac Fleetwood  10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
## Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
## Chrysler Imperial   14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
## Fiat 128            32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
## Honda Civic         30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
## Toyota Corolla      33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
## Toyota Corona       21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
## Dodge Challenger    15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
## AMC Javelin         15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
## Camaro Z28          13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
## Pontiac Firebird    19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
## Fiat X1-9           27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
## Porsche 914-2       26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
## Lotus Europa        30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
## Ford Pantera L      15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
## Maserati Bora       15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
## Volvo 142E          21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2
mtcars[which(mtcars$cyl==4 | mtcars$cyl==8) , ]
##                      mpg cyl  disp  hp drat    wt  qsec vs am gear carb
## Datsun 710          22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
## Hornet Sportabout   18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
## Duster 360          14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
## Merc 240D           24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
## Merc 230            22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
## Merc 450SE          16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
## Merc 450SL          17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
## Merc 450SLC         15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
## Cadillac Fleetwood  10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
## Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
## Chrysler Imperial   14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
## Fiat 128            32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
## Honda Civic         30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
## Toyota Corolla      33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
## Toyota Corona       21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
## Dodge Challenger    15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
## AMC Javelin         15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
## Camaro Z28          13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
## Pontiac Firebird    19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
## Fiat X1-9           27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
## Porsche 914-2       26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
## Lotus Europa        30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
## Ford Pantera L      15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
## Maserati Bora       15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
## Volvo 142E          21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2

2 用dplyr的功能創造子資料

  • dplyr 這個套件裡面有select以及filter兩個函數,可以選擇特別變數,或者符合特定條件的觀察值。

2.1 select

  • 我們可以選擇一筆資料中某一個或某些變數,減輕我們看資料的負擔。例如我們只留下一個變數:
df <- dplyr::select(iris, Species)
head(df)
##   Species
## 1  setosa
## 2  setosa
## 3  setosa
## 4  setosa
## 5  setosa
## 6  setosa
  • 我們也可以只留下兩個變數,例如:
library(pscl)
## Classes and Methods for R originally developed in the
## Political Science Computational Laboratory
## Department of Political Science
## Stanford University (2002-2015),
## by and under the direction of Simon Jackman.
## hurdle and zeroinfl functions by Achim Zeileis.
seats <- dplyr::select(AustralianElections, ALPSeats, LPSeats)
head(seats)
##   ALPSeats LPSeats
## 1       47      55
## 2       52      52
## 3       57      47
## 4       47      57
## 5       45      58
## 6       60      45
  • select_if 可以篩選特定類型資料的變數,例如:
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following object is masked from 'package:kableExtra':
## 
##     group_rows
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
iris.f <- iris |> select_if (is.factor)
head(iris.f)
##   Species
## 1  setosa
## 2  setosa
## 3  setosa
## 4  setosa
## 5  setosa
## 6  setosa
  • 另外一個方式是用函數的方式,例如我們有一筆五支籃球隊的資料,變數有:
    • 隊名
    • 所在的聯盟
    • 第一場比賽得分
    • 第二場比賽得分
    • 第三場比賽得分
  • 如果我們只想看到球隊名稱以及最後一場比賽得分,可以寫程式如下:
baseketball <- data.frame(team=c('Crab', 'Beaver', 'Apollo', 'Easy', 'Falcon'),
         conference=as.factor(c('W', 'S', 'S', 'E', 'E')),
                  game.1=c(79, 77, 86, 88, 95),
                  game.2=c(91, 85, 88, 86, 83),
         game.3=c(71, 105, 82, 85, 103))
df.short <- baseketball %>% select_if(function(x) is.character(x) | all(x == .$game.3))
head(df.short)
##     team game.3
## 1   Crab     71
## 2 Beaver    105
## 3 Apollo     82
## 4   Easy     85
## 5 Falcon    103
  • 我們可以用 select_at 來篩選特定字串的變數,例如加上vars(starts_with()),,可以一次選擇相關字串開頭的變數:
df.select <- baseketball %>% select_at(vars(starts_with('game')))
df.select
##   game.1 game.2 game.3
## 1     79     91     71
## 2     77     85    105
## 3     86     88     82
## 4     88     86     85
## 5     95     83    103
  • 也可以用vars(ends_with()),,可以一次選擇相關字串結尾的變數:
df.iris <- iris %>% select_at(vars(ends_with('length')))
head(df.iris)
##   Sepal.Length Petal.Length
## 1          5.1          1.4
## 2          4.9          1.4
## 3          4.7          1.3
## 4          4.6          1.5
## 5          5.0          1.4
## 6          5.4          1.7
  • vars(contains()),,可以一次選擇包含相關字串的變數:
library(pscl)
seats <- AustralianElections %>% select_at(vars(contains('Seats')))
head(seats)
##   Seats ALPSeats LPSeats NPSeats OtherSeats
## 1   121       47      55      19          0
## 2   121       52      52      17          0
## 3   122       57      47      17          0
## 4   122       47      57      18          0
## 5   122       45      58      19          0
## 6   122       60      45      17          0

2.2 filter

  • 如果想要篩選特定條件的資料,就如同which,可以用filter這個函數。例如從Adler這筆資料中,一口氣選符合三種條件的資料:
library(carData)
Adler.filter <- Adler %>% filter(instruction == 'none' &
                                   expectation == 'high' &
                                   rating > 0)
head(Adler.filter)
##   instruction expectation rating
## 1        none        high     22
## 2        none        high      3
## 3        none        high      4
## 4        none        high      9

3 作業

  1. 讀取africa2023這筆CSV資料,請問人口排名第三的國家是哪一個?

  2. 讀取africa2023這筆CSV資料,請問人口排名第5的國家比起排名第6的國家的人口數差別多少?

  3. 請把美國的州名排成一個陣列,然後找出州名長度多於或等於13的州(提示:nchar()傳回字串的長度)

  4. 請讀取studentsfull.txt這個檔案,然後取出經濟系與化學系的學生資料。

  5. 請從dplyr這個套件中的starwars資料,取出sex == male的子資料。請問有幾筆?

  6. 請從kmed這個套件中的heart資料,取出男性年齡小於40的子資料。請問有幾筆?

  7. 請從kmed這個套件中的heart資料,篩選出只有數字以及邏輯的變數。

  8. 請用dplyr這個套件中的iris資料,篩選出因素性質或者是名稱有花瓣(Petal)的變數。

  9. 請下載nycflights13這個套件,然後篩選出flights這筆資料裡面預定起飛時間是2013年10月1日下午1點到10月1日下午5點之間起飛(time_hour)的資料。(提示:用as.POSIXct這個函數,並且注意時區)

  10. Titanic是一筆函有好幾個表格的資料,裡面有不同艙等、不同性別、不同年齡乘客的生還人數。請找出無人生還的乘客位在哪個表格當中。

4 更新講義時間

## 
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union
## 最後更新時間: 2025-03-10 20:38:17