【问题标题】:R: How to offset and match within a dataframe?R:如何在数据框中进行偏移和匹配?
【发布时间】:2015-08-27 14:29:45
【问题描述】:

我想使用类似于 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 列中,我想要搜索哪个测试的测试结果?柱子。在此示例中,RESULT 列可以返回例如数字或字符串。在 Excel 公式中为:

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

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

【问题讨论】:

  • 你自己尝试过什么?
  • 可能是library(data.table); setDT(data)[, Result := if(any(.SD == "TRUE")) "TRUE" else NA, .SDcols = c("Test1","Test2","Test3")] 需要更多解释。
  • 感谢 Veerendra,但据我了解,您的代码在测试列中搜索 TRUE,如果发现则返回 TRUE,否则不适用。我想要返回的结果实际上可能是一个数字(或字符串等)。我已经更新了上面的问题并添加了我正在尝试的搜索。
  • @Tensibai 这是我从 OP 的问题中推断出来的,但肯定需要另一个逻辑(这就是我使用“类似”这个短语的原因); OP 对所需逻辑的一些澄清会很好
  • @Jaap 查看我的答案,了解我理解的逻辑:p

标签: r dataframe match offset


【解决方案1】:

我会选择 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)))行/列索引并使用[ 从“数据”中提取元素。我们使用list 进行包装,以便“数据”保留为单个 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(..,..)bind 我们前面的两个点来构建一个矩阵:

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

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

【讨论】:

  • 完美,感谢您的回答并帮助您了解如何读取数据(抱歉第一次发帖)!
【解决方案2】:

试试

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 的列中(使用tidyr 包中的gather 同时@987654327 的名称@ 列在key 下列出,然后用于根据与Which_test 的匹配使用base R 的subset 过滤数据

数据

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))

【讨论】:

  • 是的,这行得通!如果需要,我总是可以将输出与数据合并,但这非常有用。感谢您的回答并帮助了解如何读取数据!
猜你喜欢
  • 2021-12-17
  • 1970-01-01
  • 1970-01-01
  • 2015-07-12
  • 1970-01-01
  • 2019-02-15
  • 2014-12-20
  • 2020-01-01
  • 1970-01-01
相关资源
最近更新 更多