Info
此问题已关闭。 请重新打开它进行编辑或回答。
Random zero-restrictions in vector
5 次查看(过去 30 天)
显示 更早的评论
I have the following problem and I would be very grateful for support. Let, for instance,
A=[2 0 1]
and
B=[2 1 1 3 0 3]
where the elements of B refer to the index of A. (Context: B is a vector of workers and the elements indicate at which firm (1, 2 or 3) they are employed. 0 indicates unemployment. A is the vector indicating for each firm how many workers they want to lay off. For instance, firm 1 wants to lay of 2 workers. B is such that there is always enough workers to lay off for each firm.) I would like to create a matrix B1 (matrix of workers after random lay-offs) where for each index (firm) in A the corresponding number in A (the number of lay-offs) is randomly set to 0 in B. In the example it would be
B1=[2 0 0 3 0 0] or
B1=[2 0 0 0 0 3]
It would be great to do that without a for-loop. Is that actually possible? Any help is much appreciated! Thank you! Christian
0 个评论
回答(4 个)
Matt J
2015-1-13
编辑:Matt J
2015-1-13
No loops here, including the ones hidden inside cellfun, num2cell, arrayfun, etc... I still wonder, though, whether avoiding a for-loop is worthwhile.
nA=length(A); nB=length(B);
S=accumarray([(1:nB).',B.'+1],1);
idx=randperm(nB); iidx(idx)=1:nB;
SS=S(idx,2:end);
C=bsxfun(@gt,cumsum(SS,1),A).*SS;
B1=(C(iidx,:)*(1:nA).').'
2 个评论
Matt J
2015-1-13
编辑:Matt J
2015-1-13
Not sure why. I know bsxfun and accumarray get slower when the user supplies an arbitrary function handle for their FUNC arguments,
A = accumarray(SUBS,VAL,SZ,FUNC)
C = bsxfun(FUNC,A,B)
However, when accumarray is used with its default summation rule and bsxfun is used with its pre-optimized list of bi-operand functions (@plus, @minus, times, etc...) I think they've always been observed to outperform for-loops.
Alfonso Nieto-Castanon
2015-1-13
编辑:Alfonso Nieto-Castanon
2015-1-14
B1 = B;
i = randperm(numel(B));
c = sparse(find(B(i)),nonzeros(B(i)),1);
B1(i(~any(c&cumsum(c,1)>repmat(A,size(c,1),1),2)))=0;
EDIT: cleaned up the code a bit
1 个评论
Alfonso Nieto-Castanon
2015-1-13
编辑:Alfonso Nieto-Castanon
2015-1-14
this is just a variation of what Matt said before me
Guillaume
2015-1-13
It probably could be done with a loop using accumarray, arrayfun and cellfun, but the following would do and is much clearer. It's arguable that these three functions are not loops, anyway.
%demo data
tofire = [2 0 1 2];
workers = [4 2 1 4 1 3 0 4 3 4];
workersemployed = nonzeros(workers)';
employeecount = histc(workersemployed, unique(workersemployed));
for companyidx = 1:numel(tofire)
employees = find(ismember(workers, companyidx));
fired = randperm(employeecount(companyidx), tofire(companyidx));
workers(employees(fired)) = 0;
end
0 个评论
Andrei Bobrov
2015-1-13
编辑:Andrei Bobrov
2015-1-13
B1 = B;
ii = B~=0;
C = B(ii);
D = accumarray(C(:),(1:numel(C))',[],@(x){ x(randperm(numel(x))) });
x = cellfun(@(x,y)reshape(x(1:y),[],1),D,num2cell(A(:)),'un',0)
C(cat(1,x{:})) = 0;
B1(ii) = C;
with for..end loop
B1 = B;
for ii = 1:numel(A)
jj = find(ii == B);
B1(jj(randperm(numel(jj),A(ii)))) = 0;
end
0 个评论
此问题已关闭。
另请参阅
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!