我正在尝试使用 bcv 包中的 SVD 插补,但所有插补值都相同(按列)。
这是缺少数据的数据集http://pastebin.com/YS9qaUPs
#load data
dataMiss = read.csv('dataMiss.csv')
#impute data
SVDimputation = round(impute.svd(dataMiss)$x, 2)
#find index of missing values
bool = apply(X = dataMiss, 2, is.na)
#put in a new data frame only the imputed value
SVDImpNA = mapply(function(x,y) x[y], as.data.frame(SVDimputation), as.data.frame(bool))
View(SVDImpNA)
head(SVDImpNA)
V1 V2 V3
[1,] -0.01 0.01 0.01
[2,] -0.01 0.01 0.01
[3,] -0.01 0.01 0.01
[4,] -0.01 0.01 0.01
[5,] -0.01 0.01 0.01
[6,] -0.01 0.01 0.01
我错在哪里?
impute.svd
算法的工作原理如下:
-
将所有缺失值替换为相应的列均值。
-
计算插补矩阵的秩
k
近似值。 -
将插补位置中的值替换为步骤 2 中计算的秩
k
近似值中的相应值。 -
重复步骤 2 和 3,直到收敛。
在示例代码中,您正在设置k=min(n,p)
(默认值)。 然后,在步骤 2 中,秩k
近似正好等于插补矩阵。算法在 0 次迭代后收敛。也就是说,该算法将所有插补条目设置为列均值(如果存在数值误差,则非常接近此值)。
如果要执行除使用列均值插补缺失值之外的操作,则需要对k
使用较小的值。以下代码使用示例数据对此进行了演示:
> library("bcv")
> dataMiss = read.csv('dataMiss.csv')
k=3
> SVDimputation = impute.svd(dataMiss, k = 3, maxiter=10000)$x
> table(round(SVDimputation[is.na(dataMiss)], 2))
-0.01 0.01
531 1062
k=2
> SVDimputation = impute.svd(dataMiss, k = 2, maxiter=10000)$x
> table(round(SVDimputation[is.na(dataMiss)], 2))
-11.31 -6.94 -2.59 -2.52 -2.19 -2.02 -1.67 -1.63
25 23 61 2 54 23 5 44
-1.61 -1.2 -0.83 -0.8 -0.78 -0.43 -0.31 -0.15
14 10 13 19 39 1 14 19
-0.14 -0.02 0 0.01 0.02 0.03 0.06 0.17
83 96 94 77 30 96 82 28
0.46 0.53 0.55 0.56 0.83 0.91 1.26 1.53
1 209 83 23 28 111 16 8
1.77 5.63 9.99 14.34
112 12 33 5
请注意,对于您的数据,默认的最大迭代次数 (100) 太低(我收到一条警告消息)。为了解决这个问题,我设置了maxiter=10000
.
您描述的问题可能发生,因为 impute.svd 最初将所有 NA 值设置为等于列均值,然后在收敛时不会更改这些值。
这取决于您首先使用 SVD 插补的原因,但如果您很灵活,解决此问题的好方法可能是通过将 k 设置为 1 来切换 SVD 调用的等级。目前,k 自动设置为 min(n, p),其中 n = nrow,p = ncol,对于您的数据,这意味着 k = 3。例如,如果将其设置为 1(如 impute.svd 函数文档中的示例中设置的那样),则不会出现此问题:
library(bcv)
dataMiss = read.csv("dataMiss.csv")
SVDimputation = round(impute.svd(dataMiss, k = 1)$x, 2)
head(SVDimputation)
[,1] [,2] [,3]
[1,] 0.96 -0.23 0.52
[2,] 0.02 -0.23 -1.92
[3,] -1.87 -0.23 0.52
[4,] -0.92 -0.23 0.52
[5,] 0.49 -0.46 0.52
[6,] -1.87 -0.23 0.52