【r<-包|迭代】用purrr實(shí)現(xiàn)迭代

函數(shù)有3個(gè)好處:

  • 更容易看清代碼意圖
  • 更容易對需求變化做出反應(yīng)(改變)
  • 更容易減少程序bug

除了函數(shù),減少重復(fù)代碼的另一種工具是迭代,它的作用在于可以對多個(gè)輸入執(zhí)行同一種處理,比如對多個(gè)列或多個(gè)數(shù)據(jù)集進(jìn)行同樣的操作妥畏。

迭代方式主要有兩種:

  • 命令式編程 - for和while
  • 函數(shù)式編程 - purrr

準(zhǔn)備工作

purrr是tidyverse的核心r包之一,提供了一些更加強(qiáng)大的編程工具及舍。

library(tidyverse)
#> ─ Attaching packages ─────────────────────────────────────────────────── tidyverse 1.2.1 ─
#> ? ggplot2 3.0.0     ? purrr   0.2.5
#> ? tibble  1.4.2     ? dplyr   0.7.6
#> ? tidyr   0.8.1     ? stringr 1.3.1
#> ? readr   1.1.1     ? forcats 0.3.0
#> ─ Conflicts ──────────────────────────────────────────────────── tidyverse_conflicts() ─
#> ? dplyr::filter() masks stats::filter()
#> ? dplyr::lag()    masks stats::lag()

for循環(huán)與函數(shù)式編程

因?yàn)镽是一門函數(shù)式編程語言,我們可以先將for循環(huán)包裝在函數(shù)中窟绷,然后再調(diào)用函數(shù)锯玛,而不是使用for循環(huán),因此for循環(huán)在R中不像在其他編程語言中那么重要兼蜈。

為了說明函數(shù)式編程攘残,我們先利用下面簡單的數(shù)據(jù)框進(jìn)行一些思考:

df = tibble(
    a = rnorm(10),
    b = rnorm(10),
    c = rnorm(10),
    d = rnorm(10)
)

如果想要計(jì)算每列的均值,我們使用for循環(huán)完成任務(wù):

output = vector("double", length(df))

for (i in seq_along(df)) {
    output[[i]] = mean(df[[i]])
}

output
#> [1]  0.45635 -0.17938  0.32879  0.00263

然后我們可能意識到需要頻繁地計(jì)算每列的均值饭尝,因此將代碼提取出來肯腕,轉(zhuǎn)換為一個(gè)函數(shù):

col_mean = function(df) {
    output = vector("double", length(df))
    for ( i in seq_along(df)) {
        output[i] = mean(df[[i]])
    }
    
    output
}

然后我們覺得可能還需要這樣計(jì)算每列的中位數(shù)和標(biāo)準(zhǔn)差,因此復(fù)制粘貼了col_mean()钥平,并使用相應(yīng)的median()sd()函數(shù)替換了mean()函數(shù):

col_median = function(df) {
    output = vector("double", length(df))
    for ( i in seq_along(df)) {
        output[i] = median(df[[i]])
    }
    
    output
}

col_sd = function(df) {
    output = vector("double", length(df))
    for ( i in seq_along(df)) {
        output[i] = sd(df[[i]])
    }
    
    output
}

(有時(shí)候我還真這么干的实撒。)

哎呀姊途,我們又復(fù)制粘貼了2次代碼,因此是不是該思考下如何擴(kuò)展一個(gè)代碼讓它同時(shí)發(fā)揮幾個(gè)函數(shù)的功能呢知态?這段代碼的大部分是一個(gè)for循環(huán)捷兰,而且如果不仔細(xì)很難看出3個(gè)函數(shù)有什么差別。

通過添加支持函數(shù)到每列的參數(shù)负敏,我們可以使用同一個(gè)函數(shù)解決3個(gè)問題:

col_summary = function(df, fun){
    out = vector("double", length(df))
    for (i in seq_along(df)) {
        out[i] = fun(df[[i]])
    }
    out
}

col_summary(df, median)
#> [1] 0.4666 0.0269 0.6161 0.0573
col_summary(df, mean)
#> [1]  0.45635 -0.17938  0.32879  0.00263

將函數(shù)作為參數(shù)傳入另一個(gè)函數(shù)的做法是一種非常強(qiáng)大的功能贡茅,我們需要花些時(shí)間理解這種思想,但絕對是值得的其做。接下來我們將學(xué)習(xí)和使用purrr包顶考,它提供的函數(shù)可以替代很多常見的for循環(huán)應(yīng)用。R基礎(chǔ)包中的apply應(yīng)用函數(shù)族也可以完成類似的任務(wù)妖泄,但purrr包的函數(shù)更一致驹沿,也更容易學(xué)習(xí)。

使用purrr函數(shù)替代for循環(huán)的目的是將常見的列表問題分解為獨(dú)立的幾部分

  • 對于列表的單個(gè)元素蹈胡,我們能找到解決辦法嗎渊季?如果可以,我們就能使用purrr將該方法擴(kuò)展到列表的所有元素罚渐。
  • 如果我們面臨的是一個(gè)復(fù)雜的問題却汉,那么將其分解為可行的子問題,然后依次解決荷并。使用purrr合砂,我們可以解決子問題,然后用管道將其組合起來源织。

映射函數(shù)

先對向量進(jìn)行循環(huán)既穆,然后對其每一個(gè)元素進(jìn)行一番處理,最后保存結(jié)果雀鹃。這種模式太普遍了,因而purrr包提供了一個(gè)函數(shù)族替我們完成這種操作励两。每種類型的輸出都有一個(gè)相應(yīng)的函數(shù):

  • map()用于輸出列表
  • map_lgl()用于輸出邏輯型向量
  • map_dbl()用于輸出雙精度型向量
  • map_chr()用于輸出字符型向量

每個(gè)函數(shù)都使用一個(gè)向量(注意列表可以作為遞歸向量看待)作為輸入黎茎,并對向量的每個(gè)元素應(yīng)用一個(gè)函數(shù),然后返回和輸入向量同樣長度的一個(gè)新向量当悔。向量的類型由映射函數(shù)的后綴決定傅瞻。

使用map()函數(shù)族的優(yōu)勢不是速度,而是簡潔:它可以讓我們的代碼更易編寫盲憎,也更易閱讀嗅骄。

下面是進(jìn)行上一節(jié)一樣的操作:

library(purrr)

map_dbl(df, mean)
#>        a        b        c        d 
#>  0.45635 -0.17938  0.32879  0.00263
map_dbl(df, median)
#>      a      b      c      d 
#> 0.4666 0.0269 0.6161 0.0573
map_dbl(df, sd)
#>     a     b     c     d 
#> 0.608 1.086 0.797 0.873

**與for循環(huán)相比,映射函數(shù)的重點(diǎn)在于需要執(zhí)行的操作(即mean()饼疙、median()sd())溺森,而不是在所有元素中循環(huán)所需的跟蹤記錄以及保存結(jié)果。使用管道時(shí)這一點(diǎn)尤為突出:

df %>% map_dbl(mean)
#>        a        b        c        d 
#>  0.45635 -0.17938  0.32879  0.00263
df %>% map_dbl(median)
#>      a      b      c      d 
#> 0.4666 0.0269 0.6161 0.0573
df %>% map_dbl(sd)
#>     a     b     c     d 
#> 0.608 1.086 0.797 0.873

map_*()col_summary()具有以下幾點(diǎn)區(qū)別:

  • 所有的purrr函數(shù)都是用C實(shí)現(xiàn)的,這讓它們的速度非称粱快医窿,但犧牲了一些可讀性。
  • 第二個(gè)參數(shù)可以是一個(gè)公式炊林、一個(gè)字符向量或一個(gè)整型向量姥卢。
  • map_*()使用....f傳遞一些附加參數(shù),供每次調(diào)用時(shí)使用
  • 映射函數(shù)還保留名稱

快捷方式

對于第二個(gè)參數(shù).f渣聚,我們可以使用幾種快捷方式來減少輸入量独榴。比如我們現(xiàn)在想對某個(gè)數(shù)據(jù)集中的每一個(gè)分組都擬合一個(gè)線性模型,下面示例將mtcars數(shù)據(jù)集拆分為3個(gè)部分(按照氣缸值分類)奕枝,并對每個(gè)部分?jǐn)M合一個(gè)線性模型:

models = mtcars %>% 
    split(.$cyl) %>% 
    map(function(df) lm(mpg ~ wt, data = df))

因?yàn)樵赗中創(chuàng)建匿名函數(shù)的語法比較復(fù)雜棺榔,所以purrr提供了一種更方便的快捷方式——單側(cè)公式:

models = mtcars %>% 
    split(.$cyl) %>% 
    map(~lm(mpg ~ wt, data = .))

上面.作為一個(gè)代詞:它表示當(dāng)前列表元素(與for循環(huán)中用i表示當(dāng)前索引是一樣的)。

當(dāng)檢查多個(gè)模型時(shí)倍权,有時(shí)候我們需要提取像R方這樣的摘要統(tǒng)計(jì)量掷豺,要想完成這個(gè)任務(wù),我們需要先運(yùn)行summary()函數(shù)薄声,然后提取結(jié)果中的r.squared:

models %>% 
    map(summary) %>% 
    map_dbl(~.$r.squared)
#>     4     6     8 
#> 0.509 0.465 0.423

因?yàn)樘崛∶煞植僮鞣浅F毡榈贝詐urrr提供了一種更簡單的快捷方式:使用字符串。

models %>% 
    map(summary) %>% 
    map_dbl("r.squared")
#>     4     6     8 
#> 0.509 0.465 0.423

對操作失敗的處理

當(dāng)使用映射函數(shù)重復(fù)多次操作時(shí)默辨,某次操作失敗的概率大大增加德频。這個(gè)時(shí)候我們會收到一條錯(cuò)誤信息,但得不到任何結(jié)果缩幸。這讓人很惱火壹置!我們怎么保證不會出現(xiàn)一條魚腥了一鍋湯?

safely()是一個(gè)修飾函數(shù)(副詞)表谊,它接收一個(gè)函數(shù)(動詞)钞护,對其進(jìn)行修改并返回修改后的函數(shù)。這樣爆办,修改后的函數(shù)就不會拋出錯(cuò)誤难咕,相反,它總是返回由下面兩個(gè)元素組成的列表:

  • result - 原始結(jié)果距辆。如果出現(xiàn)錯(cuò)誤余佃,那么它就是NULL
  • error - 錯(cuò)誤對象。如果操作成功跨算,那么它就是NULL

下面用log()函數(shù)進(jìn)行說明:

safe_log = safely(log)
str(safe_log(10))
#> List of 2
#>  $ result: num 2.3
#>  $ error : NULL

str(safe_log("a"))
#> List of 2
#>  $ result: NULL
#>  $ error :List of 2
#>   ..$ message: chr "數(shù)學(xué)函數(shù)中用了非數(shù)值參數(shù)"
#>   ..$ call   : language log(x = x, base = base)
#>   ..- attr(*, "class")= chr [1:3] "simpleError" "error" "condition"

safely()函數(shù)也可以與map()共同使用:

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 "數(shù)學(xué)函數(shù)中用了非數(shù)值參數(shù)"
#>   .. ..$ call   : language log(x = x, base = base)
#>   .. ..- attr(*, "class")= chr [1:3] "simpleError" "error" "condition"

如果將以上結(jié)果轉(zhuǎn)換為2個(gè)列表爆土,一個(gè)列表包含所有錯(cuò)誤對象,另一個(gè)列表包含所有原始結(jié)果诸蚕,那么處理起來就會更容易步势。我們可以使用purrr::transpose()函數(shù)輕松完成該任務(wù)

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 "數(shù)學(xué)函數(shù)中用了非數(shù)值參數(shù)"
#>   .. ..$ call   : language log(x = x, base = base)
#>   .. ..- attr(*, "class")= chr [1:3] "simpleError" "error" "condition"

我們可以自行決定如何處理錯(cuò)誤對象氧猬,一般來說,我們應(yīng)該檢查一下y中錯(cuò)誤對象所對應(yīng)的x值立润,或者使用y中的正常結(jié)果進(jìn)行一些處理:

is_ok = y$error %>% map_lgl(is_null)
x[!is_ok]
#> [[1]]
#> [1] "a"

y$result[is_ok] %>% flatten_dbl()
#> [1] 0.0 2.3

purrr還提供了兩個(gè)有用的修飾函數(shù):

  • safely()類似狂窑,possibly()函數(shù)總是會成功返回。它比safely()還要簡單一些桑腮,因?yàn)榭梢栽O(shè)定出現(xiàn)錯(cuò)誤時(shí)返回一個(gè)默認(rèn)值:
x = list(1, 10, "a")
x %>% map_dbl(possibly(log, NA_real_))
#> [1] 0.0 2.3  NA
  • quietly()函數(shù)與safely()的作用基本相同泉哈,但前者結(jié)果不包含錯(cuò)誤對象,而是包含輸出破讨、消息和警告:
x = list(1, -1)
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 NaN
#>   ..$ output  : chr ""
#>   ..$ warnings: chr "產(chǎn)生了NaNs"
#>   ..$ messages: chr(0)

x %>% map(safely(log)) %>% str()
#> Warning in .f(...): 產(chǎn)生了NaNs
#> List of 2
#>  $ :List of 2
#>   ..$ result: num 0
#>   ..$ error : NULL
#>  $ :List of 2
#>   ..$ result: num NaN
#>   ..$ error : NULL

多參數(shù)映射

前面我們提到的映射函數(shù)都是對單個(gè)輸入進(jìn)行映射丛晦,但有時(shí)候我們需要多個(gè)相關(guān)輸入同步迭代,這就是map2()和pmap()函數(shù)的用武之地提陶。

例如我們想模擬幾個(gè)均值不同的隨機(jī)正態(tài)分布烫沙,我們可以使用map完成這個(gè)任務(wù):

mu = list(5, 10, -3)
mu %>% 
    map(rnorm, n = 5) %>% 
    str()
#> List of 3
#>  $ : num [1:5] 5.65 6.48 6.35 4.61 4.74
#>  $ : num [1:5] 8.93 8.93 10.67 10.98 8.72
#>  $ : num [1:5] -4.04 -3.25 -2.16 -3.02 -2.53

如果我們想讓標(biāo)準(zhǔn)差也不同,一種方法是使用均值向量和標(biāo)準(zhǔn)差向量的索引進(jìn)行迭代:

sigma = list(1, 5, 10)
seq_along(mu) %>% 
    map(~rnorm(5, mu[[.]], sigma[[.]])) %>% 
    str()
#> List of 3
#>  $ : num [1:5] 4.5 4.73 4.43 6.19 5.47
#>  $ : num [1:5] 8.71 8.59 18.26 7.93 4.93
#>  $ : num [1:5] -21.46 -7.94 -21.41 5.66 2.38

但這種方式比較難理解隙笆,我們使用map2()進(jìn)行同步迭代:

map2(mu, sigma, rnorm, n = 5) %>% str()
#> List of 3
#>  $ : num [1:5] 6.08 6.72 7.59 5.21 3.99
#>  $ : num [1:5] 13.44 6.81 3.61 22.29 14.29
#>  $ : num [1:5] 4.05 -1.77 -2.77 0.69 -23.91

注意這里每次調(diào)用時(shí)值發(fā)生變換的參數(shù)要放在映射函數(shù)前面锌蓄,值不變的參數(shù)要放在映射函數(shù)后面。

map()函數(shù)一樣撑柔,map2()函數(shù)也是對for循環(huán)的包裝:

map2 = function(x, y, f, ...){
    out = vector("list", length(x))
    for (i in seq_along(x)) {
        out[[i]] = f(x[[i]], y[[i]], ...)
    }
    out
}

(實(shí)際的map2()并不是這樣的瘸爽,此處是給出R實(shí)現(xiàn)的一種思想)

根據(jù)這個(gè)函數(shù),我們可以涉及map3()铅忿、map4()等等剪决,但這樣實(shí)在無聊。purrr提供了pmap()函數(shù)檀训,它可以將列表作為參數(shù)柑潦。如果我們想要生成均值、標(biāo)準(zhǔn)差和樣本數(shù)都不同的正態(tài)分布峻凫,可以使用:

n = list(1, 3, 5)
args1 = list(n, mu, sigma)

args1 %>% 
    pmap(rnorm) %>% 
    str()
#> List of 3
#>  $ : num 3.55
#>  $ : num [1:3] 8.4 10.9 -3.3
#>  $ : num [1:5] 3.9 -11.61 2.06 7.14 -16.25

如果沒有為列表元素命名渗鬼,那么pmap()在調(diào)用函數(shù)時(shí)會按照位置匹配。這樣做容易出錯(cuò)而且可讀性差荧琼,因此最后使用命名參數(shù):

args2 = list(mean = mu, sd = sigma, n = n)
args2 %>% 
    pmap(rnorm) %>% 
    str()
#> List of 3
#>  $ : num 6.18
#>  $ : num [1:3] 11.2 18 14.8
#>  $ : num [1:5] -5.27 6.57 1.88 6.53 -8.35

這樣更加安全乍钻。

因?yàn)殚L度都相同,所以將各個(gè)參數(shù)保存在一個(gè)數(shù)據(jù)框中:

params = tibble::tribble(
    ~mean, ~sd, ~n,
    5, 1, 1,
    10, 5, 3,
    -3, 10, 5
)

params %>% 
    pmap(rnorm)
#> [[1]]
#> [1] 5.41
#> 
#> [[2]]
#> [1]  5.4 10.2 14.4
#> 
#> [[3]]
#> [1] -8.653 -4.457  9.747 -4.916 -0.436

調(diào)用不同的函數(shù)

還有一種更復(fù)雜的情況:不但傳給函數(shù)的參數(shù)不同铭腕,甚至函數(shù)本身也是不同的。

f = c("runif", "rnorm", "rpois")
param = list(
    list(min = -1, max = 1),
    list(sd = 5),
    list(lambda = 10)
)

為了處理這種情況多糠,我們使用invoke_map()函數(shù):

invoke_map(f, param, n = 5) %>% str()
#> List of 3
#>  $ : num [1:5] 0.167 -0.235 -0.366 -0.933 0.304
#>  $ : num [1:5] 6.961 3.642 13.405 0.536 -2.078
#>  $ : int [1:5] 8 8 8 6 11

第1個(gè)參數(shù)是一個(gè)函數(shù)列表或包含函數(shù)名稱的字符串向量累舷。第2個(gè)參數(shù)是列表的一個(gè)列表,給出了要傳給各個(gè)函數(shù)的不同參數(shù)夹孔。隨后的參數(shù)要傳給每個(gè)函數(shù)被盈。

我們使用tribble()讓參數(shù)配對更容易:

sim = tibble::tribble(
    ~f, ~params,
    "runif", list(min = -1, max = 1),
    "rnorm", list(sd = 5),
    "rpois", list(lambda = 10)
)


sim %>% 
    dplyr::mutate(sim = invoke_map(f, params, n = 10))
#> # A tibble: 3 x 3
#>   f     params     sim       
#>   <chr> <list>     <list>    
#> 1 runif <list [2]> <dbl [10]>
#> 2 rnorm <list [1]> <dbl [10]>
#> 3 rpois <list [1]> <int [10]>

游走函數(shù)

當(dāng)使用函數(shù)的目的是向屏幕提供輸出或?qū)⑽募4娴酱疟P——重要的是操作過程而不是返回值析孽,我們應(yīng)該使用游走函數(shù),而不是映射函數(shù)只怎。

下面是一個(gè)示例:

x = list(1, "a", 3)

x %>% 
    walk(print)
#> [1] 1
#> [1] "a"
#> [1] 3

一般來說袜瞬,walk()函數(shù)不如walk2()和pwalk()實(shí)用。例如有一個(gè)圖形列表和一個(gè)文件名向量身堡,那么我們就可以使用pwalk()將每個(gè)文件保存到相應(yīng)的磁盤位置:

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 5 in image
#> Saving 7 x 5 in image
#> Saving 7 x 5 in image

我們來查看一下是不是建立好了:

dir(tempdir())
#> [1] "4.pdf" "6.pdf" "8.pdf"

for循環(huán)的其他模式

purrr還提供了其他一些函數(shù)邓尤,雖然這些函數(shù)的使用率低,但了解還是有必要的贴谎。本節(jié)就是對它們進(jìn)行簡單介紹

預(yù)測函數(shù)

一些函數(shù)可以與返回TRUEFALSE的預(yù)測函數(shù)一同使用汞扎。

keep()discard()函數(shù)可以分別保留輸入中預(yù)測值為TRUEFALSE的元素(在數(shù)據(jù)框中就是指列):

iris %>% 
    keep(is.factor) %>% 
    str()
#> 'data.frame':    150 obs. of  1 variable:
#>  $ Species: Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...


iris %>% 
    discard(is.factor) %>% 
    str()
#> 'data.frame':    150 obs. of  4 variables:
#>  $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#>  $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#>  $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#>  $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...

some()every()函數(shù)分別用來確定預(yù)測值是否對某個(gè)元素為真以及是否對所有元素為真:

x = list(1:5, letters, list(10))


x %>% 
    some(is_character)
#> [1] TRUE

x %>% 
    every(is_vector)
#> [1] TRUE

detect()可以找出預(yù)測值為真的第一個(gè)元素,detect_index()可以返回該元素的索引擅这。

x = sample(10)
x
#>  [1] 10  8  5  7  4  1  2  9  3  6

x %>% 
    detect(~ . >5)
#> [1] 10

x %>% 
    detect_index(~ . >5)
#> [1] 1

head_while()tail_while()分別從向量的開頭和結(jié)尾找出預(yù)測值為真的元素:

x %>% 
    head_while(~ . > 5)
#> [1] 10  8

x %>% 
    tail_while(~ . > 5)
#> [1] 6

歸約和累計(jì)

操作一個(gè)復(fù)雜的列表澈魄,有時(shí)候我們想要不斷合并兩個(gè)預(yù)算兩個(gè)元素(基礎(chǔ)函數(shù)Reduce干的事情)。

dfs = list(
    age = tibble(name = "John", age = 30),
    sex = tibble(name = c("John", "Mary"), sex = c("M", "F")),
    trt = tibble(name = "Mary", treatment = "A")
)

dfs %>% reduce(full_join)
#> Joining, by = "name"
#> Joining, by = "name"
#> # A tibble: 2 x 4
#>   name    age sex   treatment
#>   <chr> <dbl> <chr> <chr>    
#> 1 John     30 M     <NA>     
#> 2 Mary     NA F     A

這里我們使用reduce結(jié)合dplyr中的full_join()將它們輕松合并為一個(gè)數(shù)據(jù)框仲翎。

reduce()函數(shù)使用一個(gè)“二元函數(shù)”(即兩個(gè)基本輸入)痹扇,將其不斷應(yīng)用于一個(gè)列表,直到最后只剩下一個(gè)元素溯香。

累計(jì)函數(shù)與歸約函數(shù)類似鲫构,但會保留中間結(jié)果,比如下面求取累計(jì)和:

x = sample(10)

x
#>  [1]  9 10  8  5  6  2  3  4  7  1
x %>% accumulate(`+`)
#>  [1]  9 19 27 32 38 40 43 47 54 55

文章作者 王詩翔

上次更新 2018-10-04

許可協(xié)議 CC BY-NC-ND 4.0

purrr loop

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末逐哈,一起剝皮案震驚了整個(gè)濱河市芬迄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌昂秃,老刑警劉巖禀梳,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異肠骆,居然都是意外死亡算途,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進(jìn)店門蚀腿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嘴瓤,“玉大人,你說我怎么就攤上這事莉钙±啵” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵磁玉,是天一觀的道長停忿。 經(jīng)常有香客問我,道長蚊伞,這世上最難降的妖魔是什么席赂? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任吮铭,我火速辦了婚禮,結(jié)果婚禮上颅停,老公的妹妹穿的比我還像新娘谓晌。我一直安慰自己,他們只是感情好癞揉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布纸肉。 她就那樣靜靜地躺著,像睡著了一般烧董。 火紅的嫁衣襯著肌膚如雪毁靶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天逊移,我揣著相機(jī)與錄音预吆,去河邊找鬼。 笑死胳泉,一個(gè)胖子當(dāng)著我的面吹牛拐叉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播扇商,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼凤瘦,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了案铺?” 一聲冷哼從身側(cè)響起蔬芥,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎控汉,沒想到半個(gè)月后笔诵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡姑子,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年乎婿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片街佑。...
    茶點(diǎn)故事閱讀 39,919評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡谢翎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出沐旨,到底是詐尸還是另有隱情森逮,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布磁携,位于F島的核電站吊宋,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜璃搜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鳞上。 院中可真熱鬧这吻,春花似錦、人聲如沸篙议。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鬼贱。三九已至移怯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間这难,已是汗流浹背舟误。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留姻乓,地道東北人嵌溢。 一個(gè)月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像蹋岩,于是被迫代替她去往敵國和親赖草。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評論 2 354

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