高級數(shù)據(jù)管理
接下來废膘,我們將講解如何自己編寫函數(shù)來完成數(shù)據(jù)處理和分析任務(wù)。首先般又,我們將探索控制程序流程的多種方式彼绷,包括循環(huán)和條件執(zhí)行語句巍佑。然后,我們將研究用戶自編函數(shù)的結(jié)構(gòu)苛预,以及在編寫完成后如何調(diào)用它們句狼。最后,我們將了解數(shù)據(jù)的整合和概述方法热某,以及數(shù)據(jù)集的重塑和重構(gòu)方法腻菇。
各種函數(shù)的講解
x <- c(1, 2, 3, 4, 5, 6, 7, 8)
mean(x)
## [1] 4.5
sd(x)
## [1] 2.44949
n <- length(x)
meanx <- sum(x)/n
css <- sum((x - meanx)**2)
sdx <- sqrt(css / (n-1))
meanx
## [1] 4.5
sdx
## [1] 2.44949
# Listing 5.2 - Generating pseudo-random numbers from
# a uniform distribution
runif(5)
## [1] 0.4948163 0.1447270 0.4462854 0.1817478 0.0366217
runif(5)
## [1] 0.7535536 0.7257268 0.2369725 0.3417977 0.6111466
set.seed(1234)
runif(5)
## [1] 0.1137034 0.6222994 0.6092747 0.6233794 0.8609154
set.seed(1234)
runif(5)
## [1] 0.1137034 0.6222994 0.6092747 0.6233794 0.8609154
# Listing 5.3 - Generating data from a multivariate
# normal distribution
library(MASS)
options(digits=3)
set.seed(1234)
mean <- c(230.7, 146.7, 3.6)
sigma <- matrix( c(15360.8, 6721.2, -47.1,
6721.2, 4700.9, -16.5,
-47.1, -16.5, 0.3), nrow=3, ncol=3)
mydata <- mvrnorm(500, mean, sigma)
mydata <- as.data.frame(mydata)
names(mydata) <- c("y", "x1", "x2")
dim(mydata)
## [1] 500 3
head(mydata, n=10)
## y x1 x2
## 1 98.8 41.3 3.43
## 2 244.5 205.2 3.80
## 3 375.7 186.7 2.51
## 4 -59.2 11.2 4.71
## 5 313.0 111.0 3.45
## 6 288.8 185.1 2.72
## 7 134.8 165.0 4.39
## 8 171.7 97.4 3.64
## 9 167.2 101.0 3.50
## 10 121.1 94.5 4.10
# Listing 5.4 - Applying functions to data objects
a <- 5
sqrt(a)
## [1] 2.24
b <- c(1.243, 5.654, 2.99)
round(b)
## [1] 1 6 3
c <- matrix(runif(12), nrow=3)
c
## [,1] [,2] [,3] [,4]
## [1,] 0.9636 0.216 0.289 0.913
## [2,] 0.2068 0.240 0.804 0.353
## [3,] 0.0862 0.197 0.378 0.931
log(c)
## [,1] [,2] [,3] [,4]
## [1,] -0.0371 -1.53 -1.241 -0.0912
## [2,] -1.5762 -1.43 -0.218 -1.0402
## [3,] -2.4511 -1.62 -0.972 -0.0710
mean(c)
## [1] 0.465
# Listing 5.5 - Applying a function to the rows
# (columns) of a matrix
mydata <- matrix(rnorm(30), nrow=6)
mydata
## [,1] [,2] [,3] [,4] [,5]
## [1,] 0.459 1.203 1.234 0.591 -0.281
## [2,] -1.261 0.769 -1.891 -0.435 0.812
## [3,] -0.527 0.238 -0.223 -0.251 -0.208
## [4,] -0.557 -1.415 0.768 -0.926 1.451
## [5,] -0.374 2.934 0.388 1.087 0.841
## [6,] -0.604 0.935 0.609 -1.944 -0.866
apply(mydata, 1, mean)
## [1] 0.641 -0.401 -0.194 -0.136 0.975 -0.374
apply(mydata, 2, mean)
## [1] -0.478 0.777 0.148 -0.313 0.292
apply(mydata, 2, mean, trim=.4)
## [1] -0.542 0.852 0.499 -0.343 0.302
一個實例
一組學(xué)生參加了數(shù)學(xué)、科學(xué)和英語考試昔馋。為了給所有學(xué)生確定一個單一的成績衡量指標(biāo)筹吐,需要將這些科目的成績組合起來。另外秘遏,你還想將前20%的學(xué)生評定為A丘薛,接下來20%的學(xué)生評定為B,依次類推邦危。最后洋侨,你希望按字母順序?qū)W(xué)生排序。
觀察此數(shù)據(jù)集倦蚪,馬上可以發(fā)現(xiàn)一些明顯的障礙希坚。首先,三科考試的成績是無法比較的陵且。由于它們的均值和標(biāo)準(zhǔn)差相去甚遠(yuǎn)裁僧,所以對它們求平均值是沒有意義的。你在組合這些考試成績之前慕购,必須將其變換為可比較的單元聊疲。其次,為了評定等級沪悲,你需要一種方法來確定某個學(xué)生在前述得分上百分比排名获洲。再次,表示姓名的字段只有一個殿如,這讓排序任務(wù)復(fù)雜化了昌妹。為了正確地將其排序,需要將姓和名拆開握截。
準(zhǔn)備數(shù)據(jù)
options(digits=2)
Student <- c("John Davis", "Angela Williams",
"Bullwinkle Moose", "David Jones",
"Janice Markhammer", "Cheryl Cushing",
"Reuven Ytzrhak", "Greg Knox", "Joel England",
"Mary Rayburn")
Math <- c(502, 600, 412, 358, 495, 512, 410, 625, 573, 522)
Science <- c(95, 99, 80, 82, 75, 85, 80, 95, 89, 86)
English <- c(25, 22, 18, 15, 20, 28, 15, 30, 27, 18)
roster <- data.frame(Student, Math, Science, English,
stringsAsFactors=FALSE)
#knitr::kable(roster)
表格展示數(shù)據(jù)
Student Math Science English
John Davis 502 95 25
Angela Williams 600 99 22
Bullwinkle Moose 412 80 18
David Jones 358 82 15
Janice Markhammer 495 75 20
Cheryl Cushing 512 85 28
Reuven Ytzrhak 410 80 15
Greg Knox 625 95 30
Joel England 573 89 27
Mary Rayburn 522 86 18
數(shù)據(jù)標(biāo)準(zhǔn)化
由于數(shù)學(xué)、科學(xué)和英語考試的分值不同(均值和標(biāo)準(zhǔn)差相去甚遠(yuǎn))烂叔,在組合之前需
要先讓它們變得可以比較谨胞。一種方法是將變量進(jìn)行標(biāo)準(zhǔn)化,這樣每科考試的成績就都是用單位標(biāo)準(zhǔn)差來表示蒜鸡,而不是以原始的尺度來表示了胯努。這個過程可以使用scale() 函數(shù)來實現(xiàn):
z <- scale(roster[,2:4])
z
## Math Science English
## [1,] 0.013 1.078 0.587
## [2,] 1.143 1.591 0.037
## [3,] -1.026 -0.847 -0.697
## [4,] -1.649 -0.590 -1.247
## [5,] -0.068 -1.489 -0.330
## [6,] 0.128 -0.205 1.137
## [7,] -1.049 -0.847 -1.247
## [8,] 1.432 1.078 1.504
## [9,] 0.832 0.308 0.954
## [10,] 0.243 -0.077 -0.697
## attr(,"scaled:center")
## Math Science English
## 501 87 22
## attr(,"scaled:scale")
## Math Science English
## 86.7 7.8 5.5
score <- apply(z, 1, mean)
roster <- cbind(roster, score)
knitr::kable(roster)
Student Math Science English score
John Davis 502 95 25 0.56
Angela Williams 600 99 22 0.92
Bullwinkle Moose 412 80 18 -0.86
David Jones 358 82 15 -1.16
Janice Markhammer 495 75 20 -0.63
Cheryl Cushing 512 85 28 0.35
Reuven Ytzrhak 410 80 15 -1.05
Greg Knox 625 95 30 1.34
Joel England 573 89 27 0.70
Mary Rayburn 522 86 18 -0.18
然后牢裳,可以通過函數(shù) mean() 來計算各行的均值以獲得綜合得分,并使用函數(shù)
cbind() 將其添加到花名冊中:
劃分等級
函數(shù) quantile() 給出了學(xué)生綜合得分的百分位數(shù)叶沛∑蜒叮可以看到,成績?yōu)锳的分界點為0.74灰署,B的分界點為0.44判帮,等等。
y <- quantile(score, c(.8,.6,.4,.2))
y
## 80% 60% 40% 20%
## 0.74 0.44 -0.36 -0.89
通過使用邏輯運(yùn)算符溉箕,你可以將學(xué)生的百分位數(shù)排名重編碼為一個新的類別型成績
變量晦墙。下面在數(shù)據(jù)框 roster 中創(chuàng)建了變量 grade :
roster$grade[score >= y[1]] <- "A"
roster$grade[score < y[1] & score >= y[2]] <- "B"
roster$grade[score < y[2] & score >= y[3]] <- "C"
roster$grade[score < y[3] & score >= y[4]] <- "D"
roster$grade[score < y[4]] <- "F"
knitr::kable(roster)
Student Math Science English score grade
John Davis 502 95 25 0.56 B
Angela Williams 600 99 22 0.92 A
Bullwinkle Moose 412 80 18 -0.86 D
David Jones 358 82 15 -1.16 F
Janice Markhammer 495 75 20 -0.63 D
Cheryl Cushing 512 85 28 0.35 C
Reuven Ytzrhak 410 80 15 -1.05 F
Greg Knox 625 95 30 1.34 A
Joel England 573 89 27 0.70 B
Mary Rayburn 522 86 18 -0.18 C
按姓和名排序
使用函數(shù) strsplit() 以空格為界把學(xué)生姓名拆分為姓氏和名字。把
strsplit() 應(yīng)用到一個字符串組成的向量上會返回一個列表:
name <- strsplit((roster$Student), " ")
name
## [[1]]
## [1] "John" "Davis"
##
## [[2]]
## [1] "Angela" "Williams"
##
## [[3]]
## [1] "Bullwinkle" "Moose"
##
## [[4]]
## [1] "David" "Jones"
##
## [[5]]
## [1] "Janice" "Markhammer"
##
## [[6]]
## [1] "Cheryl" "Cushing"
##
## [[7]]
## [1] "Reuven" "Ytzrhak"
##
## [[8]]
## [1] "Greg" "Knox"
##
## [[9]]
## [1] "Joel" "England"
##
## [[10]]
## [1] "Mary" "Rayburn"
使用函數(shù) sapply() 提取列表中每個成分的第一個元素肴茄,放入一個儲存名字
的向量 Firstname 晌畅,并提取每個成分的第二個元素,放入一個儲存姓氏的向量Lastname 寡痰。 "["是一個可以提取某個對象的一部分的函數(shù)——在這里它是用來提取列表 name 各成分中的第一個或第二個元素的抗楔。你將使用 cbind()把它們添加到花名冊中。由于已經(jīng)不再需要 student 變量拦坠,可以將其丟棄:
lastname <- sapply(name, "[", 2)
firstname <- sapply(name, "[", 1)
roster <- cbind(firstname,lastname, roster[,-1])
最后连躏,可以使用函數(shù) order() 依姓氏和名字對數(shù)據(jù)集進(jìn)行排序:
roster <- roster[order(lastname,firstname),]
knitr::kable(roster)
firstname lastname Math Science English score grade
6 Cheryl Cushing 512 85 28 0.35 C
1 John Davis 502 95 25 0.56 B
9 Joel England 573 89 27 0.70 B
4 David Jones 358 82 15 -1.16 F
8 Greg Knox 625 95 30 1.34 A
5 Janice Markhammer 495 75 20 -0.63 D
3 Bullwinkle Moose 412 80 18 -0.86 D
10 Mary Rayburn 522 86 18 -0.18 C
2 Angela Williams 600 99 22 0.92 A
7 Reuven Ytzrhak 410 80 15 -1.05 F
控制流
條件語句和循環(huán)語句
循環(huán)
1.for循環(huán)
for(i in 1:5)
print("Hello")
## [1] "Hello"
## [1] "Hello"
## [1] "Hello"
## [1] "Hello"
## [1] "Hello"
2.while循環(huán)
i <- 5
while(i > 0){
print("Hello")
i <- i - 1
}
## [1] "Hello"
## [1] "Hello"
## [1] "Hello"
## [1] "Hello"
## [1] "Hello"
條件
1.if-else結(jié)構(gòu)
(x <- runif(1))
## [1] 0.48
if(x > 0.5){
print("yes")
}else{
print("no")
}
## [1] "no"
2.ifelse結(jié)構(gòu)
(x <- runif(1))
## [1] 0.11
(result <- ifelse(x > 0.5, "yes", "no"))
## [1] "no"
3.switch結(jié)構(gòu)
level <- c("poor","good","excelent")
(i <- round(runif(1,1,3)))
## [1] 2
(result <- switch(level[i],
poor = "you are poor",
good = "yes,good",
excelent = "very good"))
## [1] "yes,good"
用戶自編函數(shù)
R的最大優(yōu)點之一就是用戶可以自行添加函數(shù)。事實上贪婉,R中的許多函數(shù)都是由已有函數(shù)構(gòu)成的反粥。
函數(shù)中的對象只在函數(shù)內(nèi)部使用。返回對象的數(shù)據(jù)類型是任意的疲迂,從標(biāo)量到列表皆可才顿。讓我們看一個示例。
假設(shè)你想編寫一個函數(shù)尤蒿,用來計算數(shù)據(jù)對象的集中趨勢和散布情況郑气。此函數(shù)應(yīng)當(dāng)可以選擇性地給出參數(shù)統(tǒng)計量(均值和標(biāo)準(zhǔn)差)和非參數(shù)統(tǒng)計量(中位數(shù)和絕對中位差)。結(jié)果應(yīng)當(dāng)以一個含名稱列表的形式給出腰池。另外尾组,用戶應(yīng)當(dāng)可以選擇是否自動輸出結(jié)果。除非另外指定示弓,否則此函數(shù)的默認(rèn)行為應(yīng)當(dāng)是計算參數(shù)統(tǒng)計量并且不輸出結(jié)果讳侨。
mystats <- function(x, parametric=TRUE, print=FALSE) {
if (parametric) {
center <- mean(x); spread <- sd(x)
} else {
center <- median(x); spread <- mad(x)
}
if (print & parametric) {
cat("Mean=", center, "\n", "SD=", spread, "\n")
} else if (print & !parametric) {
cat("Median=", center, "\n", "MAD=", spread, "\n")
}
result <- list(center=center, spread=spread)
return(result)
}
# trying it out
set.seed(1234)
x <- rnorm(500)
y <- mystats(x)
y <- mystats(x, parametric=FALSE, print=TRUE)
## Median= -0.021
## MAD= 1