条件在管道后的if(nrow(.)> 0)中具有长度> 1

yh2wf1be  于 2023-07-31  发布在  其他
关注(0)|答案(3)|浏览(96)

我将我的编码转换为管道使用,遇到了困难。在当前的例子中,我有一个 Dataframe df,它以某种方式被处理,然后一个函数被应用到结果 Dataframe 。大概是这样的:

library(magrittr)
# Create data.
df <- data.frame(a=1:10, b= -10:-1)
# Process data.
df %>% 
  {.$c <- rowSums(.); .} %>%
# Keep only relevant rows
  .[.$c > 11, , drop= FALSE] %>%
# Go on if there are rows left...
  if(nrow(.) > 0){
    print("here is my code")
  } else{
    print("here is my code b")
  }

字符串
运行这个得到Error in if (.) nrow(.) > 0 else { : the condition has length > 1。这里,我想我的代码B关闭。如何调整代码使其工作?

编辑

总结一下答案:不建议在if(...){...}中使用管道,如果您仍然这样做,您的代码将变得笨拙。对我来说,这指向了管道的局限性。

snz8szmq

snz8szmq1#

可以像这样使用if

df %>% 
  {.$c <- rowSums(.); .} %>%
  .[.$c > 11, , drop= FALSE] %>%
  {`if`(nrow(.) == 0, print("here is my code"), print("here is my code b"))}

字符串
或者稍微有点黑客味

df %>% 
  {.$c <- rowSums(.); .} %>%
  .[.$c > 11, , drop= FALSE] %>%
  nrow() %>% 
  `if`(print("here is my code b"), print("here is my code"))

xdnvmnnf

xdnvmnnf2#

不要将数据的子集通过管道传输到if语句。创建一个新的data.frame并将其传递给if语句

library(magrittr)
# Create data.
df <- data.frame(a=1:10, b= -10:-1)
# Process data.
df2 <- df %>% 
  {.$c <- rowSums(.); .} %>%
  # Keep only relevant rows
  .[.$c > 11, , drop= FALSE] 
  # Go on with code a if there are rows left...
  if(nrow(df2) > 0){
    print("here is my code")
    # Code b if there are no rows..
  } else{
    print("here is my code b")
  }

字符串

nlejzf6q

nlejzf6q3#

您可以通过使用额外的{} Package 来修复代码,这将强制显式使用点

library(magrittr)
# Create data.
df <- data.frame(a=1:10, b= -10:-1)
# Process data.
df %>% 
  {.$c <- rowSums(.); .} %>%
  # Keep only relevant rows
  .[.$c > 11, , drop= FALSE] %>%
  # Go on if there are rows left...
  {if(nrow(.) > 0){
    print("here is my code")
  } else{
    print("here is my code b")
  }}
#> [1] "here is my code b"

字符串
它能正常工作的原因是if是一个3参数函数,它接收条件、yes操作和no操作(后面的参数被忽略)
在这里,您向第一个参数中插入了一个点,因此它尝试运行的代码是if(.) nrow(.)>0 else print("here is my code"),其中.是前面步骤的输出(一个 Dataframe ,而不是布尔值)
这是非常奇怪的代码,一个惯用的管道调用看起来更像(仍然使用奇怪的管道if,以避免创建临时变量):

df %>% 
  transform(c = rowSums(.)) %>% 
  subset(c > 11) %>% 
  {if(nrow(.) > 0){
    print("here is my code")
  } else {
    print("here is my code b")
  }}
#> [1] "here is my code b"

# or the following not to use the braces, closer to Cett's solution
df %>% 
  transform(c = rowSums(.)) %>% 
  subset(c > 11) %>% 
  nrow() %>%
  if (.) {
    print("here is my code")
  } else {
    print("here is my code b")
  }
#> [1] "here is my code b"


使用tidyverse的第一步是:

library(tidyverse)
df %>% 
  mutate(c = rowSums(.)) %>% 
  filter(c > 11) %>% 
  ...


如果您想保留语法,但不想用临时变量填充环境,可以使用local()

local({
  df$c <- rowSums(df)
  df <- df[df$c > 11, , drop= FALSE]
  if(nrow(df) > 0){
    print("here is my code")
  } else{
    print("here is my code b")
  }
})
#> [1] "here is my code b"
# df was not modified in your global environment
nrow(df)
#> [1] 10


通常,如果你有复杂的代码,创建了很多变量,你应该使用足够简单的函数,这样它们的执行环境就不会包含那么多的变量,所以你不需要local()来做家务。

相关问题