非常感谢您的帮助!
我正在尝试修改现有矩阵,以便在将新行添加到矩阵时,它会从预先存在的矩阵中删除值。
例如,我有矩阵:
[,1] [,2] [,3] [,4]
1 1 0 0
0 1 0 0
1 0 1 0
0 0 1 1
我想添加另一个矢量I.vec,它有两个值(I.vec=c(0,1,1,0)
)。
这很容易做到。我只是将它与矩阵联系起来。
现在,对于I.vec等于1的每一列,我想从其他行中随机选择一个值并使其为零。
理想情况下,最终会得到一个矩阵,如:
[,1] [,2] [,3] [,4]
1 0 0 0
0 1 0 0
1 0 0 0
0 0 1 1
0 1 1 0
但每次运行迭代时,我都希望它再次随机采样。
所以这就是我的尝试:
mat1<-matrix(c(1,1,0,0,0,1,0,0,1,0,1,0,0,0,1,1),byrow=T, nrow=4)
I.vec<-c(0,1,1,0)
mat.I<-rbind(mat1,I.vec)
mat.I.r<-mat.I
d1<-mat.I[,which(mat.I[5,]==1)]
mat.I.r[sample(which(d1[1:4]==1),1),which(mat.I[5,]==1)]<-0
但是这只删除了我想要删除的两个值中的一个。我也尝试过对矩阵进行子集化的变化,但我还没有成功。
再次感谢你!
答案 0 :(得分:4)
OP的描述中有一点含糊不清,因此建议使用两种解决方案:
1
可以设置为0
我将改变原来的功能(见下文)。更改是定义rows
的行。我现在有(原版中有一个错误 - 下面的版本经过修改以处理错误处理):
rows <- sapply(seq_along(cols),
function(x, mat, cols) {
ones <- which(mat[,cols[x]] == 1L)
out <- if(length(ones) == 1L) {
ones
} else {
sample(ones, 1)
}
out
}, mat = mat, cols = cols)
基本上,这样做,对于我们需要将1
交换为0
的每个列,我们计算出列的哪些行包含1
并对其中的一个进行采样这些
修改:我们必须处理列中只有一个1
的情况。如果我们只是从长度为1的向量进行采样,则R sample()
会将其视为我们想要从集合seq_len(n)
中取样而不是从长度为1的集合n
进行抽样。我们现在使用if, else
语句处理此问题。
我们必须为每列单独执行此操作,以便获得正确的行。我想我们可以做一些很好的操作来避免重复调用which()
和sample()
,但是此刻如何逃避我,因为我们必须处理只有一个{{1}的情况在列中。这是完成的函数(更新以处理原始中的长度1样本错误):
1
在这里它正在发挥作用:
foo <- function(mat, vec) {
nr <- nrow(mat)
nc <- ncol(mat)
cols <- which(vec == 1L)
rows <- sapply(seq_along(cols),
function(x, mat, cols) {
ones <- which(mat[,cols[x]] == 1L)
out <- if(length(ones) == 1L) {
ones
} else {
sample(ones, 1)
}
out
}, mat = mat, cols = cols)
ind <- (nr*(cols-1)) + rows
mat[ind] <- 0
mat <- rbind(mat, vec)
rownames(mat) <- NULL
mat
}
当我们想要进行交换的列中只有一个> set.seed(2)
> foo(mat1, ivec)
[,1] [,2] [,3] [,4]
[1,] 1 0 0 0
[2,] 0 1 0 0
[3,] 1 0 1 0
[4,] 0 0 0 1
[5,] 0 1 1 0
时,它会起作用:
1
这是一个矢量化答案,我们在进行替换时将矩阵视为向量。使用示例数据:
> foo(mat1, c(0,0,1,1))
[,1] [,2] [,3] [,4]
[1,] 1 1 0 0
[2,] 0 1 0 0
[3,] 1 0 1 0
[4,] 0 0 0 1
[5,] 0 0 1 1
这给了我们:
mat1 <- matrix(c(1,1,0,0,0,1,0,0,1,0,1,0,0,0,1,1), byrow = TRUE, nrow = 4)
ivec <- c(0,1,1,0)
## Set a seed to make reproducible
set.seed(2)
## number of rows and columns of our matrix
nr <- nrow(mat1)
nc <- ncol(mat1)
## which of ivec are 1L
cols <- which(ivec == 1L)
## sample length(cols) row indices, with replacement
## so same row can be drawn more than once
rows <- sample(seq_len(nr), length(cols), replace = TRUE)
## Compute the index of each rows cols combination
## if we treated mat1 as a vector
ind <- (nr*(cols-1)) + rows
## ind should be of length length(cols)
## copy for illustration
mat2 <- mat1
## replace the indices we want with 0, note sub-setting as a vector
mat2[ind] <- 0
## bind on ivec
mat2 <- rbind(mat2, ivec)
如果我这样做超过一次或两次,我会把它包装在一个函数中:
> mat2
[,1] [,2] [,3] [,4]
1 0 0 0
0 1 0 0
1 0 0 0
0 0 1 1
ivec 0 1 1 0
给出了:
foo <- function(mat, vec) {
nr <- nrow(mat)
nc <- ncol(mat)
cols <- which(vec == 1L)
rows <- sample(seq_len(nr), length(cols), replace = TRUE)
ind <- (nr*(cols-1)) + rows
mat[ind] <- 0
mat <- rbind(mat, vec)
rownames(mat) <- NULL
mat
}
如果你想为多个> foo(mat1, ivec)
[,1] [,2] [,3] [,4]
[1,] 1 1 0 0
[2,] 0 1 0 0
[3,] 1 0 1 0
[4,] 0 0 0 1
[5,] 0 1 1 0
执行此操作,每次增长ivec
,那么你可能不希望在循环中这样做,因为增长的对象很慢(它涉及副本等) )。但您可以修改mat1
的定义,以包含您为ind
n
绑定的额外n
行。
答案 1 :(得分:1)
你可以尝试这样的事情。在那里'nrow'将允许你与其他'I.vec'一起运行它多次。我尝试用'apply'在一行中完成这项工作,但无法再获得矩阵。
mat1<-matrix(c(1,1,0,0,0,1,0,0,1,0,1,0,0,0,1,1),byrow=T, nrow=4)
I.vec<-c(0,1,1,0)
mat.I.r<-rbind(mat1,I.vec)
for(i in 1:ncol(mat.I.r))
{
ifelse(mat.I.r[nrow(mat.I.r),i]==1, mat.I.r[sample(which(mat.I.r[1:(nrow(mat.I.r)-1),i]==1),1), i] <- 0, "")
}
mat.I.r