小潔詳解《R數(shù)據(jù)科學(xué)》第16章 Purrr下

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)先看生信星球答疑公告

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末趟紊,一起剝皮案震驚了整個(gè)濱河市氮双,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌霎匈,老刑警劉巖戴差,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異铛嘱,居然都是意外死亡暖释,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門墨吓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來球匕,“玉大人,你說我怎么就攤上這事肛真⌒扯” “怎么了?”我有些...
    開封第一講書人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵蚓让,是天一觀的道長(zhǎng)乾忱。 經(jīng)常有香客問我,道長(zhǎng)历极,這世上最難降的妖魔是什么窄瘟? 我笑而不...
    開封第一講書人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮趟卸,結(jié)果婚禮上蹄葱,老公的妹妹穿的比我還像新娘。我一直安慰自己锄列,他們只是感情好图云,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著邻邮,像睡著了一般竣况。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上筒严,一...
    開封第一講書人閱讀 49,749評(píng)論 1 289
  • 那天丹泉,我揣著相機(jī)與錄音,去河邊找鬼鸭蛙。 笑死摹恨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的娶视。 我是一名探鬼主播晒哄,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了揩晴?” 一聲冷哼從身側(cè)響起勋陪,我...
    開封第一講書人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎硫兰,沒想到半個(gè)月后诅愚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡劫映,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年违孝,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泳赋。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡雌桑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出祖今,到底是詐尸還是另有隱情校坑,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布千诬,位于F島的核電站耍目,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏徐绑。R本人自食惡果不足惜邪驮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望傲茄。 院中可真熱鬧毅访,春花似錦、人聲如沸盘榨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽草巡。三九已至磷斧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間捷犹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來泰國打工冕末, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留萍歉,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓档桃,卻偏偏與公主長(zhǎng)得像枪孩,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容