是否有一种更优雅的方法可以根据二进制矩阵的填充和大小计算出二元矩阵的边际列总数中的最大或最小变异性级别(CV) ?考虑到所有行和列总数必须为非零。 e.g。
foo(n_col, n_row, fill){ get maximum possible CV }
我们假设我们有一个名为m
的矩阵,其中所有列和行总数都是> 0
,但矩阵填充最少。
m <- matrix(rep(0,25), nrow = 5)
diag(m) <- 1
# [,1] [,2] [,3] [,4] [,5]
#[1,] 1 0 0 0 0
#[2,] 0 1 0 0 0
#[3,] 0 0 1 0 0
#[4,] 0 0 0 1 0
#[5,] 0 0 0 0 1
variability1 <- sd(colSums(m))/mean(colSums(m))
variability1
# [1] 0
# the maximum and minimum for this fill is zero
# considering that all column and row totals must be > 0
也许我们可以在增加的填充水平上检查最大值,如:
# find out which matrix elements are zeros
empty <- which(m < 1)
# vector for results
variability <- rep(NA, length(empty))
#
for(i in 1:length(variability)){
m[empty[[i]] ] <- 1
variability[[i]] <- sd(colSums(m))/mean(colSums(m))
}
# we get what should the maximum CV for each given level of matrix fill...
c(variability1, variability)
我认为像这样按列填充矩阵可以保持边际列总数的最大可变性?有没有更简单的方法来处理不同大小,填充和形状的矩阵的最大和最小可变性?
答案 0 :(得分:3)
以下提供了问题的替代公式,作为对二元矩阵的列和的向量的选择的优化,其最大化给定fill
的可变性。提供了该公式的有效性和解决它的结果算法的非正式论证。得到的算法与OP的断言一致
像这样按列填充矩阵可以保持边际列总数的最大可变性
首先,将fill
定义为1
n_row
二进制矩阵n_col
中m
的数量。根据问题陈述的约束m
是一个二进制矩阵,所有行和列的总和大于零,fill
是[max(n_row, n_col),n_row*n_col]
范围内的整数。
问题是fill
范围内[max(n_row, n_col),n_row*n_col]
的给定值,找到最大值
sd(colSums(m))/mean(colSums(m))
覆盖所有m
,m
是fill
个1
个二进制矩阵,所有行和列的总和大于零。
我们注意到,最好根据m
而不是m
本身的列总和向量来指定此优化问题的域。这是因为存在具有相同列和的向量的不同m
,因此具有相同的目标值。将列和的向量表示为x
,上述优化问题可以重新表示为最大化:
sd(x)/mean(x)
这样x
的每个元素都是[1, n_row]
范围内的整数,sum(x)
是fill
。
此外,由于sum(x)
被限制为等于fill
,因此对于给定的mean(x)
,分母词x
在所有fill
上都是常数。因此,最大化的等效目标函数只是sd(x)
或等价x
的方差。
要最大化x
的方差,我们需要选择x
,使其值之间的差异最大化,同时仍满足x
的约束。在这里,我们可以针对fill
归纳地思考这个问题。让我们假设对于给定的fill
,我们有x
的解决方案,它在满足约束条件的同时最大化x
的方差。问题变为:当我们将fill
增加到fill + 1
时,最大化其方差的新x
是什么?因为我们有sum(x)=fill
的约束,x
中的每个元素都是整数,所以递增fill
意味着我们必须增加x
中的一个元素。暂时放宽x
中每个元素的上限约束(即x[i] <= n_row
中i
中的[1,n_col]
},然后问题变为:{{{{}}中的哪个元素1}}增加最大化x
方差的增加。对于这个问题的答案,我们可以看一下x
的泰勒级数展开:
var(x)
其中var(x + dx) = var(x) + gradient(var(x)) %*% dx + 1/2 * t(dx) %*% Hessian(var(x)) %*% dx
是长度为dx
的向量,其中一个元素等于n_col
,所有其他元素为1
(即指标向量)。由于0
在var(x)
中是二次方,因此二阶扩展就足够了。此外,由于x
是指标向量,因此只有Hessian矩阵的对角元素很重要。这些是由:
dx
由于Hessian的所有对角线项都相同,因此对于任何gradient(var(x))[i] = 2*(x[i]-mean(x))/(n_col-1), for all i in [1,n_col]
Hessian(var(x))[i,i] = 2/n_col , for all i in [1,n_col]
的选择,泰勒级数的二阶项都是相同的。因此,只有第一顺序项才能确定dx
中哪个元素增加,以最大化x
方差的增加。从渐变项中可以看出,我们应该选择增加x
中具有最大当前值i
的{{1}}个元素,以便最大化方差的增加x
。现在,我们重新引入x[i]
的每个元素的上限约束。然后,最佳选择是增加x
中具有最大当前值x
的{{1}}个元素。请注意,如果i
中有多个此类元素具有相同的最大值x
,则选择其中任何一个元素都会导致x[i] < n_row
方差的相同最大增加。
我们到目前为止所展示的是,给定x
并且x[i] < n_row
的解决方案在满足约束条件时最大化x
的方差,我们有一条规则{{1}最大化fill
的{{1}}方差的增量增量。仍然显示此规则会产生新的x
,这是x
最优化dx
的新x
的方差。我们现在通过矛盾来证明这一点。具体来说,如果新的fill + 1
没有最大化x
x
的方差,那么x
必须存在另一个列和fill + 1
向量不同的规则x
,以便
x
但是,由于fill + 1
为x_1
最大化fill
,并且渐变和Hessian的等式适用于任何dx_1
,我们有:
var(x_1 + dx_1) > var(x + dx)
因而矛盾。更清楚地解释这些步骤:
x
var(x)
的最佳选择是增加fill
中的最大元素,从而增加x
。此外,对于给定的var(x_1 + dx_1) = var(x_1) + gradient(var(x_1)) %*% dx_1 + 1/2 * t(dx_1) %*% Hessian(var(x_1)) %*% dx_1
<= var(x_1) + 2*(max(x_1)-mean(x_1))/(n_col-1) + constant
<= var(x) + 2*(max(x)-mean(x))/(n_col-1) + constant
= var(x + dx)
,二阶项是所有dx_1
和x_1
的常量,因此我们只需将其表示为x_1
。gradient(var(x_1)) %*% dx_1 <= 2*(max(x_1)-mean(x_1))/(n_col-1)
最大化x
的方差,(ii)dx
以获得最佳效果,我们假设{i} fill
constant
处的var(x_1) <= var(x)
规则,以及x
,fill
最大化gradient(var(x)) %*% dx = 2*(max(x)-mean(x))/(n_col-1)
处的差异。要查看后者,请考虑dx
的列总和fill
的常见前驱向量。递增max(x_1) <= max(x)
到x
和fill
之间的规则差异只是x_-1
中要增加的元素的不同选择。从fill-1
方差的泰勒级数展开式可以看出,x_-1
中要增加到x
的元素的选择必须大于或等于要去的x_1
到x_-1
因为x_-1
。因此,x_-1
。现在将此推理扩展到以前某个x
的列总和的任何公共向量,包括初始x_1
,其中列和的初始向量全部为var(x_1) <= var(x)
& #39; S。然后,对于一条路径,选择上面定义的最佳增量规则以达到max(x_1) <= max(x)
;而对于其他路径,请选择增量规则的任意路径以达到fill-k >= max(n_row, n_col)
。由于最优规则总是在每一步增加状态的最大元素(受上限限制),因此很明显再次fill
。最后,为了完成数学归纳,我们从1
全部为x
的初始填充开始。这通常会优化x_1
,因为max(x_1) <= max(x)
给定此初始填充时没有其他选择。现在,最优增量规则x
是选择1
的第一个元素来递增,因为所有元素都是相等的。结果var(x)
通常会使初始填充的方差最大化为1,因为增加x
的任何其他元素将导致相同的方差。
以上论点立即建议以下算法在列和的向量上分配值dx
:
x
的向量中的每个元素。x + dx
- 元素x
。请注意,我们会从填充中减去fill
,以便我们可以保留这些以填充至少为x
的列总和向量的其余元素,并将数量限制为i
以满足问题的限制。x[i] <- min(n_row, fill - (ncol_-i))
该算法和相关参数验证了OP的断言
像这样按列填充矩阵可以保持边际列总数的最大可变性
在R中,代码如下:
(n_col-i)
认识到循环中1
的重复递减可以用n_row
替换,上面简化为:
fill <- fill - x[i]
使用此功能,我们可以恢复OP的结果:
foo <- function(n_col, n_row, fill) {
## preallocate the vector of column sums x and initialize to NA
x <- rep(NA, n_col)
for (i in seq_len(n_col)) {
x[i] <- pmin.int(n_row, fill-(n_col-i))
fill <- fill - x[i]
}
## compute the variability given the vector of column sums x
sd(x)/mean(x)
}