這裡介紹 R 的一些常用函數,以及如何使用這些函數對資料進行基本的分析工作。
R 中有一些函數可以讓我們在處理資料時更快速、更方便,雖然這些不是分析資料必要的函數,不過在某些情況下運用這些函數可以讓整個資料的分析流程更順暢。
tapply 函數
R 提供了各式各樣可以對數值做計算的函數,除了對單一變數做計算的函數之外,有些特別的函數也可以同時對多個變數或子集合做運算,我們拿 vegetation 這個資料來做一個例子,這個資料是黃石國家公園(Yellowstone National Park)與 National Bison Range 所觀測到的草原生態資料,研究的目的在於觀察這裡的生物多樣性是否有隨著時間而改變。
首先把資料讀進 R 中:
Veg <- read.table(file="Vegetation2.txt", header= TRUE)
names(Veg)
輸出為:
[1] "TransectName" "Samples" [3] "Transect" "Time" [5] "R" "ROCK" [7] "LITTER" "ML" [9] "BARESOIL" "FallPrec" [11] "SprPrec" "SumPrec" [13] "WinPrec" "FallTmax" [15] "SprTmax" "SumTmax" [17] "WinTmax" "FallTmin" [19] "SprTmin" "SumTmin" [21] "WinTmin" "PCTSAND" [23] "PCTSILT" "PCTOrgC"
str(Veg)
輸出為
'data.frame': 58 obs. of 24 variables: $ TransectName: Factor w/ 58 levels "A_22_02","A_22_58",..: 2 3 4 5 6 7 1 9 10 11 ... $ Samples : int 1 2 3 4 5 6 7 8 9 10 ... $ Transect : int 1 1 1 1 1 1 1 2 2 2 ... $ Time : int 1958 1962 1967 1974 1981 1994 2002 1958 1962 1967 ... $ R : int 8 6 8 8 10 7 6 5 8 6 ... $ ROCK : num 27 26 30 18 23 26 39 25 24 21 ... $ LITTER : num 30 20 24 35 22 26 19 26 24 16 ... [略]
假設我們想要看看不同的 Veg$Transect 是否會對 Veg$R 造成影響,最直接的方式就是依照 Veg$Transect 的值來區分群組,計算每一個群組的 Veg$R 平均值:
m <- mean(Veg$R)
m1 <- mean(Veg$R[Veg$Transect == 1])
m2 <- mean(Veg$R[Veg$Transect == 2])
m3 <- mean(Veg$R[Veg$Transect == 3])
m4 <- mean(Veg$R[Veg$Transect == 4])
m5 <- mean(Veg$R[Veg$Transect == 5])
m6 <- mean(Veg$R[Veg$Transect == 6])
m7 <- mean(Veg$R[Veg$Transect == 7])
m8 <- mean(Veg$R[Veg$Transect == 8])
c(m, m1, m2, m3, m4, m5, m6, m7, m8)
輸出為
[1] 9.965517 7.571429 6.142857 10.375000 [5] 9.250000 12.375000 11.500000 10.500000 [9] 11.833333
這裡的 m 是所有 Veg$R 的平均值(不分群組),而 m1 到 m8 則是依照每一個 Veg$Transect 數值分群所計算的 Veg$R 平均值,很顯然這樣手動計算每一個群組平均值的方式並不是一個很聰明的作法,這時候可以使用 R 的 tapply 函數,它可以達到同樣的功能,但是只需要一行指令:
tapply(Veg$R, Veg$Transect, mean)
輸出為
1 2 3 4
7.571429 6.142857 10.375000 9.250000
5 6 7 8
12.375000 11.500000 10.500000 11.833333若以具名參數的方式執行,看起來會更清楚:
tapply(X = Veg$R, INDEX = Veg$Transect, FUN = mean)
tapply 函數會以 INDEX 變數為依據,將 X 變數先分成數個群組,再將每一個群組的資料套用 FUN 函數做運算,以下是套用各種不同函數的範例:
Me <- tapply(Veg$R, Veg$Transect, mean)
Sd <- tapply(Veg$R, Veg$Transect, sd)
Le <- tapply(Veg$R, Veg$Transect, length)
cbind(Me, Sd, Le)
輸出為:
Me Sd Le 1 7.571429 1.3972763 7 2 6.142857 0.8997354 7 3 10.375000 3.5831949 8 4 9.250000 2.3145502 8 5 12.375000 2.1339099 8 6 11.500000 2.2677868 8 7 10.500000 3.1464265 6 8 11.833333 2.7141604 6
這個輸出列出了各個群組的 Veg$R 平均值、標準差以及樣本數。
FUN 可以指定為各種 R 的內建函數,甚至也可以使用自己訂的函數。
sapply 與 lapply 函數
在計算變數的平均值、變異數、最小值、最大值與樣本數等數值的時候,我們還是會需要執行類似 mean(Veg$R)、sd(Veg$R)、min(Veg$R)、max(Veg$R) 與 length(Veg$R) 這些指令,但是如果一次要對多個變數計算這些數值的時候(例如計算所有變數的平均值),我們可以使用 sapply 函數:
sapply(Veg[, 5:9], FUN = mean)
R ROCK LITTER ML 9.965517 20.991379 22.853448 1.086207 BARESOIL 17.594828
另外還有一個 lapply 函數,功能跟 sapply 類似,不過輸出的格式有些不同:
lapply(Veg[, 5:9], FUN = mean)
輸出為
$R [1] 9.965517 $ROCK [1] 20.99138 $LITTER [1] 22.85345 $ML [1] 1.086207 $BARESOIL [1] 17.59483
lapply 的輸出是一個 list,而 sapply 的輸出則是一個向量,兩者在功能上沒有差別,只是輸出格式不同而已。
tapply在套用FUN函數計算時,會使用區分群組之後的資料來計算,而lapply與sapply則是使用全部的資料做計算。
lapply 與 sapply 所指定的 X 參數必須要是一個 data frame,如果要處理多個向量變數,可以使用 data.frame 函數建立一個 data frame:
sapply(data.frame(cbind(Veg$R, Veg$ROCK, Veg$LITTER, Veg$ML, Veg$BARESOIL)), FUN = mean)
輸出為
X1 X2 X3 X4
9.965517 20.991379 22.853448 1.086207
X5
17.594828Exercise 1
temperature.xls 包含了 1990 年到 2005 年荷蘭海岸線上 30 個觀測點的氣溫觀測資料,請計算:
- 每一個觀測點(
Station)每個月(Month)的氣溫觀測值平均數。(計算結果應為 30 × 12 的表格) - 每一個觀測點每個月的氣溫觀測值標準差以及樣本數。
summary 函數
summary 是一個可以顯示變數基本資訊的函數,它可以接受一個普通的向量變數、cbind 的輸出或是 data frame:
Z <-cbind(Veg$R, Veg$ROCK, Veg$LITTER)
colnames(Z) <- c("R", "ROCK", "LITTER")
summary(Z)
輸出為
R ROCK
Min. : 5.000 Min. : 0.00
1st Qu.: 8.000 1st Qu.: 7.25
Median :10.000 Median :18.50
Mean : 9.966 Mean :20.99
3rd Qu.:12.000 3rd Qu.:27.00
Max. :18.000 Max. :59.00
LITTER
Min. : 5.00
1st Qu.:17.00
Median :23.00
Mean :22.85
3rd Qu.:28.75
Max. :51.00summary 會計算最小值、第一四分位數(first quartile)、中位數(median)、平均數(mean)、第三四分位數(third quartile)與最大值。我們也可以用比較簡短的指令達到同樣的效果:
summary(Veg[ , c("R","ROCK","LITTER")])
summary(Veg[ , c(5, 6, 7)])
table 函數
table 函數可以產生列聯表(contingency table),幫助我們了解整個資料的狀況。
我們以 Deer.txt 的資料來做說明,這個資料是從不同的時間與地點所採集到的動物資料,這樣研究的其中一項目的是找出動物長度與 E. cervi 寄生蟲的關係。首先將資料讀入,並做一些基本檢查:
Deer <- read.table(file = "Deer.txt", header = TRUE)
names (Deer)
[1] "Farm" "Month" "Year" "Sex" [5] "clas1_4" "LCT" "KFI" "Ecervi" [9] "Tb"
str(Deer)
'data.frame': 1182 obs. of 9 variables: $ Farm : Factor w/ 27 levels "AL","AU","BA",..: 1 1 1 1 1 1 1 1 1 1 ... $ Month : int 10 10 10 10 10 10 10 10 10 10 ... $ Year : int 0 0 0 0 0 0 0 0 0 0 ... $ Sex : int 1 1 1 1 1 1 1 1 1 1 ... $ clas1_4: int 4 4 3 4 4 4 4 4 4 4 ... $ LCT : num 191 180 192 196 204 190 196 200 197 208 ... $ KFI : num 20.4 16.4 15.9 17.3 NA ... $ Ecervi : num 0 0 2.38 0 0 0 1.21 0 0.8 0 ... $ Tb : int 0 0 0 0 NA 0 NA 1 0 0 ...
動物長度與 E. cervi 寄生蟲的關係有可能會跟動物的性別、採樣時間等變數都有關係,但如果某些時間或是地點根本沒有足夠的樣本,會造成分析上的問題,所以我們可以先使用 table 來產生列聯表,確認一下每一個分組的樣本數,例如查看每一個農場的樣本數:
table(Deer$Farm)
輸出為
AL AU BA BE CB CRC HB
15 37 98 19 93 16 35
LCV LN MAN MB MO NC NV
2 34 76 41 278 32 35
PA PN QM R\xd1 RF RO SAL
11 45 75 25 34 44 1
SAU SE TI TN VISO VY
3 26 21 31 15 40從輸出中我們可以看到,MO 這個農場有 278 個樣本,而 SAL 卻只有 1 個樣本,在這樣的狀況下,如果要使用 Deer$Farm 做分析的話,可能可以考慮使用 mixed effects model(Zuur et al., 2009)。
table 也可以產生兩個變數的列聯表,例如:
table(Deer$Sex, Deer$Year)
輸出為
0 1 2 3 4 5 99 1 115 85 154 75 78 34 21 2 76 40 197 123 60 35 0
這裡可以看出來 99 年的樣本中,有一個性別完全沒有資料,這樣的狀況很容易在進行分析的時候產生錯誤,建議在分析這類資料之前,都先以 table 做一下確認。
Exercise 2
繼續使用 Exercise 1 的資料,進行下列分析:
- 以
table檢查每個觀測點的樣本數。 - 以
table檢查每年所採集到的樣本數。 - 建立一個觀測點與年份的列聯表,看看每年中各觀測點的樣本數。
下面這張表是本篇所介紹過的 R 函數總覽。
| 函數 | 說明 | 範例 |
|---|---|---|
tapply | 將 FUN 函數依據 x 分組後,套用在 y。 | tapply (y, x, FUN = mean) |
sapply | 將 FUN 函數套用至 y 的每一個變數。 | sapply (y, FUN = mean) |
lapply | 將 FUN 函數套用至 y 的每一個變數。 | lapply (y, FUN = mean) |
sd | 計算標準差。 | sd (y) |
length | 計算向量長度。 | length (y) |
summary | 顯示變數基本資訊。 | summary (y) |
table | 產生列聯表。 | table (x, y) |
