第一部分:數學、統計和字符處理函數
- 數學和統計函數:R提供了豐富的數學和統計函數,用于執行各種計算和分析。這些函數可以幫助用戶快速完成復雜的數學運算、統計分析等任務,例如計算均值、方差、相關系數、進行假設檢驗等。
- 字符處理函數:R也提供了多種字符處理函數,用于操作和處理字符串數據。這些函數可以用于字符串的拼接、分割、替換、查找等操作,對于文本數據的處理非常有用。
第二部分:循環和條件執行以及自編函數
- 循環和條件執行:這部分將講解如何使用循環(如
for
、while
)和條件語句(如if
、else
)來控制程序的流程。這些控制結構是編程中非常重要的部分,可以幫助用戶實現復雜的邏輯和重復的操作。 - 自編函數:用戶可以自己編寫函數來完成特定的數據處理和分析任務。這部分將介紹如何定義函數、設置函數的參數、返回值等,并且講解如何在實際的數據處理中調用這些自編函數。
第三部分:數據整合與重塑
- 數據整合與概述:這部分將介紹如何對數據進行整合和概述。整合數據時,可以使用內建函數或自編函數來獲取數據的統計信息、匯總信息等,從而對數據有一個全面的了解。
- 數據集的重塑和重構:數據集的重塑和重構是指將數據從一種格式轉換為另一種格式,以滿足不同的分析需求。例如,將寬格式的數據轉換為長格式,或者將數據進行分組、合并等操作。
5.1 一個數據處理難題
問題背景
假設有一組學生參加了數學、科學和英語三門課程的考試。現在需要完成以下任務:
- 組合成績:將三門課程的成績組合成一個單一的成績衡量指標。
- 評定等級:根據組合后的成績,將學生分為不同的等級(A、B、C、D、E),每個等級包含20%的學生。
- 排序:按字母順序對學生進行排序。
數據示例
表5-1展示了部分學生的成績數據:
學生姓名 | 數學 | 科學 | 英語 |
---|---|---|---|
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 |
面臨的挑戰
-
成績不可比:
- 三門課程的成績范圍和分布不同(例如數學成績可能在幾百分,而科學和英語成績可能在0-100分之間)。
- 直接對這些成績求平均是沒有意義的,需要將它們轉換為可比較的單位(例如標準化或歸一化)。
-
評定等級:
- 需要一種方法來確定每個學生在組合成績中的百分比排名。
- 根據百分比排名將學生分為不同的等級(A、B、C、D、E),每個等級包含20%的學生。
-
排序問題:
- 學生姓名是一個整體字段,包含姓和名。
- 為了按字母順序排序,需要將姓和名拆開,分別處理。
解決方案的思路
這段內容的核心是通過R語言中的數值和字符處理函數來解決上述問題。具體步驟可能包括:
- 標準化或歸一化成績:
- 使用數學函數(如
scale()
)將不同范圍的成績轉換為可比較的單位。
- 使用數學函數(如
- 計算百分比排名:
- 使用統計函數(如
rank()
或ecdf()
)計算每個學生的百分比排名。
- 使用統計函數(如
- 評定等級:
- 根據百分比排名將學生分為不同的等級。
- 拆分姓名字段:
- 使用字符處理函數(如
strsplit()
)將學生姓名拆分為姓和名。
- 使用字符處理函數(如
- 排序:
- 使用排序函數(如
order()
)對學生進行排序。
- 使用排序函數(如
5.2 數值和字符處理函數
5.2.1 數學函數
R提供了豐富的數學函數,這些函數可以用于執行各種數學運算和變換。以下是一些常用的數學函數及其描述:
函數 | 描述 | 用例 |
---|---|---|
abs(x) | 絕對值 | abs(-4) 返回值為4 |
sqrt(x) | 平方根 | sqrt(25) 返回值為5,和25^(0.5) 等價 |
ceiling(x) | 不小于x的最小整數 | ceiling(3.475) 返回值為4 |
floor(x) | 不大于x的最大整數 | floor(3.475) 返回值為3 |
trunc(x) | 向0的方向截取的x中的整數部分 | trunc(5.99) 返回值為5 |
round(x, digits=n) | 將x舍入為指定位的小數 | round(3.475, digits=2) 返回值為3.48 |
signif(x, digits=n) | 將x舍入為指定的有效數字位數 | signif(3.475, digits=2) 返回值為3.5 |
cos(x)、sin(x)、tan(x) | 余弦、正弦和正切 | cos(2) 返回值為–0.416 |
acos(x)、asin(x)、atan(x) | 反余弦、反正弦和反正切 | acos(-0.416) 返回值為2 |
cosh(x)、sinh(x)、tanh(x) | 雙曲余弦、雙曲正弦和雙曲正切 | sinh(2) 返回值為3.627 |
acosh(x)、asinh(x)、atanh(x) | 反雙曲余弦、反雙曲正弦和反雙曲正切 | asinh(3.627) 返回值為2 |
log(x, base=n) | 對x取以n為底的對數 | log(10) 返回值為2.3026 |
log10(x) | 對x取以10為底的對數 | log10(10) 返回值為1 |
exp(x) | 指數函數 | exp(2.3026) 返回值為10 |
數據變換
數學函數的一個主要用途是對數據進行變換。例如,對于存在明顯偏倚的變量(如收入),在進一步分析之前取對數是一種常見的做法。數學函數也常用于公式中,用于繪圖函數(例如x
對sin(x)
)和在輸出結果之前對數值進行格式化。
5.2.2 統計函數
統計函數概述
R提供了豐富的統計函數,用于計算各種描述性統計量。這些函數不僅可以直接應用于數值向量,還可以通過參數調整來滿足不同的需求。以下是一些常用的統計函數及其描述:
函數 | 描述 | 用例 |
---|---|---|
mean(x) | 平均數 | mean(c(1,2,3,4)) 返回值為2.5 |
median(x) | 中位數 | median(c(1,2,3,4)) 返回值為2.5 |
sd(x) | 標準差 | sd(c(1,2,3,4)) 返回值為1.29 |
var(x) | 方差 | var(c(1,2,3,4)) 返回值為1.67 |
mad(x) | 絕對中位差(median absolute deviation) | mad(c(1,2,3,4)) 返回值為1.48 |
quantile(x, probs) | 求分位數 | quantile(x, c(0.3, 0.84)) 返回x的30%和84%分位點 |
range(x) | 求值域 | range(c(1,2,3,4)) 返回值為c(1,4) |
diff(range(x)) | 求值域的差 | diff(range(c(1,2,3,4))) 返回值為3 |
sum(x) | 求和 | sum(c(1,2,3,4)) 返回值為10 |
diff(x, lag=n) | 滯后差分 | diff(c(1,5,23,29)) 返回值為c(4,18,6) |
min(x) | 求最小值 | min(c(1,2,3,4)) 返回值為1 |
max(x) | 求最大值 | max(c(1,2,3,4)) 返回值為4 |
scale(x, center=TRUE, scale=TRUE) | 中心化或標準化 | 代碼清單5-6中給出了示例 |
參數的靈活使用
許多統計函數提供了可選參數,這些參數可以顯著影響輸出結果。例如:
y <- mean(x) # 計算x的算術平均數
z <- mean(x, trim = 0.05, na.rm = TRUE) # 計算截尾平均數,丟棄最大5%和最小5%的數據,并忽略缺失值
trim
參數用于計算截尾平均數,可以去除極端值的影響。na.rm
參數用于處理缺失值,設置為TRUE
時會忽略缺失值。
代碼示例:均值和標準差的計算
代碼清單5-1展示了如何計算某個數值向量的均值和標準差的兩種方式。
x <- c(1,2,3,4,5,6,7,8)
mean(x) # 使用R內置函數計算均值
[1] 4.5
sd(x) # 使用R內置函數計算標準差
[1] 2.449490# 手動計算均值和標準差
n <- length(x) # 獲取向量長度
meanx <- sum(x) / n # 計算均值
css <- sum((x - meanx)^2) # 計算修正平方和
sdx <- sqrt(css / (n - 1)) # 計算標準差
meanx # 手動計算的均值
[1] 4.5
sdx # 手動計算的標準差
[1] 2.449490
修正平方和的計算過程
在手動計算標準差的過程中,修正平方和(css)的計算步驟如下:
- 計算向量
x
的平均值meanx
。 - 從
x
的每個元素中減去meanx
,得到偏差向量。 - 對偏差向量的每個元素求平方,得到平方偏差向量。
- 對平方偏差向量的所有元素求和,得到修正平方和
css
。
數據的標準化
數據標準化是數據預處理中的一個重要步驟,它有助于改善分析結果的質量和可靠性。在R中,scale()
函數提供了一種方便的方式來對數據進行標準化處理。
默認標準化
默認情況下,scale()
函數對矩陣或數據框的指定列進行標準化,使得每列的均值為0,標準差為1。這在很多統計分析和機器學習算法中非常有用,因為它們通常假設數據是標準化的。
newdata <- scale(mydata)
mydata
:輸入的矩陣或數據框。newdata
:標準化后的數據。
自定義均值和標準差
如果你希望對每一列進行任意均值和標準差的標準化,可以使用以下代碼:
newdata <- scale(mydata) * SD + M
M
:目標均值。SD
:目標標準差。
這種標準化方式允許你將數據轉換為具有特定均值和標準差的新分布。例如,你可能希望將數據標準化為均值為50,標準差為10的分布:
newdata <- scale(mydata) * 10 + 50
指定列的標準化
如果你只想對數據框中的某一列進行標準化,可以使用transform()
函數。例如,將變量myvar
標準化為均值為50,標準差為10的變量:
newdata <- transform(mydata, myvar = scale(myvar) * 10 + 50)
mydata
:原始數據框。myvar
:需要標準化的列名。newdata
:新的數據框,其中myvar
列已被標準化。
注意事項
- 在非數值型的列上使用
scale()
函數將會報錯。因此,在應用scale()
之前,需要確保數據中不包含非數值型列,或者先將這些列從數據中分離或轉換。 - 數據標準化是許多數據分析和機器學習任務的前提,它有助于提高模型的性能和穩定性。
總結
scale()
函數是R中進行數據標準化的強大工具。通過它可以輕松地將數據標準化為均值為0、標準差為1的格式,也可以通過簡單的數學變換調整為目標均值和標準差。此外,transform()
函數可以方便地對數據框中的指定列進行標準化處理。這些技巧在數據預處理階段非常有用,尤其是在處理具有不同量綱和分布的數據時。
5.2.3 概率函數
概率函數概述
概率函數在統計學中扮演著重要角色,它們不僅用于生成模擬數據,還用于計算概率值。在R中,概率函數通常遵循特定的命名規則,以便于理解和使用。
命名規則
R中的概率函數命名規則如下:
d
:密度函數(density)p
:分布函數(distribution function),通常也稱為累積分布函數(CDF)q
:分位數函數(quantile function),用于找到給定概率值對應的分位點r
:生成隨機數(random deviates)
常用概率函數
表5-4列出了R中常用的一些概率分布及其縮寫:
分布名稱 | 縮寫 |
---|---|
Beta 分布 | beta |
二項分布 | binom |
柯西分布 | cauchy |
卡方分布 | chisq |
指數分布 | exp |
F 分布 | f |
Gamma 分布 | gamma |
幾何分布 | geom |
正態分布 | norm |
泊松分布 | pois |
t 分布 | t |
均勻分布 | unif |
Weibull 分布 | weibull |
正態分布函數
表5-5展示了正態分布的四個基本函數及其用法示例:
問題 | 解法 |
---|---|
在區間[–3, 3]上繪制標準正態曲線 | 使用dnorm 函數計算密度,然后使用plot 繪制曲線 |
位于z=1.96左側的標準正態曲線下方面積是多少? | 使用pnorm(1.96) 計算累積概率,結果為0.975 |
均值為500,標準差為100的正態分布的0.9分位點值為多少? | 使用qnorm(.9, mean=500, sd=100) 計算分位點,結果為628.16 |
生成50個均值為50,標準差為10的正態隨機數 | 使用rnorm(50, mean=50, sd=10) 生成隨機數 |
設置隨機數種子
為了確保結果的可重現性,可以使用set.seed()
函數設置隨機數種子。這樣,每次生成的隨機數序列將是相同的。
生成多元正態數據
在模擬研究和蒙特卡洛方法中,經常需要從多元正態分布中抽取數據。MASS
包中的mvrnorm()
函數可以方便地實現這一需求。其調用格式為:
mvrnorm(n, mean, sigma)
其中:
n
:樣本大小mean
:均值向量sigma
:方差-協方差矩陣
示例:生成多元正態數據
代碼清單5-3展示了如何從一個三元正態分布中抽取500個觀測:
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)
head(mydata, n=10)
- 設置隨機數種子以確保結果可重現。
- 指定均值向量和方差-協方差矩陣。
- 生成500個偽隨機觀測。
- 將結果從矩陣轉換為數據框,并為變量指定名稱。
- 確認數據框的維度,并輸出前10個觀測。
5.2.4 字符處理函數
字符處理函數概述
字符處理函數在R中用于處理文本型數據,它們可以幫助用戶從文本中提取信息或重新設置文本格式。這些函數對于數據清洗、文本分析和報告生成等任務至關重要。
常用字符處理函數
表5-6列出了R中一些最常用的字符處理函數及其描述:
函數 | 描述 |
---|---|
nchar(x) | 計算字符串向量x 中每個元素的字符數量 |
substr(x, start, stop) | 提取或替換字符串向量x 中的子串 |
grep(pattern, x, ...) | 在字符串向量x 中搜索與模式pattern 匹配的元素,并返回匹配元素的下標 |
sub(pattern, replacement, x, ...) | 在字符串向量x 中搜索模式pattern ,并用文本replacement 替換 |
strsplit(x, split, ...) | 在指定的分隔符split 處分割字符串向量x 中的元素 |
paste(..., sep="") | 連接字符串,sep 參數指定連接符 |
toupper(x) | 將字符串向量x 中的所有字符轉換為大寫 |
tolower(x) | 將字符串向量x 中的所有字符轉換為小寫 |
正則表達式
正則表達式提供了一種強大的方式來匹配文本模式。例如,正則表達式^[hc]?at
可以匹配以0個或1個h
或c
開頭,后接at
的任意字符串,如hat
、cat
和at
,但不會匹配bat
。
示例
以下是一些示例,展示了如何使用這些字符處理函數:
x <- c("ab", "cde", "fghij")
nchar(x[3]) # 返回值為5x <- "abcdef"
substr(x, 2, 4) # 返回值為"bcd"
substr(x, 2, 4) <- "22222" # x 將變成"a222ef"grep("A", c("b", "A", "c"), fixed=TRUE) # 返回值為2sub("\\s", ".", "Hello There") # 返回值為Hello.Therey <- strsplit("abc", "") # 返回一個列表,包含"a" "b" "c"
unlist(y)[2] # 返回"b"paste("x", 1:3, sep="") # 返回值為c("x1", "x2", "x3")
paste("x", 1:3, sep="M") # 返回值為c("xM1", "xM2", "xM3")toupper("abc") # 返回值為"ABC"
tolower("ABC") # 返回值為"abc"
5.2.5 其他實用函數
在R中,除了專門針對數值和字符處理的函數外,還有一些實用函數,它們在數據管理和處理中發揮著重要作用,但不容易歸入特定的分類。以下是一些常用的實用函數:
表5-7 其他實用函數
函數 | 描述 |
---|---|
length(x) | 返回對象x 的長度(元素數量) |
seq(from, to, by) | 生成一個從from 到to ,步長為by 的序列 |
rep(x, n) | 將對象x 重復n 次 |
cut(x, n) | 將連續型變量x 分割為n 個水平的因子,可指定ordered_result 創建有序因子 |
pretty(x, n) | 創建美觀的分割點,將連續型變量x 分割為n 個區間,常用于繪圖 |
cat(... , file ="myfile", append =FALSE) | 連接對象并輸出到屏幕或文件中,可使用轉義字符控制格式 |
示例
以下是一些示例,展示了如何使用這些實用函數:
x <- c(2, 5, 6, 9)
length(x) # 返回值為4indices <- seq(1, 10, 2) # 生成序列c(1, 3, 5, 7, 9)y <- rep(1:3, 2) # 返回值為c(1, 2, 3, 1, 2, 3)# 將連續型變量x分割為3個水平的因子
cut(x, 3)# 創建美觀的分割點,將連續型變量x分割為3個區間
pretty(x, 3)firstname <- c("Jane")
cat("Hello", firstname, "\n") # 輸出Hello Janename <- "Bob"
cat("Hello", name, "\b.\n", "Isn\'t R", "\t", "GREAT?\n")
# 輸出:
# Hello Bob.
# Isn't R GREAT?
轉義字符
在cat()
函數中,可以使用轉義字符來控制輸出格式:
\n
:新行\t
:制表符\'
:單引號\b
:退格
例如,在輸出時,可以在句號之前使用退格轉義字符(\b
),以避免在句號后面多出一個空格。
5.2.6 將函數應用于矩陣和數據框
R函數的一個強大特性是它們可以應用于多種數據對象,包括標量、向量、矩陣、數組和數據框。這使得R在數據處理方面非常靈活和強大。
示例:將函數應用于數據對象
代碼清單5-4展示了如何將函數應用于不同類型的數據對象:
a <- 5
sqrt(a) # 返回值為2.236068b <- c(1.243, 5.654, 2.99)
round(b) # 返回值為c(1, 6, 3)c <- matrix(runif(12), nrow=3)
c # 生成一個3x4的矩陣
log(c) # 對矩陣c中的每個元素取對數
mean(c) # 計算矩陣c中所有元素的均值,結果為0.444
應用函數到矩陣和數據框的特定維度
如果你希望對矩陣或數據框的行或列應用函數,可以使用apply()
函數。apply()
函數的格式如下:
apply(x, MARGIN, FUN, ...)
x
:數據對象(矩陣、數組或數據框)。MARGIN
:維度的下標(在矩陣或數據框中,MARGIN=1
表示行,MARGIN=2
表示列)。FUN
:要應用的函數。...
:傳遞給FUN
的任何參數。
示例:將函數應用到矩陣的所有行和列
代碼清單5-5展示了如何將函數應用到矩陣的所有行和列:
mydata <- matrix(rnorm(30), nrow=6)
mydata # 生成一個6x5的矩陣apply(mydata, 1, mean) # 計算每行的均值
apply(mydata, 2, mean) # 計算每列的均值
apply(mydata, 2, mean, trim=0.2) # 計算每列的截尾均值(忽略最高和最低20%的數據)
- 第一個
apply()
計算了6行的均值。 - 第二個
apply()
計算了5列的均值。 - 第三個
apply()
計算了每列的截尾均值,基于中間60%的數據,忽略最高和最低20%的值。
總結
apply()
函數是一種強大的機制,可以將任意R函數應用到矩陣、數組或數據框的任何維度上。這使得它在數據處理和分析中非常有用。此外,lapply()
和sapply()
函數可以將函數應用到列表上,提供了更多的靈活性。
5.3 數據處理難題的一套解決方案
在5.1節中,我們提出了一個數據處理問題,涉及學生考試成績的組合、評分和排序。現在,我們將通過代碼清單5-6展示解決這一問題的詳細步驟。
代碼清單5-6 示例的一種解決方案
-
設置輸出格式:
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)
-
標準化考試成績:
z <- scale(roster[,2:4]) score <- apply(z, 1, mean) roster <- cbind(roster, score)
這里,我們首先使用
scale()
函數對數學、科學和英語成績進行標準化,然后計算每個學生的標準化成績均值,并將這些均值添加到數據框中。 -
計算成績等級:
y <- quantile(score, c(.8,.6,.4,.2)) 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"
使用
quantile()
函數計算成績的分位數,并根據這些分位數將學生成績分為A到F等級。 -
拆分姓名并排序:
name <- strsplit((roster$Student), " ") Lastname <- sapply(name, "[", 2) Firstname <- sapply(name, "[", 1) roster <- cbind(Firstname, Lastname, roster[,-1]) roster <- roster[order(Lastname, Firstname),]
使用
strsplit()
函數拆分學生姓名為姓和名,然后使用sapply()
提取姓和名,最后按姓和名對數據框進行排序。
總結
這個解決方案展示了如何使用R的基本函數來解決實際的數據處理問題。通過標準化考試成績、計算成績等級、拆分和排序姓名,我們能夠將原始數據轉換為一個結構化、易于理解的格式。這些步驟不僅解決了提出的問題,還展示了R在數據處理方面的強大能力。
這個過程也強調了R中函數的靈活性和實用性,無論是在處理標量、向量、矩陣還是數據框時。通過這些基本的數據處理技術,可以為更復雜的數據分析任務打下堅實的基礎。