I have the problem when I compute in a matrix. This problem is about the speed of computation.
I have a matrix of binary image (f), I find conected component by bwlabel in matlab. [L num]=bwlabel(f);
after that base on some property I found a vector p that include some value of L that I need to remove. this is my code and explanation
function [f,L] = clear_nontext(f,L,nontext)
% p is a vector include a lot of value we need to remove
p=find(nontext(:)~=0);
% example p= [1 2 9 10 100...] that mean we need to find in L matrix where get the value =1,2,9,10,100..] and remove it
[a b]=size(L);
g=zeros(a,b);
for u=1:length(p)
for i=1:a
for j=1:b
if L(i,j)==p(u)
g(i,j)=1;
%L(i,j)=500000;
f(i,j)=0;
end
end
end
end
end
When I use this way, program run but it is so slow, because with one value of p we need to check all value in matrix f (or L) again. So I need another way to run it faster. Could you help me?
Thank you so much
Generally, MATLAB performs matrix operations (or index operations) faster then loops.
You can try the following:
g(ismember(L,p)) = 1;
f(ismember(L,p)) = 1;
EDIT:
I was curious so I ran a little test:
L = round(20*randn(10000,10000));
f = L;
p = 1:5;
[a b]=size(L);
g=zeros(a,b);
tic;
for u=1:length(p)
for i=1:a
for j=1:b
if L(i,j)==p(u)
g(i,j)=1;
f(i,j)=0;
end
end
end
end
toc
for which I got:
Elapsed time is 38.960842 seconds.
When I tried the following:
tic;
g(ismember(L,p)) = 1;
f(ismember(L,p)) = 0;
toc
I got
Elapsed time is 5.735137 seconds.
Related
just started out with matlab and have some troubles finding the solution for the following action:
I am trying to initialize a vector of 1000 different values, with a function that doesn't take any arguments as input. I can do this with a for loop, but haven't found out how to do it without.
What I expected that would work:
z = zeros(1,1000)
result = arrayfun(*functionname*,z)
This however gives an error saying that the first input must be a function handle.
My function is a simple implementation of a monte carlo method to calculate pi:
function Result = mcm()
clear
N=1000;
M=0;
for j=1:N
p=[2*rand-1; 2*rand-1];
if p'*p<1
M=M+1;
end
end
Result=4*M/N
One way to actually vectorize your given function mcm would be -
N = 1000; %// Number of data points
P = [2*rand(1,N)-1; 2*rand(1,N)-1]; %// OR 2*rand(2,N)-1
out = 4*sum(sum(P.^2,1)<1)/N
Runtime tests
Code -
N = 1000000; %// Number of data points
disp('---------------- With Original Approach')
tic
M=0;
for j=1:N
P=[2*rand-1; 2*rand-1];
if P'*P<1
M=M+1;
end
end
Result=4*M/N;
toc
disp('---------------- With Proposed Approach')
tic
P = 2*rand(2,N)-1;
out = 4*sum(sum(P.^2,1)<1)/N;
toc
Timings & Outputs -
---------------- With Original Approach
Elapsed time is 3.952998 seconds.
---------------- With Proposed Approach
Elapsed time is 0.089590 seconds.
>> Result
Result =
3.1422
>> out
out =
3.1428
Since your function takes no arguments you can't use arrayfun. arrayfun applies the function to each element in the array.
Instead use this:
z = ones(1,1000) * mcm;
A side benefit is that mcm will only run once so it will be faster than looping that function 1000 times.
I am trying to write a Matlab code to simulate a dice and compute its mean and standard deviation.
The problem is that no matter how many times we run this code, the result of randi(6) keeps the same. It made me crazy.
n=20;
m=0;
c=0;
for i=1:10000
while m<n
x=randi(6);
c=c+1;
m=m+x;
end
M(i)=m;
count(i)=c;
diff(i)=M(i)-n;
end
I think you forgot to set m back to ZERO at the end of the for. If you want the sequence of randi to change you should take a look at the function "rng".
n=20;
m=0;
c=1;
for i=1:100
while m<n
x(i, c)=randi(6);
m=m+x(i,c);
c=c+1;
end
M(i)=m;
count(i)=c;
diff(i)=M(i)-n;
m = 0;
end
You forgot to reset m and c back to 0 once the while loop terminates. m is set to 0 outside of the for loop only once, and so when m finally surpasses n, m never changes. As such, simply set m = 0 in your for loop before the while loop happens. You also need to set c to 0 because you want to count events each time the for loop iterates.
I'm also not sure how you could think that diff(i) = 2.5 for all i. This difference is a probabilistic value. Also, I don't see how you could get a floating point number in the difference because you are generating integers and accumulating integers for each trial. I think you need to examine what this value should be.
So:
n=20;
%//m=0;
%//c=0;
for i=1:10000
m = 0; %// Change here
c = 0; %// Change here too
while m<n
x=randi(6);
c=c+1;
m=m+x;
end
M(i)=m;
count(i)=c;
diff(i)=M(i)-n;
end
yesterday I implemented my first bootstrap in MATLab. (and yes, I know, for loops are evil.):
%data is an mxn matrix where the data should be sampled per column but there
can be a NaNs Elements
%from the array (a column of data) n values are sampled nReps times
function result = bootstrap_std(data, n, nReps,quantil)
result = zeros(1,size(data,2));
for i=1:size(data,2)
bootstrap_data = zeros(n,nReps);
values = find(~isnan(data(:,i)));
if isempty(values)
bootstrap_data(:,:) = NaN;
else
for k=1:nReps
bootstrap_data(:,k) = datasample(data(values,i),n);
end
end
stat = zeros(1,nReps);
for k=1:nReps
stat(k) = nanstd(bootstrap_data(:,k));
end
sort(stat);
result(i) = quantile(stat,quantil);
end
end
As one can see, this version works columnwise. The algorithm does what it should but is really slow when the data size increaes. My question is now: Is it possible to implement this logic without using for loops? My problem is here that I could not find a version of datasample which does the sampling columnwise. Or is there a better function to use?
I am happy for any hint or idea how I can speed up this implementation.
Thanks and best regards!
stephan
The bottlenecks in your implementation are
The function spends a lot of time inside nanstd which is unnecessary since you exclude NaN values from your sample anyway.
There are a lot of functions that operate column-wise, but you spend time looping over the columns and calling them many times.
You make many calls to datasample which is a relatively slow function. It's much faster to create a random vector of indices using randi and use that instead.
Here's how I would write the function (actually I probably wouldn't put in this many comments, and I wouldn't use so many temp variables, but I'm doing it now so you can see what all the steps of the computation are).
function result = bootstrap_std_new(data, n, nRep, quantil)
result = zeros(1, size(data,2));
for i = 1:size(data,2)
isbad = isnan(data(:,i)); %// Vector of NaN values
if all(isbad)
result(i) = NaN;
else
data0 = data(~isbad, i); %// Temp copy of this column for indexing
index = randi(size(data0,1), n, nRep); %// Create the indexing vector
bootstrapdata = data0(index); %// Sample the data
stdevs = std(bootstrapdata); %// Stdev of sampled data
result(i) = quantile(stdevs, quantil); %// Find the correct quantile
end
end
end
Here are some timings
>> data = randn(100,10);
>> data(randi(1000, 50, 1)) = NaN;
>> tic, bootstrap_std(data, 50, 1000, 0.5); toc
Elapsed time is 1.359529 seconds.
>> tic, bootstrap_std_new(data, 50, 1000, 0.5); toc
Elapsed time is 0.038558 seconds.
So this gives you about a 35x speedup.
Your main issue seems to be that you may have varying numbers/positions of NaN in each column, so can't work on the full matrix unless you're okay with also sampling NaNs. However, some of the inner loops could be simplified.
for k=1:nReps
bootstrap_data(:,k) = datasample(data(values,i),n);
end
Since you're sampling with replacement, you should be able to just do:
bootstrap_data = datasample(data(values,i), n*nReps);
bootstrap_data = reshape(bootstrap_data, [n nReps]);
Also nanstd can work on a full matrix so no need to loop:
stat = nanstd(bootstrap_data); % or nanstd(x,0,2) to change dimension
It would also be worth just looking over your code with profile to see where the bottlenecks are.
clear all
k_1 = 37.6;
miu_1 = 41;
Den = 2.7;
N = 100;
n=1;
phi(1)=1;
for n=1:N
phi(n)= 0.3*(n/N);
K_s(n)= K_1*(1-(1+(3*k_1)/(4*miu_1))*phi(n));
miu_s(n)= miu_1*(1-(1+(3*k_1)/(4*miu_1))*phi(n));
den1(n)=Den*(1-phi(n));
vp(n)=sqrt((k_s(n)+(4/3)*miu_s(n))/den1(n));
end
figure(1);
plot(phi,miu_s);
figure(2);
plot (phi,vp)
i am new on matlab and do not know what is problem with my code when i run my program only a beep buzz and nothing happens. guide me
The reason your code doesn't work is case sensitivity. You are using k_1 and K_1, and k_s and K_s (unless that is intentional). When I change that, your code compiles ok.
clear all
k_1 = 37.6;
miu_1 = 41;
Den = 2.7;
N = 100;
n=1;
phi(1)=1;
for n=1:N
phi(n)= 0.3*(n/N);
k_s(n)= k_1*(1-(1+(3*k_1)/(4*miu_1))*phi(n));
miu_s(n)= miu_1*(1-(1+(3*k_1)/(4*miu_1))*phi(n));
den1(n)=Den*(1-phi(n));
vp(n)=sqrt((k_s(n)+(4/3)*miu_s(n))/den1(n));
end
figure(1);
plot(phi,miu_s);
figure(2);
plot (phi,vp)
when programming in MatLab, is usually a good practice to prealocate variables instead of declaring them in a loop. In this way, MatLab creates the object just once and changes each of it's values once in the loop. Otherwise you will be declaring a new variable and writing all its contents every loop iteration which is a costly process. Your Code might be working but be extreeeeemly slow, leading you to think nothing is happening. Try prealocating all the variables inside the loop with the zeros() function like this:
phi=zeros(N,1);
phi(1)=1;
K_s=zeros(N,1);
%... and so on for all your variables inside the loop
for n=1:N
phi(n)= 0.3*(n/N);
K_s(n)= k_1*(1-(1+(3*k_1)/(4*miu_1))*phi(n));
miu_s(n)= miu_1*(1-(1+(3*k_1)/(4*miu_1))*phi(n));
den1(n)=Den*(1-phi(n));
vp(n)=sqrt((k_s(n)+(4/3)*miu_s(n))/den1(n));
end
Hope that helps
You are doing a lot of unnecessary things here, including that entire loop.
For example:
N = 100;
n=1; %this value is never used
phi(1)=1; % this is overwritten in loop
for n=1:N
phi(n)= 0.3*(n/N);
... (loop continues)
You don't need a loop here. Instead, work on whole vectors
N = 100;
n = 1:100; %predefine vector
phi = 0.3*(n/N); % outputs vector of phi from 0.003 to 0.3
For cases when you are combining multiple vectors remember to use ./ and .* for element-wise divison and multiplication, e.g. the last equation will end up being:
vp=sqrt((k_s+(4/3)*miu_s)./den1);
Having a vector x and I have to add an element (newElem) .
Is there any difference between -
x(end+1) = newElem;
and
x = [x newElem];
?
x(end+1) = newElem is a bit more robust.
x = [x newElem] will only work if x is a row-vector, if it is a column vector x = [x; newElem] should be used. x(end+1) = newElem, however, works for both row- and column-vectors.
In general though, growing vectors should be avoided. If you do this a lot, it might bring your code down to a crawl. Think about it: growing an array involves allocating new space, copying everything over, adding the new element, and cleaning up the old mess...Quite a waste of time if you knew the correct size beforehand :)
Just to add to #ThijsW's answer, there is a significant speed advantage to the first method over the concatenation method:
big = 1e5;
tic;
x = rand(big,1);
toc
x = zeros(big,1);
tic;
for ii = 1:big
x(ii) = rand;
end
toc
x = [];
tic;
for ii = 1:big
x(end+1) = rand;
end;
toc
x = [];
tic;
for ii = 1:big
x = [x rand];
end;
toc
Elapsed time is 0.004611 seconds.
Elapsed time is 0.016448 seconds.
Elapsed time is 0.034107 seconds.
Elapsed time is 12.341434 seconds.
I got these times running in 2012b however when I ran the same code on the same computer in matlab 2010a I get
Elapsed time is 0.003044 seconds.
Elapsed time is 0.009947 seconds.
Elapsed time is 12.013875 seconds.
Elapsed time is 12.165593 seconds.
So I guess the speed advantage only applies to more recent versions of Matlab
As mentioned before, the use of x(end+1) = newElem has the advantage that it allows you to concatenate your vector with a scalar, regardless of whether your vector is transposed or not. Therefore it is more robust for adding scalars.
However, what should not be forgotten is that x = [x newElem] will also work when you try to add multiple elements at once. Furthermore, this generalizes a bit more naturally to the case where you want to concatenate matrices. M = [M M1 M2 M3]
All in all, if you want a solution that allows you to concatenate your existing vector x with newElem that may or may not be a scalar, this should do the trick:
x(end+(1:numel(newElem)))=newElem