使用 mapply 在数据帧中进行间接寻址
Using mapply for indirect addressing in a data frame
有以下两个数据框
> d1
keystr keynum
1 abc 5
2 def 2
3 def 7
4 abc 3
> d2
HD 2 3 5 7
1 abc H I J K
2 def L M N P
我想插入一个 d1$val 列,它使用 keystr
中的字符串和 keynum
中的数字作为 d2
数据框中的索引。结果应该是:
> d1
keystr keynum val
1 abc 5 J
2 def 2 L
3 def 7 P
4 abc 3 I
这应该是mapply的间接应用。我怎样才能制作下面的代码
d1 <- data.frame("keystr"=c("abc","def","def","abc"), "keynum"=c(5,2,7,3))
d2 <- data.frame("HD"=c("abc","def"),
"2"=c("H","L"), "3"=c("I","M"),
"5"=c("J","N"), "7"=c("K","P"))
d1$val <- mapply(function(kstr,knum) d2[kstr,knum],
d1$keystr, d1$keynum )
以这种(间接)方式访问条目?
添加了 check.names = False 以启用 data.frame 以数字开头的列名称。使用两列的 cbind()
矩阵索引,i, j
对将被一次提取。
d1 <- data.frame("keystr"=c("abc","def","def","abc"), "keynum"=c(5,2,7,3))
d2 <- data.frame("HD"=c("abc","def"),
"2"=c("H","L"), "3"=c("I","M"),
"5"=c("J","N"), "7"=c("K","P"), check.names=FALSE)
d1$val <- mapply(function(kstr,knum) d2[cbind(match(kstr, d1$keystr),
match(knum, names(d2)))],
d1$keystr,
d1$keynum)
keystr keynum val
1 abc 5 J
2 def 2 L
3 def 7 P
4 abc 3 I
如果您没有使用 mapply
的限制,您可以加入:
代码:
library(tidyverse)
d1 <- data.frame("keystr"=c("abc","def","def","abc"), "keynum"=c(5,2,7,3))
d2 <- data.frame("HD"=c("abc","def"),
"2"=c("H","L"), "3"=c("I","M"),
"5"=c("J","N"), "7"=c("K","P"))
d2 %>%
gather(keynum, value, -HD) %>%
mutate(keynum = as.numeric(gsub(keynum, pattern = "X", replacement = ""))) %>%
left_join(y = ., x = d1, by = c("keystr" = "HD", "keynum"))
输出:
keystr keynum value
1 abc 5 J
2 def 2 L
3 def 7 P
4 abc 3 I
我们可以转换数据框,然后通过tidyr and dplyr进行合并。
library(dplyr)
library(tidyr)
d3 <- d2 %>%
gather(keynum, letter, -HD) %>%
mutate(keynum = as.numeric(sub("X", "", keynum)))
d4 <- d1 %>%
left_join(d3, by = c("keystr" = "HD", "keynum"))
d4
# keystr keynum letter
# 1 abc 5 J
# 2 def 2 L
# 3 def 7 P
# 4 abc 3 I
数据
请注意,我在创建数据框时设置了 stringsAsFactors = FALSE
。
d1 <- data.frame("keystr"=c("abc","def","def","abc"), "keynum"=c(5,2,7,3),
stringsAsFactors = FALSE)
d2 <- data.frame("HD"=c("abc","def"),
"2"=c("H","L"), "3"=c("I","M"),
"5"=c("J","N"), "7"=c("K","P"),
stringsAsFactors = FALSE)
如果转换为矩阵并 cbind 列字符值,则可以使用 d1 列为 d2[-1] 中的字符值编制索引。它创建一个 two-D 查找 table,您可以同时将行和列的索引传递给该查找。然后,您还可以针对它传递一个 two-D 矩阵以生成输出向量。 (也可以对 R 数组使用 3 或 4 或 higher-D 索引,on=e 将向其传递 3,4 或更高数字的列矩阵):
( m2 <- sapply(d2[ , -1], as.character) )
#------
2 3 5 7
[1,] "H" "I" "J" "K"
[2,] "L" "M" "N" "P"
rownames(m2) <- as.character(d2[[1]])
m2
#--------
2 3 5 7
abc "H" "I" "J" "K"
def "L" "M" "N" "P"
(d1$val <- m2[ cbind(as.character(d1[[1]]),as.character(d1[[2]])) ])
[1] "J" "L" "P" "I"
d1
#--------
keystr keynum val
1 abc 5 J
2 def 2 L
3 def 7 P
4 abc 3 I
请注意需要重复使用 as.character
,因为这些是因子列。更好的构造是用 stringsAsFactors=FALSE
构建你的 data.frames。构建矩阵会很快,索引可能会非常有效。
您可以使用基础 R:
重塑并加入 data.frames
d1 <- read.table(text = 'keystr keynum
1 abc 5
2 def 2
3 def 7
4 abc 3', stringsAsFactors = FALSE)
d2 <- read.table(text = 'HD 2 3 5 7
1 abc H I J K
2 def L M N P', stringsAsFactors = FALSE, check.names = FALSE)
d2 <- reshape(d2, idvar = "HD", varying = names(d2)[-1], v.names = "val",
times = names(d2)[-1], direction = "long")
merge(d1, d2, by.x = c("keystr", "keynum"), by.y = c("HD", "time"))
#> keystr keynum val
#> 1 abc 3 I
#> 2 abc 5 J
#> 3 def 2 L
#> 4 def 7 P
我觉得OP
想对了,mapply
可以给他提供一个直接的解决方案。他的 mapply
方法非常接近可行的解决方案。必须更正用于比较行选择的逻辑,然后 paste0
用于从 d2
中选择列。
d1$val <- mapply(function(x,y)d2[d2$HD==x,paste0("X",y)],d1$keystr, d1$keynum)
d1
# keystr keynum val
# 1 abc 5 J
# 2 def 2 L
# 3 def 7 P
# 4 abc 3 I
#
有以下两个数据框
> d1
keystr keynum
1 abc 5
2 def 2
3 def 7
4 abc 3
> d2
HD 2 3 5 7
1 abc H I J K
2 def L M N P
我想插入一个 d1$val 列,它使用 keystr
中的字符串和 keynum
中的数字作为 d2
数据框中的索引。结果应该是:
> d1
keystr keynum val
1 abc 5 J
2 def 2 L
3 def 7 P
4 abc 3 I
这应该是mapply的间接应用。我怎样才能制作下面的代码
d1 <- data.frame("keystr"=c("abc","def","def","abc"), "keynum"=c(5,2,7,3))
d2 <- data.frame("HD"=c("abc","def"),
"2"=c("H","L"), "3"=c("I","M"),
"5"=c("J","N"), "7"=c("K","P"))
d1$val <- mapply(function(kstr,knum) d2[kstr,knum],
d1$keystr, d1$keynum )
以这种(间接)方式访问条目?
添加了 check.names = False 以启用 data.frame 以数字开头的列名称。使用两列的 cbind()
矩阵索引,i, j
对将被一次提取。
d1 <- data.frame("keystr"=c("abc","def","def","abc"), "keynum"=c(5,2,7,3))
d2 <- data.frame("HD"=c("abc","def"),
"2"=c("H","L"), "3"=c("I","M"),
"5"=c("J","N"), "7"=c("K","P"), check.names=FALSE)
d1$val <- mapply(function(kstr,knum) d2[cbind(match(kstr, d1$keystr),
match(knum, names(d2)))],
d1$keystr,
d1$keynum)
keystr keynum val
1 abc 5 J
2 def 2 L
3 def 7 P
4 abc 3 I
如果您没有使用 mapply
的限制,您可以加入:
代码:
library(tidyverse)
d1 <- data.frame("keystr"=c("abc","def","def","abc"), "keynum"=c(5,2,7,3))
d2 <- data.frame("HD"=c("abc","def"),
"2"=c("H","L"), "3"=c("I","M"),
"5"=c("J","N"), "7"=c("K","P"))
d2 %>%
gather(keynum, value, -HD) %>%
mutate(keynum = as.numeric(gsub(keynum, pattern = "X", replacement = ""))) %>%
left_join(y = ., x = d1, by = c("keystr" = "HD", "keynum"))
输出:
keystr keynum value
1 abc 5 J
2 def 2 L
3 def 7 P
4 abc 3 I
我们可以转换数据框,然后通过tidyr and dplyr进行合并。
library(dplyr)
library(tidyr)
d3 <- d2 %>%
gather(keynum, letter, -HD) %>%
mutate(keynum = as.numeric(sub("X", "", keynum)))
d4 <- d1 %>%
left_join(d3, by = c("keystr" = "HD", "keynum"))
d4
# keystr keynum letter
# 1 abc 5 J
# 2 def 2 L
# 3 def 7 P
# 4 abc 3 I
数据
请注意,我在创建数据框时设置了 stringsAsFactors = FALSE
。
d1 <- data.frame("keystr"=c("abc","def","def","abc"), "keynum"=c(5,2,7,3),
stringsAsFactors = FALSE)
d2 <- data.frame("HD"=c("abc","def"),
"2"=c("H","L"), "3"=c("I","M"),
"5"=c("J","N"), "7"=c("K","P"),
stringsAsFactors = FALSE)
如果转换为矩阵并 cbind 列字符值,则可以使用 d1 列为 d2[-1] 中的字符值编制索引。它创建一个 two-D 查找 table,您可以同时将行和列的索引传递给该查找。然后,您还可以针对它传递一个 two-D 矩阵以生成输出向量。 (也可以对 R 数组使用 3 或 4 或 higher-D 索引,on=e 将向其传递 3,4 或更高数字的列矩阵):
( m2 <- sapply(d2[ , -1], as.character) )
#------
2 3 5 7
[1,] "H" "I" "J" "K"
[2,] "L" "M" "N" "P"
rownames(m2) <- as.character(d2[[1]])
m2
#--------
2 3 5 7
abc "H" "I" "J" "K"
def "L" "M" "N" "P"
(d1$val <- m2[ cbind(as.character(d1[[1]]),as.character(d1[[2]])) ])
[1] "J" "L" "P" "I"
d1
#--------
keystr keynum val
1 abc 5 J
2 def 2 L
3 def 7 P
4 abc 3 I
请注意需要重复使用 as.character
,因为这些是因子列。更好的构造是用 stringsAsFactors=FALSE
构建你的 data.frames。构建矩阵会很快,索引可能会非常有效。
您可以使用基础 R:
重塑并加入 data.framesd1 <- read.table(text = 'keystr keynum
1 abc 5
2 def 2
3 def 7
4 abc 3', stringsAsFactors = FALSE)
d2 <- read.table(text = 'HD 2 3 5 7
1 abc H I J K
2 def L M N P', stringsAsFactors = FALSE, check.names = FALSE)
d2 <- reshape(d2, idvar = "HD", varying = names(d2)[-1], v.names = "val",
times = names(d2)[-1], direction = "long")
merge(d1, d2, by.x = c("keystr", "keynum"), by.y = c("HD", "time"))
#> keystr keynum val
#> 1 abc 3 I
#> 2 abc 5 J
#> 3 def 2 L
#> 4 def 7 P
我觉得OP
想对了,mapply
可以给他提供一个直接的解决方案。他的 mapply
方法非常接近可行的解决方案。必须更正用于比较行选择的逻辑,然后 paste0
用于从 d2
中选择列。
d1$val <- mapply(function(x,y)d2[d2$HD==x,paste0("X",y)],d1$keystr, d1$keynum)
d1
# keystr keynum val
# 1 abc 5 J
# 2 def 2 L
# 3 def 7 P
# 4 abc 3 I
#