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:nrow(data)
很简单,它给出了一个向量 [1] 1 2 3 4
对应于我们数据集中的行数
match(data$Which.Test., names(data)))
给出每个匹配测试的索引[1] 1 2 3 4
cbind(..,..)
绑定我们前面的两个点来构建一个矩阵:
[,1] [,2]
[1,] 1 2
[2,] 2 3
[3,] 3 2
[4,] 4 4
我们看到这个矩阵与我们希望取值的每一行匹配。因此,当将此矩阵作为我们数据集的选择器时,我们会得到正确的结果。然后我们可以将它分配给一个新变量或 df 的一个新列。
我想使用类似于 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:nrow(data)
很简单,它给出了一个向量[1] 1 2 3 4
对应于我们数据集中的行数match(data$Which.Test., names(data)))
给出每个匹配测试的索引[1] 1 2 3 4
cbind(..,..)
绑定我们前面的两个点来构建一个矩阵:[,1] [,2] [1,] 1 2 [2,] 2 3 [3,] 3 2 [4,] 4 4
我们看到这个矩阵与我们希望取值的每一行匹配。因此,当将此矩阵作为我们数据集的选择器时,我们会得到正确的结果。然后我们可以将它分配给一个新变量或 df 的一个新列。