如何将缺失值插入向量中

6

让我尽可能地概括这个问题。

假设我有两个变量ab

a <- as.integer(runif(20, min = 0, max = 10))
a <- as.data.frame(a)
b <- as.data.frame(a[c(-7, -11, -15),])

所以b有17个观察值,是a的子集,a有20个观察值。
我的问题是:如何使用这两个变量生成第三个变量c,它像a一样有20个观察值,但缺少7、11和15个观察值,并且其他观察值与b相同,但顺序与a相同?
或者换句话说:我该如何在位置7、11和15上将这些缺失的观察值插入到变量b中?
这似乎非常简单(可能确实如此),但我已经尝试了很长时间,却没有得到结果。

你是否实际拥有变量 ab,或者能够直接从 a 直接到达 c(你是否拥有创建变量 b 的指令)? - Joe
嗨,乔,是的,我有_a_和_b_。 - hjms
3个回答

5

1) 循环 试试这个循环:

# test data
set.seed(123) # for reproducibility
a <- as.integer(runif(20, min = 0, max = 10))
a <- as.data.frame(a)
b <- as.data.frame(a[c(-7, -11, -15),])

# lets work with vectors
A <- a[[1]]
B <- b[[1]]

j <- 1
C <- A
for(i in seq_along(A)) if (A[i] == B[j]) j <- j+1 else C[i] <- NA

该句意为:“提供:”
> C
 [1]  2  7  4  8  9  0 NA  8  5  4 NA  4  6  5 NA  8  2  0  3  9

2) 减少 这是一个无循环版本:

f <- function(j, a) j + (a == B[j])
r <- Reduce(f, A, acc = TRUE)
ifelse(duplicated(r), NA, A)

提供:

[1]  2  7  4  8  9  0 NA  8  5  4 NA  4  6  5 NA  8  2  0  3  9

3) dtw. 在同名包中使用dtw,我们可以得到一个紧凑的无环代码:

library(dtw)

ifelse(duplicated(dtw(A, B)$index2), NA, A)

提供:

[1]  2  7  4  8  9  0 NA  8  5  4 NA  4  6  5 NA  8  2  0  3  9

更新:添加了更多解决方案。


1
@Joe,已添加了一个无循环版本。 - G. Grothendieck
@G.Grothendieck 很好! - Joe
@eddi,我的第三个答案可以处理这些。请注意,你的回复中的复杂示例并没有唯一的答案,实际上,上面的第三个替代方案确实给出了一个不同但有效的答案。 - G. Grothendieck
@G.Grothendieck,你的第三个答案仍然对我给出的示例返回了次优结果(当然,OP可能不关心与最小编辑距离匹配,但如果我们要添加一个基准来确定什么是最优的 - 那就是显而易见的)。 - eddi
@eddi,这个问题中并没有最优性的概念。实际上,你的复杂模式有多个可行解决方案。 - G. Grothendieck
显示剩余3条评论

3

这里有一种更复杂的方法,使用Levenshtein距离算法,在更复杂的示例中表现更好(在我尝试的几个较大的测试中似乎也更快):

# using same data as G. Grothendieck:
set.seed(123) # for reproducibility
a <- as.integer(runif(20, min = 0, max = 10))
a <- as.data.frame(a)
b <- as.data.frame(a[c(-7, -11, -15),])
A = a[[1]]
B = b[[1]]

# compute the transformation between the two, assigning infinite weight to 
# insertion and substitution
# using +1 here because the integers fed to intToUtf8 have to be larger than 0
# could also adjust the range more dynamically based on A and B
transf = attr(adist(intToUtf8(A+1), intToUtf8(B+1),
                    costs = c(Inf,1,Inf), counts = TRUE), 'trafos')

C = A
C[substring(transf, 1:nchar(transf), 1:nchar(transf)) == "D"] <- NA
#[1]  2  7  4  8  9  0 NA  8  5  4 NA  4  6  5 NA  8  2  0  3  9

更复杂的匹配示例(贪婪算法表现不佳的情况):
A = c(1,1,2,2,1,1,1,2,2,2)
B = c(1,1,1,2,2,2)

transf = attr(adist(intToUtf8(A), intToUtf8(B),
                    costs = c(Inf,1,Inf), counts = TRUE), 'trafos')

C = A
C[substring(transf, 1:nchar(transf), 1:nchar(transf)) == "D"] <- NA
#[1] NA NA NA NA  1  1  1  2  2  2

# the greedy algorithm would return this instead:
#[1]  1  1 NA NA  1 NA NA  2  2  2

1
请注意,此解决方案依赖于“a”的组件每个都是一位数字的事实。 - G. Grothendieck
@G.Grothendieck 很好的观点 - 将其扩展到更大的整数的方法是使用 intToUtf8 而不是 paste0 - 我会在一秒钟内进行编辑。 - eddi

2
数据框版本与G.的版本相差不大(假设a、b已设置如上)。
j <- 1
c <- a
for (i in (seq_along(a[,1]))) {
    if (a[i,1]==b[j,1]) {
        j <- j+1
        } else 
        {
        c[i,1] <- NA
        }

}

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