draw random number following a custom distribution [duplicate] - performance

This question already has answers here:
Weighted random numbers in MATLAB
(4 answers)
Closed 8 years ago.
I need to draw random numbers following a distribution I chose.
Example: draw 7 numbers from 1 to 7 with those probabilities:
1: 0.3
2: 0.2
3: 0.15
4: 0.15
5: 0.1
6: 0.05
7: 0.05
Since in my actual application I need to draw potentially 1000 numbers I need this to be as much efficient as possible (ideally linear).
I know there is a function in MATLAB that draws random numbers from a normal distribution; is there any way to adapt it?

Think you can use randsample too from Statistics Toolbox as referenced here.
%%// Replace 7 with 1000 for original problem
OUT = randsample([1:7], 7, true, [0.3 0.2 0.15 0.15 0.1 0.05 0.05])

numbers = 1:7;
probs = [.3 .2 .15 .15 .1 .05 .05];
N = 1000; %// how many random numbers you want
cumProbs = cumsum(probs(:)); %// will be used as thresholds
r = rand(1,N); %// random numbers between 0 and 1
output = sum(bsxfun(#ge, r, cumProbs))+1; %// how many thresholds are exceeded

You can use gendist from matlab file exchange: http://www.mathworks.com/matlabcentral/fileexchange/34101-random-numbers-from-a-discrete-distribution/content/gendist.m
This generates 1000 random numbers:
gendist([.3,.2,.15,.15,.1,.05,.05],1000,1)

If you do not have randsample, you can use histc like it does internally, just without all the fluff:
N = 100;
nums = 1:7;
p = [.3 .2 .15 .15 .1 .05 .05];
cdf = [0 cumsum(p(:).'/sum(p))]; cdf(end)=1; %' p is pdf
[~, isamps] = histc(rand(N,1),cdf);
out = nums(isamps);

Related

Plot 2-d data in Matlab [duplicate]

This question already has an answer here:
Creating colormap at specific point and color weights at matlab
(1 answer)
Closed 5 years ago.
I have data like this :
x coordinate| y coordinate | Z
0.01 | 0.15 | 1
0.23 | 0.17 | 5
0.28 | 0.18 | 6
... ... ...
I want to plot all of these data in 2-d such that , in each point (x,y)
we have the corresponding intensity Z which i want to be depicted with a colour . Just like the function 'image' which already exists . But i have a problem that the aforementioned function of matlab plot in a uniform manner all the points. So if i have
x= [0 0.01 1];
y = [0 1];
'Z = [1 1 0;0 1 1];'
Then it will plot the corresponding densities at the (0,0) (0.5,0) , (1 ,0)... So it takes the max of x and the min of x and take uniform pieces .
I want to plot my data in specific points.
Any ideas , is there any other suitable function for this ?
How can i construct something like that ?
If your data is a grid that has sligth variations on the values, but still a grid, do:
surf(x,y,z,'linestyle','none');
axis tight;axis off; view(2)
Example output with
z=peaks;
[x,y]=meshgrid(1:49,1:49);
x=x+rand(size(x))*0.1;
y=y+rand(size(x))*0.1;

How to create a uniformly random matrix in Julia?

l want to get a matrix with uniformly random values sampled from [-1,2]
x= rand([-1,2],(3,3))
3x3 Array{Int64,2}:
-1 -1 -1
2 -1 -1
-1 -1 -1
but it takes into consideration just -1 and 2, and I'm looking for continuous values for instance -0.9 , 0.75, -0.09, 1.80.
How can I do that?
Note: I am assuming here that you're looking for uniform random variables.
You can also use the Distributions package:
## Pkg.add("Distributions") # If you don't already have it installed.
using Distributions
rand(Uniform(-1,2), 3,3)
I do quite like isebarn's solution though, as it gets you thinking about the actual properties of the underlying probability distributions.
for random number in range [a,b]
rand() * (b-a) + a
and it works for a matrix aswell
rand(3,3) * (2 - (-1)) - 1
3x3 Array{Float64,2}:
1.85611 0.456955 -0.0219579
1.91196 -0.0352324 0.0296134
1.63924 -0.567682 0.45602
You need to use a FloatRange{Float64} with the dessired step:
julia> rand(-1.0:0.01:2.0, 3, 3)
3x3 Array{Float64,2}:
0.79 1.73 0.95
0.73 1.4 -0.46
1.42 1.68 -0.55

Matlab indexing two dimensions with linear indicies while keeping a third dimension constant

Say I have 2D linear indicies:
linInd = sub2ind(imSize,rowPnts,colPnts);
And I have a 3D color image I:
I = rand(64,64,3)*255
Is there any way that I can index something like this in order to get all coordinates in the 2D plane but for each channel of the image? That is, can I get all of the color channel information for each pixel with one command using linear indicies that are specified for 2D?
I(linInd,:)
So I don't have to split up the image into 3 parts and then reassemble again?
Thanks.
You can broadcast the 2D linear indices to a 3D case using bsxfun without messing with the input array, like so -
[m,n,r] = size(I);
out = I(bsxfun(#plus,linInd,(m*n*(0:r-1))'))
Sample setup
%// ---------------- 2D Case ---------------------
im = randi(9,10,10);
imSize = size(im);
rowPnts = [3,6,8,4];
colPnts = [6,3,8,5];
linInd = sub2ind(imSize,rowPnts,colPnts);
%// ---------------- 3D Case ---------------------
I = randi(9,10,10,4);
%// BSXFUN solution
[m,n,r] = size(I);
out = I(bsxfun(#plus,linInd,(m*n*(0:r-1))')); %//'
%// Tedious work of splitting
Ir = I(:,:,1);
Ig = I(:,:,2);
Ib = I(:,:,3);
Ia = I(:,:,4);
Output
>> Ir(linInd)
ans =
8 9 1 6
>> Ig(linInd)
ans =
1 5 9 8
>> Ib(linInd)
ans =
8 5 3 8
>> Ia(linInd)
ans =
8 8 3 3
>> out
out =
8 9 1 6
1 5 9 8
8 5 3 8
8 8 3 3
To my knowledge, reshaping the matrix first is the only way to use linear indexing this way.
I2=reshape(I,[],3)
I2(ind,:)
Is it specifically necessary for you to keep that dimension as the third? If not, you could permute the array to move that dimension to the 1st position, then use arr(i3d, linInd).

Sampling a Greyscale image into 8 levels

What I am trying to do:-
Using MATLAB, I am trying to read a Greyscale image (having pixel values bw range 0-255) i.e. an 8bit image into like 3 bit image, hence it is like sampling the range into 8 different levels. For example if the pixel value is 25 then as it comes bw range 0-31, it will be assigned value 0, for bw 32-63 level will be 1 and so on until finally range 224-255 it will be on range 7.
After that I am counting the total no of pixels in different levels.
Code:-
img=imread('Cameraman.bmp');
r=size(img,1);
c=size(img,2);
pixel_count=zeros(9,1);
for i=1:r
for j=1:c
if fix(img(i,j)/31)==8
img(i,j)
end
img(i,j)=fix(img(i,j)/33);
pixel_count(img(i,j)+1)=pixel_count(img(i,j)+1)+1;
end
end
pixel_count
My Problem:-
Even if the range of each pixel is from 0-255, and I am dividing it into 8 levels, I am getting a total of 9 levels.
For debugging it I added the if statement in the code and my output is:--
ans = 248
ans = 250
ans = 249
ans = 249
ans = 235
ans = 249
ans = 249
ans = 235
...and more
pixel_count =
11314
3741
2061
5284
12629
25590
4439
437
41
As you can see for some values like 249,235 and more I am getting the extra 9th level.
What is the problem here. Please help.
Thank You.
You aren't dividing by the right value properly. You need to divide by 32, then take the floor / fix. Between 0-31, if you divide by 32 then take the floor / fix, you get the value 0, between 31-63, you get 1, up until 224-255 which gives you 7.
Also, your for loop is incorrect. You are mistakenly replacing the pixel of the input image with its bin location. I would also change the precision to double. It seems that with my experiments, using fix combined with a uint8 image gives me that random 9th bin index that you're talking about.
Take a look at some sample results from my REPL:
>> fix(240/32) + 1
ans =
8
>> fix(uint8(240)/32) + 1
ans =
9
>> fix(uint8(255)/32) + 1
ans =
9
>> fix(255/32) + 1
ans =
8
Therefore, it's a problem with the image type. For any values that are beyond 240, the value when being divided by 32 as it's uint8 gets rounded so that 240 / 32 = 7.5 but because it's uint8 and it's an integer, it gets rounded to 8, then adding 1 makes it go to 9. Therefore, anything beyond 240 will get rounded to 8 and ultimately giving you 9 when adding by 1.
So, simply change the division to be 32, not 33 or 31 and fix what I said above:
img=imread('Cameraman.bmp');
img = double(img); %// Change
r=size(img,1);
c=size(img,2);
pixel_count=zeros(8,1); %// Change
for i=1:r
for j=1:c
pix = fix(img(i,j)/32); %// Change here
pixel_count(pix+1)=pixel_count(pix+1) + 1; %// Change
end
end
pixel_count
As a minor note, to check to see if you're right, use histc:
pixel_count = histc(fix(double(img(:))/32) + 1, 1:8);
If you got your code right, your code and with what I wrote above should match. Using the cameraman.tif image that's built-in to the Image Processing Toolbox, let's compare the outputs:
>> pixel_count
pixel_count =
13532
2500
2104
8341
15333
22553
817
356
>> pixel_count2 = histc(fix(double(img(:))/32) + 1, 1:8)
pixel_count2 =
13532
2500
2104
8341
15333
22553
817
356
Looks good to me!

Using Bi-cubic Interpolation

I read about it on Wikipedia, theory sounds good, but I don't know to apply to practice.
I have an small example like this one:
Original Image Matrix
1 2
3 4
If I want to double size the image, then the new matrix is
x x x x
x x x x
x x x x
x x x x
Now, the fun part is how to transfer old values in original matrix to the new matrix, I intend to do like this
1 x 2 x
x x x x
3 x 4 x
x x x x
Then applying the Bi cubic Interpolation on it (at this moment just forget about using 16 neighbor pixel, I don't have enough space to demonstrate such a large matrix here).
Now my questions are:
1. Do I do the data transferring (from old to new matrix) right? If not, what should it look like?
2. What should be the value of x variables in the new matrix? to me , this seems correct because at least we have some values to do the calculation instead of x notations.
1 1 2 2
1 1 2 2
3 3 4 4
3 3 4 4
3. Will all of the pixels in new matrix be interpolated? Because the pixels at the boundary do not have enough neighbor pixels to perform the calculation.
Thank you very much.
Interpolation means estimating a value for points that don't physically exist. You need to start with a coordinate system, so let's just use two incrementing integers for X position and Y position.
0, 0 1, 0
0, 1 1, 1
Your output requires 4x4 pixels which should be spaced at 0.5 intervals instead of the 1.0 intervals of the input:
-0.25,-0.25 0.25,-0.25 0.75,-0.25 1.25,-0.25
-0.25, 0.25 0.25, 0.25 0.75, 0.25 1.25, 0.25
-0.25, 0.75 0.25, 0.75 0.75, 0.75 1.25, 0.75
-0.25, 1.25 0.25, 1.25 0.75, 1.25 1.25, 1.25
None of the coordinates in the output exist in the input, so they'll all need to be interpolated.
The offset of the first coordinate of -0.25 is chosen so that the first and last coordinate will be equal distances from the edges of the input, and is calculated by the difference between the output and input intervals divided by 2. For example if you wanted a 10x zoom the interval is 0.1, the initial offset is (0.1-1)/2 and the points would be (-0.45, -0.35, -0.25, -0.15, ... 1.35, 1.45).
The Bicubic algorithm will require data for points outside of the original image. The easiest solution comes when you use a premultiplied alpha representation for your pixels, then you can just use (0,0,0,0) as the value for anything outside the image boundaries.

Resources