R:如何在数据帧内偏移和匹配?

R: How to offset and match within a dataframe?

我想使用类似于 Excel 的 OFFSET 和 MATCH 函数的东西,这里是一个示例数据集: 数据=

Which Test?|Test1   |Test2  |Test3  |RESULT
Test1      |TRUE    |80%    |0      |
Test2      |FALSE   |25%    |0      |
Test1      |TRUE    |16%    |0      |
Test3      |FALSE   |12%    |1      |

结果列应为:

Which Test?|Test1   |Test2  |Test3  |RESULT
Test1      |TRUE    |80%    |0      |TRUE
Test2      |FALSE   |25%    |0      |25%
Test1      |TRUE    |16%    |0      |TRUE
Test3      |FALSE   |12%    |1      |1

在最后的RESULT栏我想要搜索Which test?的测试结果。柱子。在此示例中,RESULT 列可以 return,例如,数字或字符串。在 Excel 公式中将是:

=OFFSET($A, ROW()-1,MATCH(A2,$B:$D,0))

到目前为止,我已经尝试使用 sapply 列出测试,并且 return 将其添加到另一个函数,例如 which(colnames... 这就是我卡住的地方。

尝试

library(tidyr)
out = subset(gather(data, key, RESULT, 2:4), Which_Test == key)
req = unique(merge(data, out[,-2], by = "Which_Test"))

#>req
#  Which_Test Test1 Test2 Test3 RESULT
#1      Test1  TRUE   80%     0   TRUE
#3      Test1  TRUE   16%     0   TRUE
#5      Test2 FALSE   25%     0    25%
#6      Test3 FALSE   12%     1      1

此处使用 Which_test 作为常量,Test 列被收集到一个名为 RESULT 的列中(使用 gather 来自 tidyr package) 同时 Test 列的名称列在 key 下,然后使用基 R 的 [= 根据与 Which_test 的匹配过滤数据20=]

数据

data = structure(list(Which_Test = structure(c(1L, 2L, 1L, 3L), 
      .Label = c("Test1","Test2", "Test3"), class = "factor"), 
       Test1 = c(TRUE, FALSE, TRUE, FALSE), 
       Test2 = structure(c(4L, 3L, 2L, 1L), 
      .Label = c("12%", "16%", "25%", "80%"), class = "factor"), 
       Test3 = c(0L, 0L, 0L, 1L)), 
      .Names = c("Which_Test", "Test1", "Test2", "Test3"), 
       class = "data.frame", row.names = c(NA, -4L))

我会和sapply一起去:

data <- read.table(text="Which Test?|Test1   |Test2  |Test3  |RESULT
Test1      |TRUE    |80%    |0      |
Test2      |FALSE   |25%    |0      |
Test1      |TRUE    |16%    |0      |
Test3      |FALSE   |12%    |1      |", 
 header=T, 
 sep="|",
 stringsAsFactors=F,
 strip.white=T)

data$RESULT <- sapply( 1:nrow(data), function(x) { data[x,data[x,1]] })

对于每一行,获取目标列 data[x,1](内部访问),对于该列,获取行值 data[x,...]

输出:

> data
  Which.Test. Test1 Test2 Test3 RESULT Result
1       Test1  TRUE   80%     0     NA   TRUE
2       Test2 FALSE   25%     0     NA    25%
3       Test1  TRUE   16%     0     NA   TRUE
4       Test3 FALSE   12%     1     NA      1

如果有两个变量,sapply 中的函数将是:

function(x) {
 tcol <- data[x,1] # First column value of row x
 data[x,tcol]) # Get the value at row x and column tcol
}

使用 Map/mapply 的方法是提供 'i' (seq(nrow(data)))、'j' (match(data$Which.Test., names(data))) row/column 索引和使用 [ 从 'data' 中提取元素。我们用 list 换行,这样 'data' 保持为单个 data.frame 并将循环通过 'i'、'j'.

的长度
 mapply(`[`, list(data), seq(nrow(data)), match(data$Which.Test., names(data) ) )
 #[1] "TRUE" "25%"  "TRUE" "1"   

不过,一种可能的矢量化方法就是

data[cbind(1:nrow(data), match(data$Which.Test., names(data)))]
## [1] " TRUE" "25%"   " TRUE" "1"  

这是将 Which.Test. 中的值与 data 的列名进行匹配,并返回匹配列的索引。然后,我们通过使用 cbind.

将其与 1:nrow(data) 组合来对每一行的这些列进行子集化

上面@DavidArenburg 解决方案的更详细解释(因为我不得不花一些时间来完全理解它):

子集运算符接受一个矩阵,所以我们这样做:

  1. 1:nrow(data) 很简单,它给出了一个向量 [1] 1 2 3 4 对应于我们数据集中的行数
  2. match(data$Which.Test., names(data)))给出每个匹配测试的索引[1] 1 2 3 4
  3. cbind(..,..)绑定我们前面的两个点来构建一个矩阵:

         [,1] [,2]
    [1,]    1    2
    [2,]    2    3
    [3,]    3    2
    [4,]    4    4
    

    我们看到这个矩阵与我们希望取值的每一行匹配。因此,当将此矩阵作为我们数据集的选择器时,我们会得到正确的结果。然后我们可以将它分配给一个新变量或 df 的一个新列。