如何在R中添加不等长度的命名向量

3

这应该很简单,但我似乎无法使它工作。我有两个命名的向量长度不相等:

x <- as.vector(c(5, 10,15,20))
names(x) <- c("A", "B", "C", "D")
y <- as.vector(c(7, 12))
names(y) <- c("A", "D")

我想将它们加在一起并保留最长名称的命名约定。我希望 x + y 的结果为:
A   B   C   D
12  10  15  32

我尝试过将长度调整为相等,如其他地方建议的那样,这样可以进行算术运算,但无法保留命名约定。我还尝试了一些方法,例如:

z <- x[names(y)] + y

但这只是得到了算术结果,却没有保留结构。

3个回答

6
你可以使用 tapply()
z <- c(x, y)
tapply(z, names(z), sum)
#  A  B  C  D 
# 12 10 15 32 

1
太好了,Richard。我以前从未使用过tapply。非常棒。谢谢! - Ernie

2
你可以使用replace来完成此操作,匹配两个向量的名称:
x + replace(rep(0, length(x)), names(x) %in% names(y), y)
#  A  B  C  D 
# 12 10 15 32 

假设xy的名称顺序相同。

或者,您可以尝试以下方法,它不需要相同的顺序:

z <- x
m <- match(names(y), names(x))
z[m] <- z[m] + y
z
#  A  B  C  D 
# 12 10 15 32 

虽然这两种方法都不如 @RichardScriven 建议使用 tapply 来得简洁,但它们在处理大向量时更有效率:

set.seed(144)
big.x <- runif(1000000)
names(big.x) <- paste("x", 1:1000000)
big.y <- big.x[sort(sample(1:1000000, 500000))]
sum.rscriven <- function(x, y) {
  z <- c(x, y)
  tapply(z, names(z), sum)
}
sum.josilber1 <- function(x, y) x + replace(rep(0, length(x)), names(x) %in% names(y), y)
sum.josilber2 <- function(x, y) {
  z <- x
  m <- match(names(y), names(x))
  z[m] <- z[m] + y
  z
}
system.time(sum.rscriven(big.x, big.y))
#    user  system elapsed 
#  12.650   0.151  12.817 
system.time(sum.josilber1(big.x, big.y))
#    user  system elapsed 
#   0.214   0.002   0.215 
system.time(sum.josilber2(big.x, big.y))
#    user  system elapsed 
#   0.180   0.003   0.182 

请注意,这两种提出的解决方案至少比本例中的 tapply 解决方案快 50 倍(big.x 长度为 100 万,big.y 长度为 50 万),因为它们执行单个向量化加法而不是许多较小的 sum 调用。

我真的很喜欢使用 match() 的那个。思维很好。 - Rich Scriven
非常好!由于我不仅需要总和还需要差异,所以我将使用匹配解决方案。谢谢。Ernie - Ernie

1

使用length<-colSums的一个示例

colSums(rbind(x, `length<-`(y, length(x))[names(x)]), na.rm=T)
#  A  B  C  D 
# 12 10 15 32 

另一种使用mergecolSums的方法

colSums(merge(as.list(x), as.list(y), all=T), na.rm=T)
#  A  D  B  C 
# 12 32 10 15 

这似乎无法保持从 x 中的排序。 - josliber

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接