在 R 中顺序迭代两个列表

Ale*_*lex 6 loops r function sequence

我有两个 df 看起来像这样

library(tidyverse)
iris <- iris%>% mutate_at((1:4),~.+2)
iris2 <- iris 
names(iris2)<-sub(".", "_", names(iris2), fixed = TRUE)
Run Code Online (Sandbox Code Playgroud)

我的目标是减少iris高于相应变量 iniris2的最大值的变量值,以匹配 中的最大值iris2

我写了一个函数来做到这一点。

max(iris$Sepal.Length) 
[1] 9.9
max(iris2$Sepal_Length)
[1] 7.9
# i want every value of iris that is >= to max value of iris2 to be equal to the max value of iris 2.

# my function:
fixmax<- function(data,data2,var1,var2) {
  data<- data %>% 
    mutate("{var1}" := ifelse(get(var1)>=max(data2[[var2]],na.rm = T),
                              max(data2[[var2]],na.rm = T),get(var1)))
  return(data)
}

# apply my function to a variable
tst_iris <- fixmax(iris,iris2,"Sepal.Length","Sepal_Length")
max(tst_iris$Sepal.Length)
7.9 # it works!
Run Code Online (Sandbox Code Playgroud)

我面临的挑战是我想在两个变量列表上依次迭代我的函数——即Sepal.Lengthwith Sepal_LengthSepal.WidthwithSepal_Width等。

有谁知道我怎么能做到这一点?

我尝试使用,Map但我做错了什么。

lst1 <- names(iris[,1:4])
lst2 <- names(iris2[,1:4])
final_iris<- Map(fixmax,iris, iris2,lst1,lst2)
Run Code Online (Sandbox Code Playgroud)

我的目标是获得一个 df ( final_iris),其中每个变量都使用fixmax. 我知道我可以通过在每个变量上运行我的函数来做到这一点。

final_iris <- iris
final_iris <- fixmax(final_iris,iris2,"Sepal.Length","Sepal_Length")
final_iris <- fixmax(final_iris,iris2,"Sepal.Width","Sepal_Width")
final_iris <- fixmax(final_iris,iris2,"Petal.Length","Petal_Length")
final_iris <- fixmax(final_iris,iris2,"Petal.Width","Petal_Width")
Run Code Online (Sandbox Code Playgroud)

但是在实际数据中,我必须运行此操作数十次,并且我希望能够按顺序循环我的函数。有谁知道我环路我fixmaxlst1lst2顺序?

nni*_*loc 6

您可以利用内置于R. 如果数据帧具有相同的列/变量排序函数映射到两个数据帧使用mapplypurrr::map2将逐列迭代而不需要指定列名。

给定两个输入数据帧(df_smalldf_big),步骤是:

  1. 计算每列的最大值df_small以创建df_small_max
  2. pmin函数应用于using 的每一列df_big和每个值(或者如果您更喜欢映射)df_small_maxmapplypurr::map2_dfctidyverse
#set up fake data
df_small <- iris[,1:4]
df_big <- df_small + 2

# find max of each col in df_small
df_small_max <- sapply(df_small, max)

# replace values of df_big which are larger than df_small_max
df_big_fixed <- mapply(pmin, df_big, df_small_max)




# sanity check -- Note the change in Sepal.Width
df_small_max
#> Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
#>          7.9          4.4          6.9          2.5
head(df_big, 3)
#>   Sepal.Length Sepal.Width Petal.Length Petal.Width
#> 1          7.1         5.5          3.4         2.2
#> 2          6.9         5.0          3.4         2.2
#> 3          6.7         5.2          3.3         2.2
head(df_big_fixed, 3)
#>      Sepal.Length Sepal.Width Petal.Length Petal.Width
#> [1,]          7.1         4.4          3.4         2.2
#> [2,]          6.9         4.4          3.4         2.2
#> [3,]          6.7         4.4          3.3         2.2
Run Code Online (Sandbox Code Playgroud)

reprex 包( v2.0.0 )于 2021 年 7 月 31 日创建


Aki*_*ies 3

您的问题可能与数据框本身就是列表这一事实有关。Map()期望非函数参数是相同长度的列表。任何比最长列表短的参数都会被“回收”以匹配其长度。

目前,您拥有:

final_iris<- Map(fixmax,iris, iris2,lst1,lst2)
Run Code Online (Sandbox Code Playgroud)

这实际上相当于:

final_iris<- Map(fixmax,
                 list(iris$Sepal.Length,
                      iris$Sepal.Width,
                      iris$Petal.Length,
                      iris$Petal.Width,
                      iris$Species),
                 list(iris2$Sepal_Length,
                      iris2$Sepal_Width,
                      iris2$Petal_Length,
                      iris2$Petal_Width,
                      iris2$Species),
                 lst1,
                 lst2)
Run Code Online (Sandbox Code Playgroud)

(要理解原因,您必须记住,从技术上讲,像 和 一样的数据框irisiris2幕后是[原子]向量列表。)

我怀疑您希望iris并被iris2提供给每次调用fixmax(). 为了Map()回收这两个向量,需要将它们作为单元素列表提供。就像这样:

final_iris<- Map(fixmax, list(iris), list(iris2),lst1,lst2)
Run Code Online (Sandbox Code Playgroud)

要将数据帧列表合并为单个数据帧,请执行以下操作

do.call(rbind, final_iris)
Run Code Online (Sandbox Code Playgroud)