根据另一个数据框的特定数字间隔对一个数据框进行子集化

Subset one data frame based on specific numeric intervals from another

我想要基于 df2.

中特定数值区间之外的值的子集 df1

我的输入 df1df2:

df1 <- 'name sam1 sam2 sam3  
        AZ1  2.65  2.56  2.65
        AX1  2.22  2.41  2.85
        AX2  2.45  2.45  2.85'
df1 <- read.table(text=df1, header=T)

df2 <- 'name sam1 sam2 sam3  
        AZ1  1  0  1
        AX1  0.75  0.55  1
        AX2  0  0  0.62'
df2 <- read.table(text=df2, header=T)

我尝试了以下代码对其进行子集化但没有成功:

out <- df1[if(df2 >= 0.90) |if(df2 <= 0.10) | if(df2 <= 0.60 && df2 >= 0.40)]

我试图仅对 df1 值高于 0.90 低于 0.1 介于 0.4 之间的单元格进行子集化到 0.6(反过来:NA 到 x 间隔:0.40 > x > 0.10 和 0.9 > x > 0.6)。预期输出为:

out <- 'name sam1 sam2 sam3  
            AZ1  2.65  2.56  2.65
            AX1  NA  2.41  2.85
            AX2  2.45  2.45  NA'
out <- read.table(text=out, header=T)

如果您对这里的语法有任何帮助,我将不胜感激。

手动引入 NA 通常更容易。如果为真,则不需要 if 如果没有要评估的代码;不等式已经评估为布尔值。真的,你只需要

 df1[((df2 < 0.9) & (df2 > 0.6)) | ((df2 < 0.4) & (df2 > 0.1))] <- NA

它改变了 df1 所以它看起来像

> df1
  name sam1 sam2 sam3
1  AZ1 2.65 2.56 2.65
2  AX1   NA 2.41 2.85
3  AX2 2.45 2.45   NA

对于像这样的长布尔测试,请注意括号,尤其是当您有多个范围时。


编辑

如果完全按照上面的方式在 df2 上调用,此代码将引发警告

Warning messages:
1: In Ops.factor(left, right) : ‘<’ not meaningful for factors
2: In Ops.factor(left, right) : ‘>’ not meaningful for factors
3: In Ops.factor(left, right) : ‘<’ not meaningful for factors
4: In Ops.factor(left, right) : ‘>’ not meaningful for factors

因为df2$name是一个因素。由于因子将它们的值存储为数字(映射到级别),因此 R 警告它不会对这些值执行不等式操作,无论如何我们都不希望它这样做。由于它对 name 列没有任何作用,因此无论警告如何,结果都是我们想要的。

可以通过将 name 更改为字符来完全避免警告,或者首先不将其转换为因素。在读取数据时在 read.table 中指定选项 stringsAsFactors = FALSE,或者在上面的行前面加上

 df2$name <- as.character(df2$name)

由于很明显 R 不会将字符串和数字进行不等式比较,因此它不会再发出警告。

您可以创建一个函数 returns 一个逻辑矩阵,该矩阵使用 findInterval 从 df2 的值和条件间隔映射,然后使用 is.na<-[= 将 NA 标记到目标数据帧上14=]

 nafunc <- function(z) {sapply(z, function(x) 
      findInterval( as.numeric(x), c(-Inf, 0.10, 0.40, 0.6, 0.9, Inf)) %in% c(2, 4) )}

is.na( df1)  <- nafunc(df2)
df1
#------    
  name sam1 sam2 sam3
1  AZ1 2.65 2.56 2.65
2  AX1   NA 2.41 2.85
3  AX2 2.45 2.45   NA

您也可以使用该函数从 df1 中提取值:

> df1[ !nafunc(df2) ]
 [1] "AZ1"  "AX1"  "AX2"  "2.65" "2.45" "2.56" "2.41" "2.45" "2.65" "2.85"

不漂亮,因为提取过程强制转换为矩阵,将所有内容强制转换为字符。所以将尝试稍微不同的操作顺序:

> df1[, 2:4 ][!nafunc(df2)[, 2:4]]
[1] 2.65 2.45 2.56 2.41 2.45 2.65 2.85   # Delivers the first requested result.

使用 magrittr

library(magrittr)

idx <- as.matrix(df2[, -1]) %>% 
       {(.<0.9 & .>0.6) | (.<0.4 & .>0.1)}

df1[, -1][idx] <- NA

df1

   name sam1 sam2 sam3
1  AZ1 2.65 2.56 2.65
2  AX1   NA 2.41 2.85
3  AX2 2.45 2.45   NA

或更短但相同的答案

df1[, -1][df2 %>% .[, -1] %>% as.matrix %>% 
         {(.<0.9 & .>0.6) | (.<0.4 & .>0.1)}] <- NA