【R语言】循环遍历机制 :for、purrr::map、apply、repeat、while、迭代器等

【R语言】循环遍历机制 :for、purrr::map、apply、repeat、while、迭代器等

前言

解决一些循环遍历的问题,实操可以在前文“【R语言】csv + excel批量文件的读取、导出处理”查看。

准备

依旧是准备测试文件
在这里插入图片描述

代码

梳理了R语言中一些常见的遍历循环的操作,总共六类。

part_1: for循环

介绍: for 循环结构可以遍历向量或者列表中的每个元素, 循环必有三要素: 输出–>序列–>循环体
模板:

for (var in list) {    # 表达式 expression
 action(var)
}

举例:

:
output <- vector("double", ncol(df))      # 1. 输出  output <- vector("double", length(x))
for ( i in seq_along(df) ) {              # 2. 序列  seq_along() ≈ length() 唯一优势:能区别0;
       output[[i]] <- median(df[[i]])     # 3. 循环体
}
output

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

举例:
sum_100 = 0                           # 1.输出
for(i in seq(from=1,to=100,by=1)){    # 2.序列 
  	sum_100 = sum_100 + i             # 3.循环体
}
sum_100 
part_2: purrr::map

介绍:purrr 包 提供了大量的类似map的函数,可以服务于减少循环、处理嵌套数据、多模型等应用需求,属于R语言中比较常见的编程函数包。
主要内容:

library("purrr")  
purrr::map()       依次应用一元函数到一个序列的每个元素上, 用于输出列表, 基本等同base::lapply() /plyr::lapply()
purrr::map2()      依次应用二元函数到两个序列的每对元素上 map2(x,y,function = x+y)
                   m <- list(1,2,3)
                   n <- list(4,5,6) 
                   map2(m,n, `+`)   # 列表的四维运算, +-*/ ;
purrr::pmap()      应用多元函数到多个序列的每组元素上,可以实现对数据框逐行迭代

map 系列默认返回列表型,可根据想要的返回类型添加后缀:int, _dbl, _lgl, _chr, _df
purrr::map_lgl(data, function)   用于输出逻辑型向量;
purrr::map_int(data, function)   用于输出整型向量;
purrr::map_dbl(data, function)   用于输出双精度型向量;
purrr::map_chr(data, function)   用于输出字符型向量;

可以接着对返回的数据框df做行/列合并:purrr::map_dfr, purrr::map_dfc
purrr::map_dfr(.x, .f, .id = "id_col") # 将函数.f依次应用到序列.x的每个元素返回数据框,再bind_rows按行合并为一个数据框,.id可用来增加新的列描述来源
purrr::map_dfc(.x, .f) 
purrr::map_dfr(set_names(filenames),read_xlsx,.id = "来源")      # id 为来源字段名称 
purrr::map_dfr(set_names(files),~read_xlsx(.x,sheet = 1),.id = "来源")  

PS:
与 for 循环相比,映射函数的重点在于需要执行的操作(即 mean()、median() 和 sd()),而不是在所有元素中循环所需的跟踪记录以及保存结果;
如果不理解,加上使用管道, 可以让两者差距更加明显:

df <- list(a = rnorm(10),
           b = rnorm(10),
           c = rnorm(10)
		   )  
library("magrittr")  # 管道函数 
map_dbl(df, mean)  <=>  df %>% map_dbl(mean) 
# > a b c d #> 0.2026 -0.2068 0.1275 -0.0917 
map_dbl(df, median) <=> df %>% map_dbl(median)
# > a b c d
# > 0.237 -0.218 0.254 -0.133 
map_dbl(df, sd) <=> df %>% map_dbl(sd) 
# > a b c d 
# > 0.796 0.759 1.164 1.062

part_3: ?pply系列

介绍
?pply是一个系列函数,存在于base/plyr两个包中
基本函数格式: ?pply(data, 参数(非必要) ,function() )

主要类别:
apply()   应用矩阵/数组 
lapply()  应用列表/向量 
sapply()  应用列表/向量 
tapply()  
mapply()

详细介绍:
列举了几个函数的详细介绍和使用场景、差异。


(1). apply(X, MARGIN=1/2, FUN)
· 参数说明
· x: 一个数组或者矩阵
· MARGIN=1 : 操作基于行 MARGIN=2: 操作基于列  MARGIN=c(1,2) : 对行和列都进行操作;
· FUN: 使用哪种操作,内置的函数有mean、medium、sum、min、max,用户自定义函数;  

tmp <- matrix(C<-(1:10),nrow=5, ncol=6)
tmp <- apply(tmp, 2, sum)
tmp 


(2). lapply()函数
# 多一个l 代表 输出格式为list,其他和apply无差;
movies <- c("SPYDERMAN","BATMAN","VERTIGO","CHINATOWN")
class(movies)            # 查看数据类型
movies_lower <- lapply(movies, tolower) 
str(movies_lower)        # 输出list形式,故一般用units() 整合
movies_lower <- unlist(lapply(movies,tolower))  


(3). sapply()函数
# 与lapply 无大差异,返回向量;
# 多个参数
dt <- cars[1:5,]
t <- c("red","red","red","blue","bile")
dt <- data.frame(dt,t)
 
lapply(dt, min)        #如果数框中出现非数字结构变量,需指定变量;
sapply(dt, min)
sapply(dt, min, simplify <- F) <- lapply(dt, min)
sapply(dt, min, simplify <- T)  


(4). tapply(X, INDEX, FUN = NULL)
# X: 一个对象,一般都是向量
# INDEX: 一个包含分类因子的列表(list)
# FUN: 对X里面每个元素进行操作的函数
t =c("red","red","red","blue","bile")
dt = data.frame(dt,t)
dt %>% group_by(t) %>% summarise(sum(speed))     # 与tapply同样结果 ,更好用  ps:dplyr包函数;


(5). mapply(FUN,X ...)
用的比较少,和上面没区别,只是参数位置换了 

part_4: repeat结构

介绍: repeat 比较容易理解,有些python的感觉,会用循环break的语句。
本质是简单的重复同一个表达式:repeat expression
如果要跳出循环,可以使用break命令,若要跳至循环中的下一轮迭代,需要使用next命令;
如果在循环中不包括break命令,R代码将会是一个无限循环.

模板:

repeat {
   expression
   if(condition){
        break
   }
}

举例:

# 求1-100的和
i <- 1
sum_100 <- 0
repeat{ sum_100 = sum_100 + i
        i = i + 1
       if(i > 100){
         print(sum_100)
         break
       }
} 
part_5: while结构

介绍: while和repeat有些类似,在某个条件为真时,重复某一特定的表达式,直到条件结束。
模板:

while(condition)  {                   # 条件
				 action(variable)     # 表达式 
				}

举例:

i <- 1
sum_100 <- 0
while(i<=100){
 			  sum_100 <- sum_100 + i;    # 分号不能忘 
  			  i <- i + 1 
  }
print(sum_100)
part_6: 迭代器foreach

介绍: 该部分属于循环的拓展了,C或者java等现代编程语言中,都会有foreach等迭代器. R本身并没有提供这样的机制,只能通过R语言添加包来实现;
详情:
(1)迭代器:从另外一个对象中返回元素的抽象对象.使用迭代器可以使代码具有更好的可读性同时易于并行执行.
添加R语言扩展包iterators可以实现迭代器功能.
迭代器可以返回向量、数组、数据框或者其他对象的元素,当然也可以返回函数.
模板:

iter(obj,checkFunc=function(...) TRUE,recycle=FALSE,...)
# obj 指定对象
# checkFunc 指定一个过滤迭代器返回值的函数
# recyle 指定当对象元素迭代完成之后是否对迭代进行重置

举例:

iter_one <- iter(1:10,checkFunc=function(x) x%%2==0,recycle=F)
nextElem(iter_one)   #nextElem()函数用来查看下一个迭代项,这个函数会隐式地调用checkFunc,如果下一个值符合checkFunc,则返回该值,否则将迭代下一个值,直至找到一个符合checkFunc的值或者将所有值都迭代完毕

(2)foreach循环: 通过R语言扩展包foreach实现,foreach能够循环遍历某个对象(向量、矩阵、数据框或者迭代器)中的多个元素,针对各个元素执行表达式,并返回结果.
模板:

foreach(..., .combine, .init, .final=NULL, .inorder=TRUE,
       .multicombine=FALSE,
       .maxcombine=if (.multicombine) 100 else 2,
       .errorhandling=c('stop', 'remove', 'pass'),
       .packages=NULL, .export=NULL, .noexport=NULL,
       .verbose=FALSE)

真正执行foreach循环,需要使用%do%或者%dopar%运算符

i_square <- foreach(i=1:5) %do% i^2

%do%运算符顺序执行表达式,而%dopar%运算符可以用来并行执行表达式.

总结

以上是梳理总结的一些关于R语言循环遍历机制的内容,希望能帮到大家, 如有错误,欢迎指正。
原创不易,转载请注意出处:
https://blog.csdn.net/weixin_41613094/article/details/128250752

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值