【问题标题】:R across find only positive or only negative values tidyverseR 跨找到仅正值或仅负值 tidyverse
【发布时间】:2021-05-21 19:02:01
【问题描述】:

在 dplyr Column-wise operations 中有这个例子:

df <- tibble(x = c("a", "b"), y = c(1, 1), z = c(-1, 1))
# Find all rows where EVERY numeric variable is greater than zero
df %>% filter(across(where(is.numeric), ~ .x > 0))
#> # A tibble: 1 x 3
#>   x         y     z
#>   <chr> <dbl> <dbl>
#> 1 b         1     1

如果我们稍微改变一下小标题:

df <- tibble(x = c("a", "b", "c"), y = c(1, 1, -1), z = c(-1, 1, -1))

我们想要为两列获取负值或正值,我们需要为列命名:

df %>% filter((y > 0 & z > 0) | (y < 0 & z < 0))
#> # A tibble: 2 x 3
#>  x         y     z
#>  <chr> <dbl> <dbl>
#> 1 b         1     1
#> 2 c        -1    -1

across() 怎么办?

df %>% filter(across(where(is.numeric), ~ .x > 0 | .x < 0))
#> # A tibble: 3 x 3
#>  x         y     z
#>  <chr> <dbl> <dbl>
#> 1 a         1    -1
#> 2 b         1     1
#> 3 c        -1    -1

【问题讨论】:

  • 很好的问题。

标签: r dplyr across


【解决方案1】:

我认为,由于您在逐行操作中处理 2 个变量,因此使用 map2 包中的 map2 会容易得多:

library(dplyr)
library(purrr)

df <- tibble(x = c("a", "b", "c"), y = c(1, 1, -1), z = c(-1, 1, -1))

df %>%
  filter(map2_lgl(y, z, ~ (.x > 0 & .y > 0) | (.x < 0 & .y < 0)))

# A tibble: 2 x 3
  x         y     z
  <chr> <dbl> <dbl>
1 b         1     1
2 c        -1    -1

【讨论】:

  • 因此还没有办法处理cross。谢谢你的回答。
  • 没有,看看我亲爱的朋友@AnilGoyal 的版本,我也在努力。
  • 请记住,您可以轻松地使用 purrr 函数进行逐行操作。
  • 如果有两个以上的变量,这将不起作用
  • 是的,在这种情况下我们必须使用pmap
【解决方案2】:

我们必须从c(T, T)c(T, F)c(F, F) 等一组条件句中检查所有TRUE 或所有FALSE。现在-

  • if_all 将过滤 c(T, T)
  • !if_any 将从 ! 中再次过滤 c(T, T),即否定剩余值
  • 这两个将由| 加入,即
  • 因此,我们将只有c(T, T) & c(F, F)

这样就可以了

df %>% filter(if_all(where(is.numeric), ~ .x > 0) | !if_any(where(is.numeric), ~ .x < 0))

# A tibble: 2 x 3
  x         y     z
  <chr> <dbl> <dbl>
1 b         1     1
2 c        -1    -1

另类

df %>% filter(if_all(where(is.numeric), ~ .x > 0) | across(where(is.numeric), ~ .x < 0))

# A tibble: 2 x 3
  x         y     z
  <chr> <dbl> <dbl>
1 b         1     1
2 c        -1    -1

让我们看看更大的例子

set.seed(201)
df <- data.frame(A = LETTERS[1:10], x = rnorm(10), y = rnorm(10), z = -1*rnorm(10))

> df
   A           x           y           z
1  A  0.28606069  0.69329617  0.24400084
2  B -0.34454603  0.22380936  0.98825314
3  C  0.32576373  0.39845694 -1.24206048
4  D -1.69658097  1.01347438  1.68266603
5  E -1.28548252 -0.64785307 -1.44289063
6  F -0.07503189  0.64845271  0.46543975
7  G  0.26693735  0.20734270 -0.69366150
8  H  0.05593404  0.06439014  0.08772557
9  I -2.30403431  0.66938092  0.95508038
10 J  0.18900414 -0.37425445 -0.17010088

> df %>% filter(if_all(where(is.numeric), ~ .x > 0) | !if_any(where(is.numeric), ~ .x < 0))
  A           x           y           z
1 A  0.28606069  0.69329617  0.24400084
2 E -1.28548252 -0.64785307 -1.44289063
3 H  0.05593404  0.06439014  0.08772557

【讨论】:

  • 我的朋友很好的解决方案。我试图想办法用一个across 函数来做到这一点。到目前为止我失败了。
  • :) 我被这个问题卷入了好几个小时。
  • 我不知道为什么它没有产生所需的输出!
  • 因为我们同时检查相互矛盾的条件。就像我们必须从c(T, T)c(T, F)c(F, F) 中过滤相同的值。让我在答案中添加一个解释。
  • 是的,你完全正确。谢谢你让我知道。期待我们未来对其他方法和问题的讨论。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-19
  • 1970-01-01
  • 1970-01-01
  • 2017-11-18
相关资源
最近更新 更多