4 for循環(huán)與函數(shù)式編程
library(tidyverse)
df <- tibble(
a = rnorm(10),
b = rnorm(10),
c = rnorm(10),
d = rnorm(10)
)
用for循環(huán)計(jì)算每列的均值
output <- vector("double", length(df))
for (i in seq_along(df)) {
output[[i]] <- mean(df[[i]])
}
output
#> [1] -0.3893274 0.2581997 -0.3238829 0.2181311
書中給出一個(gè)奇怪的例子來說明函數(shù)組合
f1 <- function(x) abs(x - mean(x)) ^ 1
f2 <- function(x) abs(x - mean(x)) ^ 2
f3 <- function(x) abs(x - mean(x)) ^ 3
#關(guān)于abs:
#絕對(duì)值函數(shù)蚊荣,幫助文檔里還有一句:
#abs(x) returns an integer vector when x is integer or logical.
abs(TRUE)
#> [1] 1
abs(FALSE)
#> [1] 0
f <- function(x, i) abs(x - mean(x)) ^ i
#其實(shí)這個(gè)函數(shù)應(yīng)該是向量化的巩割,x應(yīng)該是個(gè)向量
#直接將df作為x會(huì)導(dǎo)致全是NA
f(df[[1]],3)
#> [1] 3.418992e-01 1.620302e-01 5.253052e-01 4.321956e-02 6.489365e+00
#> [6] 2.156025e+00 4.578027e-02 3.268124e-01 6.154311e-02 2.012281e-06
將函數(shù)作為參數(shù)傳入另一個(gè)函數(shù)
col_summary <- function(df, fun) {
out <- vector("double", length(df))
for (i in seq_along(df)) {
out[i] <- fun(df[[i]])
}
out
}
#操作對(duì)象是df了
col_summary(df,mean)
#> [1] -0.3893274 0.2581997 -0.3238829 0.2181311
col_summary(df, median)
#> [1] -0.2201724 0.2174858 -0.5452395 0.1845153
col_summary(df, sd)
#> [1] 0.9108518 1.1001024 1.1995958 0.6618306
5.映射函數(shù)-map
這是一個(gè)強(qiáng)大的函數(shù)族,直接返回結(jié)果
? map() 用于輸出列表;
? map_lgl() 用于輸出邏輯型向量蛙婴;
? map_int() 用于輸出整型向量;
? map_dbl() 用于輸出雙精度型向量尔破;
? map_chr() 用于輸出字符型向量街图。
map_dbl(df,mean)
#> a b c d
#> -0.3893274 0.2581997 -0.3238829 0.2181311
map_dbl(df,median)
#> a b c d
#> -0.2201724 0.2174858 -0.5452395 0.1845153
map_dbl(df,sd)
#> a b c d
#> 0.9108518 1.1001024 1.1995958 0.6618306
#偷偷試一下指定dbl會(huì)怎么樣
map(df,mean)
#> $a
#> [1] -0.3893274
#>
#> $b
#> [1] 0.2581997
#>
#> $c
#> [1] -0.3238829
#>
#> $d
#> [1] 0.2181311
#返回了一個(gè)列表。還是指定數(shù)據(jù)類型比較好
可以支持管道操作
df %>% map_dbl(mean)
#> a b c d
#> -0.3893274 0.2581997 -0.3238829 0.2181311
df %>% map_dbl(median)
#> a b c d
#> -0.2201724 0.2174858 -0.5452395 0.1845153
df %>% map_dbl(sd)
#> a b c d
#> 0.9108518 1.1001024 1.1995958 0.6618306
創(chuàng)建線性模型(暫時(shí)不用深究懒构,知道實(shí)現(xiàn)了什么即可)
mtcars$cyl
#> [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4
models <- mtcars %>%
split(.$cyl) %>%
map(function(df) lm(mpg ~ wt, data = df))
提取模型的 r.squared--擬合度
models %>%
map(summary) %>%
map_dbl(~.$r.squared) #入門
#> 4 6 8
#> 0.5086326 0.4645102 0.4229655
models %>%
map(summary) %>%
map_dbl("r.squared") #升級(jí)方法
#> 4 6 8
#> 0.5086326 0.4645102 0.4229655
x <- list(list(1, 2, 3), list(4, 5, 6), list(7, 8, 9))
x %>% map_dbl(2)
#> [1] 2 5 8
5.2R基礎(chǔ)包
提取每個(gè)向量中>0.8的數(shù)
x1 <- list(
c(0.27, 0.37, 0.57, 0.91, 0.20),
c(0.90, 0.94, 0.66, 0.63, 0.06),
c(0.21, 0.18, 0.69, 0.38, 0.77)
)
x2 <- list(
c(0.50, 0.72, 0.99, 0.38, 0.78),
c(0.93, 0.21, 0.65, 0.13, 0.27),
c(0.39, 0.01, 0.38, 0.87, 0.34)
)
threshold <- function(x, cutoff = 0.8) x[x > cutoff]
x1 %>% sapply(threshold) %>% str()
#> List of 3
#> $ : num 0.91
#> $ : num [1:2] 0.9 0.94
#> $ : num(0)
x2 %>% sapply(threshold) %>% str()
#> num [1:3] 0.99 0.93 0.87
盯了一會(huì)兒想明白了餐济,為什么同樣類型的兩個(gè)list輸出結(jié)果一個(gè)是list,一個(gè)是向量呢胆剧?
這兩個(gè)list的區(qū)別絮姆,x1中三個(gè)向量,符合要求的數(shù)值各不相同秩霍,而x2中符合要求的個(gè)數(shù)都是1篙悯。所以自動(dòng)選擇了輸出形式,這就是上面說的“你不知道會(huì)得到什么樣的輸出”铃绒。
關(guān)于替代方式vapply鸽照,并沒有給出具體例子來理解,這里的重點(diǎn)是purrr而非基礎(chǔ)包颠悬。
safe_log <- safely(log)
str(safe_log(10))
#> List of 2
#> $ result: num 2.3
#> $ error : NULL
#str(safe_log("a"))
safely函數(shù)用于查看是否有錯(cuò)矮燎。
返回result和error兩個(gè)結(jié)果。二者不可兼得哈哈椿疗。
safely() 也可以與 map() 函數(shù)共同使用
x <- list(1, 10, "a")
y <- x %>% map(safely(log))
str(y)
#> List of 3
#> $ :List of 2
#> ..$ result: num 0
#> ..$ error : NULL
#> $ :List of 2
#> ..$ result: num 2.3
#> ..$ error : NULL
#> $ :List of 2
#> ..$ result: NULL
#> ..$ error :List of 2
#> .. ..$ message: chr "non-numeric argument to mathematical function"
#> .. ..$ call : language log(x = x, base = base)
#> .. ..- attr(*, "class")= chr [1:3] "simpleError" "error" "condition"
#此時(shí)結(jié)果是按照元素匯總成表格漏峰,更理想的情況是按照正誤分別匯總,用導(dǎo)函數(shù)transpose届榄。
#返回2個(gè)list浅乔,正確錯(cuò)誤各自匯總到一起。
y <- y %>% transpose()
str(y)
#> List of 2
#> $ result:List of 3
#> ..$ : num 0
#> ..$ : num 2.3
#> ..$ : NULL
#> $ error :List of 3
#> ..$ : NULL
#> ..$ : NULL
#> ..$ :List of 2
#> .. ..$ message: chr "non-numeric argument to mathematical function"
#> .. ..$ call : language log(x = x, base = base)
#> .. ..- attr(*, "class")= chr [1:3] "simpleError" "error" "condition"
is_ok <- y$error %>% map_lgl(is_null)
x[!is_ok]
#> [[1]]
#> [1] "a"
#返回出錯(cuò)的原始數(shù)據(jù),運(yùn)行正確的顯示結(jié)果。
y$result[is_ok] %>% flatten_dbl()
#> [1] 0.000000 2.302585
另外兩個(gè)函數(shù):possibly和quiet
possibly:成功時(shí)返回結(jié)果靖苇,失敗時(shí)返回默認(rèn)值席噩。
quietly,result包括result output warnings messages
x <- list(1, 10, "a")
x %>% map_dbl(possibly(log, NA_real_))
#> [1] 0.000000 2.302585 NA
x %>% map_dbl(possibly(log,FALSE ))
#> [1] 0.000000 2.302585 0.000000
#后面這行是我亂寫的贤壁,邏輯值被轉(zhuǎn)換成了0悼枢,這個(gè)參數(shù)是設(shè)置錯(cuò)誤返回的默認(rèn)值。
x <- list(1,10)
x %>% map(quietly(log)) %>% str()
#> List of 2
#> $ :List of 4
#> ..$ result : num 0
#> ..$ output : chr ""
#> ..$ warnings: chr(0)
#> ..$ messages: chr(0)
#> $ :List of 4
#> ..$ result : num 2.3
#> ..$ output : chr ""
#> ..$ warnings: chr(0)
#> ..$ messages: chr(0)
#這個(gè)不能存在字符串元素脾拆,否則報(bào)錯(cuò)
7. 多參數(shù)映射
p236
一個(gè)參數(shù)多次改變馒索,生成多組數(shù)據(jù)
mu <- list(5, 10, -3)
mu %>%
map(rnorm,n=5) %>%
str()
#> List of 3
#> $ : num [1:5] 6.06 5.06 4.28 4.67 3.58
#> $ : num [1:5] 9.68 11.99 9.72 11.04 10.51
#> $ : num [1:5] -3.03 -3.12 -1.79 -2.31 -2.84
關(guān)于rnorm,有三個(gè)參數(shù)名船,個(gè)數(shù),均值绰上,標(biāo)準(zhǔn)差。他們的默認(rèn)順序是個(gè)數(shù)-均值-標(biāo)準(zhǔn)差渠驼,想要改變順序蜈块,需要指定參數(shù)名。
2個(gè)參數(shù)多次改變迷扇,生成多組數(shù)據(jù)
rnorm(10)
#> [1] 0.65730448 0.09405843 -0.97479908 -1.28342701 0.67344511
#> [6] -0.13338635 -1.62213469 -0.27219989 -0.36645900 2.14604270
rnorm(5,10)
#> [1] 10.531237 11.055287 10.223192 10.169048 9.877334
rnorm(5,n=10)
#> [1] 5.890862 4.368264 5.896254 5.711182 4.555885 5.992307 6.263651
#> [8] 4.281883 3.434235 4.508614
x <- rnorm(5,20,n=100)
sd(x)
#> [1] 20.61705
mean(x)
#> [1] 4.588476
同一個(gè)函數(shù)中兩個(gè)參數(shù)不同百揭,用map2
三個(gè)以上參數(shù)不同,用pmap蜓席,需要用多個(gè)等長(zhǎng)列表保存不同參數(shù)器一,最好使用命名參數(shù)〕冢可用tribble保存盹舞。
函數(shù)不同,參數(shù)也不同隘庄,用invoke_map()
8.游走函數(shù)
重要的是保存結(jié)果,如多張ggplot繪圖保存(小本本已記下)
library(ggplot2)
plots <- mtcars %>%
split(.$cyl) %>%
map(~ggplot(., aes(mpg, wt)) + geom_point())
paths <- stringr::str_c(names(plots), ".pdf")
pwalk(list(paths, plots), ggsave, path = tempdir())
#> Saving 7 x 7 in image
#> Saving 7 x 7 in image
#> Saving 7 x 7 in image
9.for循環(huán)的其他模式
(1)預(yù)測(cè)函數(shù)
keep和discard
保留true或false對(duì)應(yīng)的元素
some和every
對(duì)某個(gè)元素是否為真癣亚,對(duì)所有元素是否為真
我的理解丑掺,some是:是否存在為真的元素。
x <- list(1:5, letters, list(10))
x %>%
some(is_integer)
#> [1] TRUE
x %>%
some(is_character)
#> [1] TRUE
detect和detect_index
第一個(gè)true的值和位置
head_while tail_while
據(jù)我目測(cè)最后兩個(gè)函數(shù)應(yīng)該是各自查找一半述雾。
(2)歸約與累計(jì)
reduce和accumulate
reduce() 函數(shù)使用一個(gè)“二元”函數(shù)(即具有兩個(gè)基本輸入的函數(shù))街州,將其不斷應(yīng)用于一個(gè)列表,直到最后只剩下一個(gè)元素為止玻孟。
累計(jì)函數(shù)與歸約函數(shù)很相似唆缴,但前者會(huì)保留所有中間結(jié)果。
微信公眾號(hào)生信星球同步更新我的文章黍翎,歡迎大家掃碼關(guān)注面徽!
我們有為生信初學(xué)者準(zhǔn)備的學(xué)習(xí)小組,點(diǎn)擊查看??
想要參加我的線上線下課程,也可加好友咨詢??
如果需要提問,請(qǐng)先看生信星球答疑公告