I'm using Matlab and well it's straightforward to find the probability of an element in a matrix, but I a little unsure of how to find probability of an element in a row or column.
e.g this matrix:
X = [
1 2 4 1 8;
5 3 6 9 2;
6 2 2 3 2
];
How would I find the probability of "2" occurring in each row and column of this random matrix.
You could do the following:
X_unique = unique(X);
p_row = zeros(size(X,1),numel(X_unique));
p_col = zeros(size(X,2),numel(X_unique));
for ii = 1:size(X,1)
p_row(ii,:) = hist(X(ii,:),X_unique);
p_row(ii,:) = p_row(ii,:)/sum(p_row(ii,:));
end
for ii = 1:size(X,2)
p_col(ii,:) = hist(X(:,ii),X_unique);
p_col(ii,:) = p_col(ii,:)/sum(p_col(ii,:));
end
Now, each row of p_row contains the probability distribution of the elements of unique(X) in the corresponding row of X and each row of p_col contains the probability distribution of the elements of unique(X) in the corresponding column of X.
For example, for the given example,
X_unique =
1
2
3
4
5
6
8
9
Thus,
p_row =
0.4000 0.2000 0 0.2000 0 0 0.2000 0
0 0.2000 0.2000 0 0.2000 0.2000 0 0.2000
0 0.6000 0.2000 0 0 0.2000 0 0
p_col =
0.3333 0 0 0 0.3333 0.3333 0 0
0 0.6667 0.3333 0 0 0 0 0
0 0.3333 0 0.3333 0 0.3333 0 0
0.3333 0 0.3333 0 0 0 0 0.3333
0 0.6667 0 0 0 0 0.3333 0
Here's a simple, not-quite-Matlab-ish solution that works on non-empty bi-dimensional matrices, looking for elements with the value "2", and returning probabilities by column:
a = [1 2 4 1 8; 5 3 6 9 2; 6 2 2 3 2];
nrows = size(a,1);
ncols = size(a,2);
pc = zeros(1, ncols); % Prob. by column
% Iterate trough columns
for k = 1:ncols
n = sum(a(:,k) == 2);
pc(k) = n/nrows;
end;
You can adapt it to compute "probabilities" by row, or by other dimensions, or look for other values.
Related
I am working on a problem which requires me to group array elements and average each group. For example consider the 4 x 4 matrix M,
M = [ 1 0 0 1;
1 0 1 1;
1 1 0 1;
0 0 0 1;]
I want to group this into a 2 x 2 matrix, taking an average of the elements so we would get
M1 = [0.5 0.75;
0.5 0.5;]
does anyone know a way to do this?
Many thanks
You can do this using conv2, and a little indexing, like so:
>> A = conv2(M,ones(2), 'same');
>> A(1:2:end,1:2:end)/4
ans =
0.5000 0.7500
0.5000 0.5000
I think the way to go is to first split your matrix in parts using mat2cell, then apply your functions to each part and merge them to a new matrix:
>> M = [ 1 0 0 1;
1 0 1 1;
1 1 0 1;
0 0 0 1;]
M =
1 0 0 1
1 0 1 1
1 1 0 1
0 0 0 1
>> T=mat2cell(M, [2 2], [2 2])
T =
2×2 cell array
{2×2 double} {2×2 double}
{2×2 double} {2×2 double}
>> M1 = cellfun(#mean, cellfun(#mean, T, 'UniformOutput', false))
M1 =
0.5000 0.7500
0.5000 0.5000
>>
You can do something like this for any rectangle, where x and y denote the size of domains that you want to average.
function M1 = get_means(M, x, y)
[rows, cols] = size(M);
if mod(rows, x) == 0 && mod(cols, y) == 0
for i = 1:y:cols
for j = 1:x:rows
M1((j+x-1)/x, (i+y-1)/y) = sum(M(j:j+x-1,i:i+y-1),'all')/(x*y);
end
end
else
error('The matrix doesn''t have compatible dimensions.')
end
end
You can loop over the grouped matrices and then calculate the mean
M = [ 1 0 0 1;
1 0 1 1;
1 1 0 1;
0 0 0 1;];
n=2; % 2x2 mat
% create new matrix with means
MM = zeros(n,n);
% row counter for mean-Matrix
r=1;
% loop over matrix groups
for row=1:n:size(M,1)
c = 1; % column counter for mean-Matrix
for col=1:n:size(M,2)
MM(r,c) = mean(mean(M(row:row+n-1, col:col+n-1)));
c = c+1;
end
r = r+1;
end
Output:
MM =
0.5000 0.7500
0.5000 0.5000
i'm new to matlab, too used to python and having difficulty finding a way to filter a struct similar to how i can filter a pandas dataframe in python based on condition.
Matlab
a = arrayfun(#(x) x.value ==10, Data);
Data_10 = Data(a);
Error using arrayfun Non-scalar in Uniform output, at index 1, output
1. Set 'UniformOutput' to false.
How i would do so in python:
Data_10 = Data[Data.value == 10]
Try this:
Data_10 = zeros(size(Data.value));
Data_10(Data.value==10) == 10;
This should write into your array Data_10 the value 10 into each position, that has a 10 in Data and leave the rest as 0.
I am not sure if I fully understood your question. Here is my underestanding:
You want to filter certain values of an matrix.
Lets imagine we have a Matrix A filled with values. You want to filter values smaller than lowthresh = 0 and greater than upthresh = 5.
A = [3 6 -2.4 1; 0 34 4.76 0.5; 84 3 2.32 4; 1 -1 2 3.99];
lowthresh = 0;
upthresh = 5;
A(A<lowthresh | A>upthresh) = NaN; % Nan is a good flag
Output:
A =
3.0000 NaN NaN 1.0000
0 NaN 4.7600 0.5000
NaN 3.0000 2.3200 4.0000
1.0000 NaN 2.0000 3.9900
Having substituted your values you can do some basic functions ignoring NaNs:
For instance average:
mean(A,'omitnan')
ans =
1.3333 3.0000 3.0267 2.3725
I hope this adresses your question. Notice, that you can do this for any statement, that returns a boolean (isnan(), ... ) even if the boolean does not have anything to do with the matrix at all.
Lets say we have 2 matrizes that have the same size but different numbers:
A =
1 1 0
1 1 0
0 0 0
B =
0 0 0
0 0 0
0 0 0
We can easily say:
B(A==1) = 2
B =
2 2 0
2 2 0
0 0 0
I hope it helped a bit,
cheers Pablo
I am new to Matlab and I am trying to create programmatically a square Matrix which may have some random stochastic columns but I can't come up with a working solution. By stochastic column I mean the sum of the column elements which are positive should be equal to 1 (the column non-zero elements should be the same and their sum equal to 1). The position of the non-zero elements is not important in the matrix. PS: some columns could be all-zero elements and some could be with only one non-zero element, in this case 1.
I need your guidance or an example of working code on this guys. Thanks in advance.
Here is an example:
A=
0.2500 0.5000 0 0 0 0 0
0.2500 0.5000 0.3333 0 0 0 0
0 0 0.3333 0.2500 0 0 0.3333
0.2500 0 0 0.2500 0 0.5000 0
0.2500 0 0 0.2500 0 0 0
0 0 0 0.2500 0 0.5000 0.3333
0 0 0.3333 0 0 0 0.3333
% here is my code but it's not doing the work yet
n = 5;
A = zeros(n, 5);
i = 0;
for i = 1:n
if rand < 0.5
i = i + 1;
A(i, :) = rand(1, 5);
end
end
A = A(1:i, :)
First generate a random floating point matrix and threshold as you have done. Once you threshold this, simply sum along each column, then divide every column by the sum. Broadcasting will be useful here so that you avoid having to loop through or replicate the summed values per column over all rows.
Something like this should work:
n = 7;
A = rand(n, n) >= 0.5;
sumA = sum(A, 1);
A = bsxfun(#rdivide, A, sumA);
% Or in MATLAB R2016b and up:
% A = A ./ sumA;
A(isnan(A)) = 0;
The first two lines are self-explanatory. Choose n, then create a n x n square matrix of random 0s and 1s. The third line finds the sum of each column, and the fourth line which is the pièce de resistance is taking the sum of each column and doing an internal replication so that you create a temporary matrix that is the same size as the random matrix, but each column contains the total sum for that column. You then divide element wise and that produces your result. This is achieved with the bsxfun function. The last line of code is very important. Supposing that you have a column where there are no 1s. This means that when it's time to normalize, we will encounter a 0 / 0 error which translates to NaN. The last line of code finds any values that are NaN and sets them to 0.
Alternatively in MATLAB R2016b and up, you can simply do the element-wise division operator ./ and it does the broadcasting already.
Example Run
After running the above code, this is one potential result:
>> A
A =
0.2500 0.5000 0 0.2500 0 0 0
0 0 0.2500 0.2500 1.0000 0 0
0 0 0 0.2500 0 0.2500 0.3333
0.2500 0 0 0.2500 0 0.2500 0
0.2500 0.5000 0.2500 0 0 0.2500 0
0 0 0.2500 0 0 0.2500 0.3333
0.2500 0 0.2500 0 0 0 0.3333
What about all zero columns?
To ensure that the code works for all zero columns, simply make the threshold when you create the random matrix more aggressive. Make it higher, like 0.8 or so. This means that there's a higher chance that you will get a 0 than a 1.
Therefore, I changed the second line of code to:
A = rand(n, n) >= 0.8;
When I did this and ran the code again, this is what I get for one run:
>> A
A =
0 0 0 0.2500 0 0.5000 0
0 0.5000 1.0000 0.2500 0 0.5000 0
0 0 0 0 1.0000 0 1.0000
0 0.5000 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0.2500 0 0 0
0 0 0 0.2500 0 0 0
I'm trying to solve a system of 10 linear equations out of which the middle 8 equations look alike. They look like this :
t_i-1 - 2.3086*(t_i) + t_i+1 == -7.7160
where i = 2:9
so I decided to construct the coefficient matrix and the constant matrix(array) for the system of equations through looping.This is what I did.
T = sym('t' , [1 10]); %% Creates a vector T = [ t1 t2 .... t10]
A_10 = zeros(10,10);
b_10 = zeros(10,1);
for i = 2:9 %% This loop generates the equations and arranges them in the matrices A_10 and B_10.
T(i-1) - 2.3086*T(i) + T(i+1) == -7.7160;
[A_10(i,i-1:i+1),b_10(i,1)] = equationsToMatrix(ans)
end
Everything except for the ninth row(last but one) is correct in the Matrix A_10. This is what A_10 looks like
A_10 =
Columns 1 through 9
0 0 0 0 0 0 0 0 0
1.0000 -2.3086 1.0000 0 0 0 0 0 0
0 1.0000 -2.3086 1.0000 0 0 0 0 0
0 0 1.0000 -2.3086 1.0000 0 0 0 0
0 0 0 1.0000 -2.3086 1.0000 0 0 0
0 0 0 0 1.0000 -2.3086 1.0000 0 0
0 0 0 0 0 1.0000 -2.3086 1.0000 0
0 0 0 0 0 0 1.0000 -2.3086 1.0000
0 0 0 0 0 0 0 1.0000 1.0000
0 0 0 0 0 0 0 0 0
Column 10
0
0
0
0
0
0
0
0
-2.3086
0
The last three elements of the row nine should be 1 , -2.3086 , 1 like the previous rows but it shows 1, 1, -2.3086. What am I doing wrong here?
This is what the iteration looks like in the loop
ans = t8 - (11543*t9)/5000 + t10 == -1929/250
The equation is correct too. I can't figure out what the problem is.
Without the second input vars, equationsToMatrix uses symvar to determine the variable list.
Using symvar directly with the last equation gives
>> i = 9;symvar(T(i-1) - 2.3086*T(i) + T(i+1) == -7.7160)
ans =
[ t10, t8, t9]
So for whatever reason, symvar produced the incorrect ordering for only the last equation (possibly because 1 < 9). To remedy the situation, pass your intended ordering using the second input
eqn = T(i-1) - 2.3086*T(i) + T(i+1) == -7.7160;
[A_10(i,i-1:i+1),b_10(i,1)] = equationsToMatrix(eqn,T(i-1:i+1));
You'll also noticed I assigned the equation to an explicit variable eqn. This is better practice than relying on ans.
Also, since you're producing a numeric array anyway, you can produce A without the Symbolic Toolbox in a number of ways. For example:
n = 10;
A = full(spdiags(ones(n,1)*[1,-2.3086,1],[-1,0,1],n,n));
A([1,end],:) = 0;
Say I have the following two matrices:
>> x = [1 4 3; 6 4 3; 6 9 3; 2 4 3; 5 4 0; 5 3 1; 6 4 7];
>> y = [0 0 1; 1 1 0; 1 1 0; 0 1 1; 0.2 0.8 0.54; 1 1 1; 0 0 0];
Where you can think of x as some image, and y the degree of membership of of each element of x to some region of interest.
Say I set those elements in x that have degree of membership = 1 to 1 and the other elements to 0 as follows:
x = zeros(size(y));
x(y==1) = 1;
In which case I will have the following output:
0 0 1
1 1 0
1 1 0
0 1 1
0 0 0
1 1 1
0 0 0
Now, for the elements of 0, how can I substitute their values with the value of y in the corresponding location?
Thanks.
Try this:
x(x==0)=y(x==0);
Ans:
x =
0 0 1.0000
1.0000 1.0000 0
1.0000 1.0000 0
0 1.0000 1.0000
0.2000 0.8000 0.5400
1.0000 1.0000 1.0000
0 0 0