如何将Lapply与mutate函数一起使用

时间:2019-07-12 08:30:01

标签: r if-statement dplyr lapply mutate

如何将lapply与mutate函数一起使用

您好,我正在尝试将lapply与mutate函数一起使用。我正在处理嵌套列表数据。

让我们举个例子。 given是具有两个元素的嵌套列表。每个元素都是10 * 2列表。

given<-replicate(2,list(matrix(unlist(replicate(10,sample(c(0.2,0.3,0.4,0.1),2,replace=FALSE),simplify=FALSE)),ncol=2)))
colnames(given[[1]])<-c('a','b')
colnames(given[[2]])<-c('a','b')
given

我将0.1和0.2转换为“低”,将0.3转换为“中”,将0.4转换为“高”。我使用了lapply,mutate和if_else函数。

new_given<-lapply(seq_along(given), function(x){
  mutate(x,
         given[[x]][['new']] = if_else(given[[x]][['a']] %in% c(0.1,0.2),'low',
                                      if_else(given[[x]][['I12']] %in% c(0.3),'middle','high')))})

但是,发生了错误。它说有一个'意外的')''。但是,括号中的数字是右配对的。

> new_given<-lapply(seq_along(given), function(x){
+   mutate(x,
+          given[[x]][['new']] = if_else(given[[x]][['a']] %in% c(0.1,0.2),'low',
Error: unexpected '=' in:
"  mutate(x,
         given[[x]][['new']] ="
>                                       if_else(given[[x]][['I12']] %in% c(0.3),'middle','high')))})
Error: unexpected ')' in "                                      if_else(given[[x]][['I12']] %in% c(0.3),'middle','high'))"
> 

您能告诉我问题出在哪里以及如何解决吗?

*其他信息:我读了这篇文章,Using lapply with mutate in R 但是,它使用data.frame,而不处理列表数据。因此,方法似乎有所不同。

2 个答案:

答案 0 :(得分:1)

首先,您要获得矩阵列表,而不是数据帧列表。另外,您可以在此处将lapply引向given而不是进行seq_along

library(dplyr)

lapply(given, function(x) {  
   data.frame(x) %>%
     mutate(new = if_else(a %in% c(0.1,0.2),'low',
                             if_else(a %in% c(0.3),'middle','high')))})


#[[1]]
#     a   b    new
#1  0.2 0.1    low
#2  0.1 0.2    low
#3  0.4 0.4   high
#4  0.3 0.2 middle
#5  0.1 0.3    low
#6  0.3 0.1 middle
#7  0.4 0.2   high
#8  0.1 0.3    low
#9  0.3 0.1 middle
#10 0.4 0.3   high

#[[2]]
#     a   b    new
#1  0.3 0.1 middle
#2  0.1 0.3    low
#3  0.3 0.1 middle
#4  0.2 0.3    low
#5  0.1 0.4    low
#6  0.4 0.1   high
#7  0.1 0.2    low
#8  0.2 0.3    low
#9  0.4 0.4   high
#10 0.3 0.1 middle

此外,更好的方法是将方法分开。因此,纯基础R解决方案就是

lapply(given, function(x) 
      transform(data.frame(x), 
       new = ifelse(a %in% c(0.1,0.2),'low',ifelse(a %in% c(0.3),'middle','high'))))

而您更喜欢tidyverse

map(given, ~ data.frame(.) %>%
             mutate(new = if_else(a %in% c(0.1,0.2),'low',
                               if_else(a %in% c(0.3),'middle','high'))))

答案 1 :(得分:1)

您的方法有很多问题。首先,您遇到的错误只是在发生第一个错误(意外的'=')之后复制其余行的副作用。

错误的原因不同。您正在将mutate应用于xx是长度为1的数字矢量。但是,mutate仅适用于数据帧(甚至不包括矩阵!)。不过,您可以先将矩阵转换为data.frames(正如Ronak在另一个答案中所建议的那样)。

最后,您的矩阵是两倍。您的方法可能大部分时间都有效,但不能保证始终有效,因为即使数字看起来像0.3,实际上也可能是0.3000000000000000001,在这种情况下,%in% 0.3返回FALSE。现在看来似乎不太可能,但请相信我,这种方法迟早会伤害您并且您不会看到它来的。我是凭经验说话的。

让我们首先创建一个采用矩阵的函数,并根据其第一列确定其应为“低”,“中”还是“高”。

cut函数需要多个中断,并为每个数字分配一个表示给定间隔的因子级别:

cut(given[[1]][,1], c(-Inf, 0.2, 0.3, Inf))

结果:

 [1] (0.3, Inf] (-Inf,0.2] (-Inf,0.2] (0.3, Inf] (-Inf,0.2] (0.3, Inf]
 [7] (-Inf,0.2] (-Inf,0.2] (0.3, Inf] (-Inf,0.2]
Levels: (-Inf,0.2] (0.2,0.3] (0.3, Inf]

我们可以直接为结果分配标签:

cut(given[[1]][,1], c(-Inf, 0.2, 0.3, Inf), labels=c("low", "mid", "high"))

我们可以将其变成一个函数:

mklevels <- function(mtx) {
  cut(mtx[,1], c(-Inf, 0.2, 0.3, Inf), labels=c("low", "mid", "high"))
}

不是将矩阵转换为数据帧并添加新列,而是为什么不创建每个矩阵只有一列的新数据框:

data.frame(sapply(given, mklevels))

这样做的好处是,如果矩阵很大并且用于其他计算目的,则将它们更改为数据帧不是一种有效的方法。

如果您确实希望使用%in%,然后将数据转换为因数。这样,您将能够检查因子水平并查看是否存在问题。例如:

x <- c(0.3, 0.2, 0.3 + 1e-11, 0.1)
x

看起来足够无辜:

> x
[1] 0.3 0.2 0.3 0.1

但是,x[4] %in% .3返回FALSE。但是将其转换为一个因子并查看其水平:

factor(x)

[1] 0.3           0.2           0.30000000001 0.1          
Levels: 0.1 0.2 0.3 0.30000000001

一旦将数据转换为因子,就可以安全地采用Ronak的方法。但是我永远不会尝试使用数字向量!