【问题标题】:How do I create a loop with multiple if criteria across dataframe columns?如何跨数据框列创建具有多个 if 条件的循环?
【发布时间】:2018-03-15 06:08:07
【问题描述】:

我有一个包含多个列变量和大约 10 行复制的数据框,还有一个包含相同变量但 700 行的第二个数据框。我想创建一个循环,获取第二个数据帧中行的每个值,看看它是否在第一个数据帧的相应列的范围内。到目前为止,我已经尝试了一个相当不雅的长 for loop,其中有很多语法错误,以至于我不知道从哪里开始修复它。

这是我的数据框的缩短版本。数据框 1:c1a

WAV    UV     VIOLET    BLUE
2D1    10.8   10.1      23.5
3A4    6.2    8.2       19.9
4A1    8.3    11.7      28.6
5C2    7.9    8.2       31.0
5C3    10.7   9.5       18.1

数据框 2:paint2

ID    UV     VIOLET    BLUE
D1    7.9    10.1      19.3
D2    7.0    9.2      15.9
D3    21.4   20.7      27.4
D4    10.3   8.9      20.9
D5    21.7   16.5      21.3

所以我想要查看 D1 的每个值是否落入数据帧 1 的相应列的范围内,依此类推,然后得到所有列都成功的 ID 的输出。

我的代码:

c1a.out=NULL

for (i in nrow(paint2)){
  if (min(c1a[,2]) < [i,2] < max(c1a[,2])
  && min(c1a[,3]) < [i,3] < max(c1a[,3])
  && min(c1a[,4]) < [i,4] < max(c1a[,4])){
  c1a.out=c(c1a.out, [i,1])
  }
}     

输出将只是一个列表,其中 ID 名称的值落在第一个数据帧中整个 COLUMN 的范围内。

>c1a.out
>D1  D4

例如,D2 没有进入列表,因为它的 BLUE 值不在 c1a 中的 BLUE 值范围内,即使它的 UV 和 VIOLET 值在 c1a 中它们各自列的范围内。

我知道这很丑,但我对制作循环知之甚少。 如果对我收到的错误(意外的括号和逗号)进行了更正,或者可以创建更简单、更优雅的循环版本,我会全力以赴。

【问题讨论】:

  • c1a 中的每个 ID 是否应该有多个值?否则 minmax 毫无意义。包含所需输出的完全可重现的示例将非常有帮助。
  • 不,我希望 ID 行中的每个值都在 c1a 中同一变量的整个列中进行测试。所以我想看看 D1 的 UV 值是否在 c1a UV 列的范围内,并对每一列重复此操作。然后在每一行上循环。输出只是一个列表,其中列出了哪些行 (ID) 的所有值都在 c1a 的相应列的范围内。抱歉,我觉得这很难解释。我会在帖子中添加一些细节。

标签: r for-loop if-statement


【解决方案1】:

好的,这是一个tidyverse 解决方案,但可能比我想要的更复杂一些 - 显然并不比 for 循环更容易阅读。但是,它应该适用于要比较的任意数量的变量,假设所有表都具有一个 ID 列的相同结构,然后要比较的列数相同。我会逐步介绍方法。

  1. 我们要做的是将paint2 中的每个值与c1a 中的正确值进行比较,并返回TRUEFALSE。因此,我们使用map2 并行映射paint2 中的列,除了第一个(.x = .[, -1])和c1a 的右索引(.y = 2:ncol(.))。我们可以这样做,因为数据框只是列的列表!因此,整个map2 行创建了一个新列表,每个变量列都有一个元素,每个元素都包含正确的逻辑值。像这样:

paint2 中每个单元格一个值

$UV
[1]  TRUE  TRUE FALSE  TRUE FALSE

$VIOLET
[1]  TRUE  TRUE FALSE  TRUE FALSE

$BLUE
[1]  TRUE FALSE  TRUE  TRUE  TRUE
  1. 然后我们要比较每一行,如果每一行都是TRUE,则只返回TRUE。所以我们首先要transpose(),让每个元素都是一行而不是一列。

  2. 然后,我们要检查所有行以查看它们是否都是TRUE,因此我们使用all 映射行。 unlist 只是为了避免在列表而不是向量上使用 all 的警告。这给了我们:

paint2 中每行一个值

[1]  TRUE FALSE FALSE  TRUE FALSE
  1. 最后,我们只使用which 来获取TRUE 的索引,并打印出ID 的值。
library(tidyverse)
c1a <- read_table2(
  "WAV    UV     VIOLET    BLUE
  D1    10.8   10.1      23.5
  A4    6.2    8.2       19.9
  A1    8.3    11.7      28.6
  C2    7.9    8.2       31.0
  C3    10.7   9.5       18.1"
)

paint2 <- read_table2(
  "ID    UV     VIOLET    BLUE
  D1    7.9    10.1      19.3
  D2    7.0    9.2      15.9
  D3    21.4   20.7      27.4
  D4    10.3   8.9      20.9
  D5    21.7   16.5      21.3"
)

indices <- paint2 %>% map2(
  .x = .[, -1],
  .y = 2:ncol(.),
  .f = ~ between(.x, min(c1a[, .y]), max(c1a[, .y]))
) %>%
  transpose() %>%
  map_lgl(~ all(unlist(., use.names = FALSE))) %>%
  which()

paint2$ID[indices]
#> [1] "D1" "D4"

reprex package (v0.2.0) 于 2018 年 3 月 15 日创建。

为了进一步阅读,this is a great tutorial on purrr 并使用它来映射对象,尽可能避免 for 循环。

【讨论】:

  • 非常感谢,这对我的大型数据集很有用。
猜你喜欢
  • 2019-12-26
  • 2019-10-10
  • 2011-10-06
  • 2019-03-11
  • 1970-01-01
  • 2023-03-25
  • 2013-04-05
  • 2015-08-18
相关资源
最近更新 更多