R学习:R for Data Science 循环-迭代(for while))

R学习往期回顾:

R学习:R for Data Science 向量(1)

R学习:R for Data Science 向量(2)

R学习 从Tidyverse学起,入门R语言 dplyr合并数据

R学习 流程控制 if,else,ifelse

R学习 从Tidyverse学起,入门R语言(tidyr和stringr)

R学习 从Tidyverse学起,入门R语言(tibble,readr和dplyr)

R学习:字符串

R学习:环境和函数

R学习:数据框的基本操作

R学习:R for Data Science(五)

R学习:R for Data Science(四)

R学习:R for Data Science(三)

R学习:R for Data Science(二)

R学习:R for Data Science(一)

函数是减少重复代码的一种工具,其减少重复代码的方法是,先识别出代码中的重复模式,然后将其提取出来,成为更容易修改和重用的独立部分。减少重复代码的另一种工具是迭代,它的作用在于可以对多个输入执行同一种处理,比如对多个列或多个数据集进行同样的操作。

for循环

假设我们有以下这样一个简单的 tibble

library(tidyverse)df <- tibble( a = rnorm(10), b = rnorm(10), c = rnorm(10), d = rnorm(10))

我们想要计算出每列的中位数。你完全可以使用复制粘贴来完成这个任务:

median(df$a)median(df$b)median(df$c)median(df$d)

但这样做就违反了我们的经验法则:永远不要复制粘贴超过 2 次。相反,我们应该使用for 循环:

output <- vector("double", ncol(df)) # 1. 输出for (i in seq_along(df)) { # 2. 序列 output[[i]] <- median(df[[i]]) # 3. 循环体}output

每个 for 循环都包括 3 个部分

输出: output <- vector("double", length(x))
在开始循环前,你必须为输出结果分配足够的空间。这对循环效率非常重要,如果在每次迭代中都使用 c() 来保存循环的结果,那么 for 循环的速度就会特别慢。创建给定长度的空向量的一般方法是使用 vector() 函数,该函数有两个参数:向量类型("logical"、 "integer"、 "double"、 "character" 等)和向量的长度。

序列: i in seq_along(df)
这部分确定了使用哪些值来进行循环:每一轮 for 循环都会赋予 i 一个来自于 seq_along(df) 的不同的值。我们可以将 i 看作一个代词,和 it 类似。

循环体: output[[i]] <- median(df[[i]])
这部分就是执行具体操作的代码。它们会重复运行,每次运行都使用一个不同的 i值。第一次迭代运行的是 output[[1]] <- median(df[[1]]),第二次迭代运行的是output[[2]] <- median[[2]],以此类推。

for循环的变体

如果已经掌握了基础的 for 循环,那么你就应该再熟悉一下它的几种变体。不管进行何种迭代,这些变体都非常重要。因此,即使在下一节中掌握了函数式编程技术,也不要忘了如何使用这些变体

在基础 for 循环之上有 4 种变体
· 修改现有对象,而不是创建新对象。
· 使用名称或值进行迭代,而不是使用索引。
· 处理未知长度的输出。
· 处理未知长度的序列。

1 修改现有对象

有时我们会希望使用 for 循环来修改现有的对象。例如,回想一下第 14 章中的一个问题,我们希望对数据框中的每列进行调整:

df <- tibble( a = rnorm(10), b = rnorm(10), c = rnorm(10), d = rnorm(10))rescale01 <- function(x) { rng <- range(x, na.rm = TRUE) (x - rng[1]) / (rng[2] - rng[1])}#将每一列数据标准化到0-1之间df$a <- rescale01(df$a)df$b <- rescale01(df$b)df$c <- rescale01(df$c)df$d <- rescale01(df$d)

为了使用 for 循环解决这个问题,我们还是先思考一下 for 循环的 3 个部分

输出:
我们已经有了输出,和输入是相同的!

序列:
我们可以将数据框看作数据列的列表,因此可以使用 seq_along(df) 在每列中进行迭代。

函数体:
可以使用 rescale01() 函数。
因此可以写出以下代码:

for (i in seq_along(df)) { df[[i]] <- rescale01(df[[i]])}

一般来说,你可以使用类似的循环来修改列表或数据框,要记住使用 [[,而不是 [。你或许已经发现了,我们在所有 for 循环中使用的都是 [[。我们认为甚至在原子向量中最好也使用 [[,因为它可以明确表示我们要处理的是单个元素。

2 循环模式

对向量进行循环的基本方式有 3 种,至此我们只介绍了最常用的一种方式:通过 for (iin seq_along(xs)) 使用数值索引进行循环,并使用 x[[i]] 提取出相应的值。另外两种循环方式如下

· 使用元素进行循环: for (x in xs)。如果只关心副作用,比如绘图或保存文件,那么这种方式是最适合的,因为有效率地保存输出结果是非常困难的。

· 使用名称进行循环: for (nm in names(xs))。这种方式会给出一个名称,你可以使用这个名称和 x[[nm]] 来访问元素的值。如果想要在图表标题或文件名中使用元素名称,那么你就应该使用这种方式。

如果想要创建命名的输出向量,请一定按照如下方式进行命名:

results <- vector("list", length(x))names(results) <- names(x)

使用数值索引进行循环是最常用的方式,因为给定位置后,就可以提取出元素的名称和值

for (i in seq_along(x)) { name <- names(x)[[i]] value <- x[[i]]}

3 未知的输出长度

有时你可能不知道输出的长度。例如,假设你想模拟长度随机的一些随机向量。你或许想要通过逐渐增加向量长度的方式来解决这个问题:

means <- c(0, 1, 2)output <- double()
for (i in seq_along(means)) { n <- sample(100, 1) output <- c(output, rnorm(n, means[[1]]))}str(output)

但这并不是一种非常高效的方式,因为 R 要在每次迭代中复制上一次迭代中的所有数据。从技术角度来看,你执行了一种“平方”(O(n2))操作,这意味着,如果元素数量增加到原来的 3 倍,那么循环时间就要增加到原来的 9 倍。

更好的解决方式是将结果保存在一个列表中,循环结束后再组合成一个向量

means <- c(0, 1, 2)out <- vector("list", length(means))for (i in seq_along(means)) { n <- sample(100, 1) out[[i]] <- rnorm(n, means[[i]])}str(out)
str(unlist(out))

这里我们使用了 unlist() 函数将一个向量列表转换为单个向量。更严格的一种转换方式是使用 purrr::flatten_dbl() 函数,如果输入不是双精度型列表,那么它就会抛出一个错误。

其他情况下也可以使用这种编码模式
· 你或许会生成一个很长的字符串。不要使用 paste() 函数将每次迭代的结果与上一次连接起来,而应该将每次迭代结果保存在字符向量中,然后再使用 paste(output,collapse = "") 将这个字符向量组合成一个字符串。

· 你或许会生成一个很大的数据框。不要在每次迭代中依次使用 rbind() 函数,而应该将每次迭代结果保存在列表中,再使用dplyr::bind_rows(output) 将结果组合成数据框。

注意这种模式。只要遇到类似情况,就应该使用一个更复杂的对象来保存每次迭代的结果,最后再一次性组合起来。

4 未知的序列长度

有时你甚至不知道输入序列的长度。这种情况在模拟时很常见。例如,在掷硬币时,你想要循环到连续 3 次掷出正面向上。这种迭代不能使用 for 循环来实现,而应该使用 while循环。 while 循环比 for 循环更简单,因为前者只需要 2 个部分:条件和循环体。

while (condition) { # 循环体}

while 循环也比 for 循环更常用,因为任何 for 循环都可以使用 while 循环重新实现,但不是所有 while 循环都能使用 for 循环重新实现

for (i in seq_along(x)) { # 循环体}
# 等价于
i <- 1while (i <= length(x)) { # 循环体 i <- i + 1}

在以下示例中,我们使用 while 循环找出了连续 3 次掷出正面向上的硬币所需的投掷次数:

flip <- function() sample(c("T", "H"), 1)flips <- 0nheads <- 0while (nheads < 3) { if (flip() == "H") { nheads <- nheads + 1 } else { nheads <- 0 } flips <- flips + 1}flips

下回继续

(0)

相关推荐

  • 一文讲解Python教程:for循环语句

    Python中的for循环是迭代循环,可以遍历任何的序列对象或可迭代对象,如str.list.tuple.dict等. 遍历时,for循环语句将遍历对象中的所有成员,遍历顺序与成员在对象中的顺序一致, ...

  • R语言简单for循环

    欢迎来到医科研,这里是白介素2的读书笔记,跟我一起聊临床与科研的故事, 生物医学数据挖掘,R语言,TCGA.GEO数据挖掘. 简单for循环  创建一个简单数据框 1Sys.setlocale('LC ...

  • 科技·Kotlin从入门到精通,循环控制

    循环结构是在一定条件下反复执行某段程序的流程结构,被反复执行的程序被称为循环体.循环语句是由循环体及循环的终止条件两部分组成的.For循环for循环可以对任何提供迭代器(iterator)的对象进行遍 ...

  • 想仅报名单细胞数据分析学习班,请先独立完成一个R考核题

    最近我们生信技能树发布了一年一度的单细胞线下5天学习班 一年一度的生信技能树单细胞线下培训班火热招生 报名者众多,有趣的是大部分人对前面的3天生物信息学基础知识课不感兴趣,想直接报名2天的单细胞学习班 ...

  • 用 PyTorch 实现基于字符的循环神经网络 | Linux 中国

    导读:在过去的几周里,我花了很多时间用 PyTorch 实现了一个 char-rnn 的版本.我以前从未训练过神经网络,所以这可能是一个有趣的开始. 本文字数:7201,阅读时长大约:9分钟 http ...

  • 【R分享|实战】一次有趣的尝试~函数定义与循环

    " 敢于尝试,快乐无穷."   --科白君 "R分享实战"专刊·第8篇   编辑 | 科白维尼   1000字 | 5分钟阅读 本期推送内容 一次有趣的尝试.主 ...

  • R学习:R for Data Science 循环-迭代 purrr 函数代替 for 循环

    R学习往期回顾: R学习:R for Data Science 循环-迭代(for while)) R学习:R for Data Science 向量(1) R学习:R for Data Scienc ...

  • R学习:R for Data Science(一)

    R语言学习系列 今天我们来开始一起学习一本书:R for Data Science 数据科学是一个极其广阔的领域,仅靠一本书是不可能登堂入室的.本书的目标是教会你使用最重要的数据科学工具.在一个典型的 ...

  • R学习:R for Data Science(二)

    R语言学习系列 昨天我们开始了R for Data Science这本书的学习,今天我们来继续学习 R学习:R for Data Science(一) 分面 添加额外变量的一种方法是使用图形属性.另一 ...

  • R学习:R for Data Science(三)

    R语言学习系列 今天我们来继续学习R for Data Science R学习:R for Data Science(一) R学习:R for Data Science(二) 统计变换 接下来我们看一 ...

  • R学习:R for Data Science(四)

    前面我们学了该书得第一章节,使用ggplot2进行数据可视化,现在我们开始学习第二章节,本章节内容丰富,值得收藏! R学习:R for Data Science(一) R学习:R for Data S ...

  • R学习:R for Data Science(五)

    R学习:R for Data Science(一) R学习:R for Data Science(二) R学习:R for Data Science(三) R学习:R for Data Science ...

  • R学习:R for Data Science(六) 使用forcats处理因子

    R学习往期回顾: R学习 从Tidyverse学起,入门R语言 dplyr合并数据 R学习 流程控制 if,else,ifelse R学习 从Tidyverse学起,入门R语言(tidyr和strin ...

  • R学习:R for Data Science(七)函数

    R学习往期回顾: R学习:R for Data Science(六)使用forcats处理因子 R学习 从Tidyverse学起,入门R语言 dplyr合并数据 R学习 流程控制 if,else,if ...

  • R学习:R for Data Science 向量(1)

    R学习往期回顾: R学习 从Tidyverse学起,入门R语言 dplyr合并数据 R学习 流程控制 if,else,ifelse R学习 从Tidyverse学起,入门R语言(tidyr和strin ...