我需要生成包含1和0的K
列和N
行的随机矩阵,以便:
a)每行包含k
个。{
b)每一行都与另一行不同(组合学强加如果N
> nchoosek(K, k)
将有nchoosek(K,k)
行。
假设我想要N = 10000
(在所有可能的nchoosek(K, k) = 27405
组合中),不同的1×K向量(K = 30
)包含k(含k = 4
)个并且K - k
零。
此代码:
clear all; close
N=10000; K=30; k=4;
M=randi([0 1],N,K);
plot(sum(M,2)) % condition a) not satisfied
既不满足a)也不满足b)。
此代码:
clear all; close;
N=10000;
NN=N; K=30; k=4;
tempM=zeros(NN,K);
for ii=1:NN
ttmodel=tempM(ii,:);
ttmodel(randsample(K,k,false))=1; %satisfies condition a)
tempM(ii,:)=ttmodel;
end
Check=bi2de(tempM); %from binary to decimal
[tresh1,ind,tresh2] = unique(Check);%drop the vectors that appear more than once in the matrix
M=tempM(ind,:); %and satisfies condition b)
plot(sum(M,2)) %verify that condition a) is satisfied
%Effective draws, Wanted draws, Number of possible combinations to draw from
[sum(sum(M,2)==k) N nchoosek(K,k) ]
满足条件a)和部分条件b)。我部分说,因为除非NN>> N,否则最终矩阵将包含少于N
个行,每个行彼此不同。
是否有更好更快的方法(可能避免使用for循环以及需要使用NN>> N)来解决问题?
答案 0 :(得分:2)
首先,生成 N 唯一的k-long位置的排列:
cols = randperm(K, N);
cols = cols(:, 1:k);
然后生成匹配的行索引:
rows = meshgrid(1:N, 1:k)';
最后用:
创建稀疏矩阵A = sparse(rows, cols, 1, N, K);
要获得矩阵的完整形式,请使用full(A)
。
K = 10;
k = 4;
N = 5;
cols = randperm(K, N);
cols = cols(:, 1:k);
rows = meshgrid(1:N, 1:k)';
A = sparse(rows, cols , 1, N, K);
full(A)
我得到的结果是:
ans =
1 1 0 0 0 0 0 1 0 1
0 0 1 1 0 1 0 0 0 1
0 0 0 1 1 0 1 0 1 0
0 1 0 0 0 0 1 0 1 1
1 1 1 0 0 1 0 0 0 0
即使对于 K 和 N 的大值,此计算也应该非常快。对于 K = 30, k = 4, N = 10000,结果在不到0.01秒内获得。
答案 1 :(得分:0)
你可以使用randperm(n)生成从1到n的整数的随机序列,并将非重复序列作为行存储在矩阵M中直到大小(唯一(M,'行'),1)== size(男,1)。然后,您可以使用M来索引逻辑矩阵,并在每行中使用适当数量的真值。
答案 2 :(得分:0)
如果你有足够的内存用于nchoosek(K,k)整数,建立一个这样的数组,使用部分Fisher-Yates shuffle来获得N个合适的均匀随机子集。现在,给定N个整数数组,将每个整数解释为表示最终数组的每一行的组合的等级。如果你使用组合的colexicographical排序,从排名计算组合是非常简单的(虽然它使用了大量的二项式组合函数,所以有一个快速的组合是值得的。)
我不是一个Matlab人,但我在C中做过类似的事情。例如:
for (i = k; i >= 1; --i) {
while ((b = binomial(n, i)) > r) --n;
buf[i-1] = n;
r -= b;
}
将使用buf[]
至0
的索引填充数组n-1
,以获取r
k
个n
个1
元素的组合colex order。您可以将这些解释为行中{{1}}的位置。