Write for logical value Matlab - matlab

Let's say T=1:20 ; P=[2 6 9 11 15 19].
How to write a logical value for P in range T?
The answer I want is: flag= [0 1 0 0 0 1 0 0 1 0 1 0 0 0 1 0 0 0 1 0].

Use ismember made for exactly this task -
ismember(T,P)

You can define a logical vector flag the size of T, then use P as an index vector of the flag to raise to true:
T=1:20 ; P=[2 6 9 11 15 19] ;
flag = false(size(T)) ;
flag(P) = true ;
flag =
0 1 0 0 0 1 0 0 1 0 1 0 0 0 1 0 0 0 1 0

For the fun of it, an alternative to Hoki's answer:
T(P) = 0;
flag = ~T
This sets all values that are in P equal to zero, and then checks if the values in T is 0 or not. This of course has the downside that it overwrites T. Note: I would go for Hoki's answer!

Related

permutation/combination with specific condition

Let us we have binary number to fill out 9 spots with specific condition: 0 always comes before 1. the possible conditions is 10:
1 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1
0 0 1 1 1 1 1 1 1
0 0 0 1 1 1 1 1 1
0 0 0 0 1 1 1 1 1
0 0 0 0 0 1 1 1 1
0 0 0 0 0 0 1 1 1
0 0 0 0 0 0 0 1 1
0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0
Now lest us extent it to 0, 1, 2 with same rule. 0 should be always before 1 and/or 2. 1 should be before 1. Again, 9 spots are available to fill out.
I know that this yields to 55 combinations.
Question:
(1) what is the mathematical formulation to generalize this?
(2) How can I store all those 55 combinations? [any matlab code?]
Thanks
As the commenter said, the answer comes down to stars and bars. You can also think of this as counting the number of non-decreasing sequences i_1 <= i_2 <= ... <= i_k, where k is the number of symbols available and each i_j is a number between 0 and 9.
That said, here's a matlab script that generates all possibilities. Each row of the output matrix is one possible string of digits.
function M = bin_combs(L,k)
% L: length
% k: number of symbols
if k == 1
M = zeros(1,L);
else
M = zeros(0,L);
N = bin_combs(L,k-1);
for i = 1:size(N,1)
row = N(i,:);
for j=find(row==k-2)
new_row = row;
new_row(j:end) = new_row(j:end) + 1;
M = [M;new_row];
end
M = [M;row];
end
end
Some sample output:
>> size(bin_combs(9,3))
ans =
55 9
>> size(bin_combs(9,4))
ans =
220 9

Performing an averaging operation over every n elements in a vector

I have a logical vector in which I would like to iterate over every n-elements. If in any given window at least 50% are 1's, then I change every element to 1, else I keep as is and move to the next window. For example.
n = 4;
input = [0 0 0 1 0 1 1 0 0 0 0 1 0 1 0 1 0 0 0 1];
output = func(input,4);
output = [0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1 0 0 0 1];
This function is trivial to implement but is it possible to apply a vectorized implementation using logical indexing?. I am trying to build up the intuition of applying this technique.
here's a one liner (that works for your input):
func = #(input,n) input | kron(sum(reshape(input ,n,[]))>=n/2,ones(1,n));
of course, there are cases to solve that this doesnt answer, what if the size of the input is not commensurate in n? etc...
i'm not sure if that's what you meant by vectorization, and I didnt benchmark it vs a for loop...
Here is one way of doing it. Once understood you can compact it in less lines but I'll details the intermediate steps for the sake of clarity.
%% The inputs
n = 4;
input = [0 0 0 1 0 1 1 0 0 0 0 1 0 1 0 1 0 0 0 1];
1) Split your input into blocks of size n (note that your final function will have to check that the number of elements in input is a integer multiple of n)
c = reshape(input,n,[]) ;
Gives you a matrix with your blocks organized in columns:
c =
0 0 0 0 0
0 1 0 1 0
0 1 0 0 0
1 0 1 1 1
2) Perform your test condition on each of the block. For this we'll take advantage that Matlab is working column wise for the sum function:
>> cr = sum(c) >= (n/2)
cr =
0 1 0 1 0
Now you have a logical vector cr containing as many elements as initial blocks. Each value is the result of the test condition over the block. The 0 blocks will be left unchanged, the 1 blocks will be forced to value 1.
3) Force 1 columns/block to value 1:
>> c(:,cr) = 1
c =
0 1 0 1 0
0 1 0 1 0
0 1 0 1 0
1 1 1 1 1
4) Now all is left is to unfold your matrix. You can do it several ways:
res = c(:) ; %% will give you a column vector
OR
>> res = reshape(c,1,[]) %% will give you a line vector
res =
0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1 0 0 0 1

How to create an error function comparing two matrices?

I have two matrices in MATLAB. Each one is filled with 1 and 0 at different positions. I want to compare each element:
If there is a 1 match, I want it to record as True Positive.
If there is a 0 match, I want it to record as True Negative.
If one says 1 and the other says 0, I want to record as False Positive.
If one says 0 and the other says 1, I want to record as False Negative.
I tried just comparing the two matrices:
idx = A == B
But, that gives me a simple match, not telling me when there is a True Positive or Negative, etc.
Is there any specific function I could use, or any alternative?
You could just add the matrices in a prescribed way....
a = [1 0 1 0
1 1 0 0
0 0 1 1];
b = [1 0 0 0
0 0 0 1
0 0 1 0];
C = a + 2*b;
% For pairs [a,b] we expect
% [0,0]: C = 0, true negative
% [1,0]: C = 1, false positive
% [0,1]: C = 2, false negative
% [1,1]: C = 3, true positive
% C =
% [ 3 0 1 0
% 1 1 0 2
% 0 0 3 1 ]
If you have the Statistics and Machine Learning toolbox and you only want a summary, you might just need the function confusionmat.
From the docs:
C = confusionmat(group,grouphat) returns the confusion matrix C determined by the known and predicted groups in group and grouphat. [...]. C is a square matrix with size equal to the total number of distinct elements in group and grouphat. C(i,j) is a count of observations known to be in group i but predicted to be in group j.
For example:
a = [1 0 1 0
1 1 0 0
0 0 1 1];
b = [1 0 0 0
0 0 0 1
0 0 1 0];
C = confusionmat( a(:), b(:) );
% C =
% [ 5 1
% 4 2]
% So for each pair [a,b], we have 5*[0,0], 2*[1,1], 4*[1,0], 1*[0,1]
A similar function for those with the Neural Network Toolbox instead would be confusion.
You could just use bitwise operators to produce the four different values:
bitor(bitshift(uint8(b),1),uint8(a))
Produces an array with
0 : True Negative
1 : False Negative (a is true but b is false)
2 : False Positive (a is false but b is true)
3 : True Positive
One naive approach would be four comparisons, case by case:
% Set up some artificial data
ground_truth = randi(2, 5) - 1
compare = randi(2, 5) - 1
% Determine true positives, false positives, etc.
tp = ground_truth & compare
fp = ~ground_truth & compare
tn = ~ground_truth & ~compare
fn = ground_truth & ~compare
Output:
ground_truth =
1 0 1 0 0
0 1 1 0 1
1 1 0 1 0
0 1 0 1 1
0 0 0 1 0
compare =
0 1 1 0 1
0 1 1 1 0
1 1 0 0 1
1 1 1 0 0
1 1 1 1 1
tp =
0 0 1 0 0
0 1 1 0 0
1 1 0 0 0
0 1 0 0 0
0 0 0 1 0
fp =
0 1 0 0 1
0 0 0 1 0
0 0 0 0 1
1 0 1 0 0
1 1 1 0 1
tn =
0 0 0 1 0
1 0 0 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 0 0
fn =
1 0 0 0 0
0 0 0 0 1
0 0 0 1 0
0 0 0 1 1
0 0 0 0 0
That works, because 0 and 1 (or any positive value) are alternative representations for true and false.
To keep your main code clean, set up a separate function, say my_stats.m
function [tp, fp, tn, fn] = my_stats(ground_truth, compare)
% Determine true positives, false positives, etc.
tp = ground_truth & compare;
fp = ~ground_truth & compare;
tn = ~ground_truth & ~compare;
fn = ground_truth & ~compare;
end
and call it in your main code:
% Set up some artificial data
ground_truth = randi(2, 5) - 1
compare = randi(2, 5) - 1
[tp, fp, tn, fn] = my_stats(ground_truth, compare)
Hope that helps!
I found that I can use the find method and set two conditions, then just find the numbers of the element in each variable
TruePositive = length(find(A==B & A==1))
TrueNegative = length(find(A==B & A==0))
FalsePositive = length(find(A~=B & A==1))
FalseNegative = length(find(A~=B & A==0))
The confusionmatrix() method suggested by #Wolfie is also really neat, especially if you use the confusionchart() which provides a nice visualisation.

Measure how spread out the data in an array is

I have an array of zeros and ones and I need to know if the data is spread out across the columns or concentrated in clumps.
For example:
If I have array x and it has these values:
Column 1 values: 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1
Column 2 values: 1 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 1 0 0 0 1
if we counted the number of ones we can know that it is the same number but the ones are more well spread out and distributed in column 2 compared with column 1.
I am trying to make a score that gives me a high value if the spreading is good and low value if the spreading is bad... any ideas??
Sample of Data:
1 0 0 0 5 0 -2 -3 0 0 1
1 0 0 0 0 0 0 0 0 0 1
2 0 0 0 0 0 0 3 -3 1 0
1 2 3 0 5 0 2 13 4 5 1
1 0 0 0 0 0 -4 34 0 0 1
I think what you're trying to measure is the variance of the distribution of the number of 0s between the 1s, i.e:
f = #(x)std(diff(find(x)))
So for you data:
a = [1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1]
b = [1 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 1 0 0 0 1]
f(a)
= 8.0498
f(b)
= 2.0736
But I still think you're essentially trying to measure the disorder of the system which is what I imagine entropy measures but I don't know how
Note that this gives a low value if the "spreading" is good and a high value if it is bad (i.e. the opposite of your request).
Also if you want it per column then it becomes a little more complicated:
f = #(x)arrayfun(#(y)std(diff(find(x(:,y)))), 1:size(x,2))
data = [a', b'];
f(data)
WARNING: This method pretty much does not consider trailing and leading 0s. I don't know if that's a problem or not. but basically f([0; 0; 0; 1; 1; 1; 0; 0; 0]) returns 0 where as f([1; 0; 0; 1; 0; 1; 0; 0; 0]) returns a positive indicating (incorrectly) that first case is more distributed. One possible fix might be to prepend and append a row of ones to the matrix...
I think you would need an interval to find the "spreadness" locally, otherwise the sample 1 (which is named as Column 1 in the question) would appear as spread too between the 2nd and 3rd ones.
So, following that theory and assuming input_array to be the input array, you can try this approach -
intv = 10; %// Interval
diff_loc = diff(find(input_array))
spread_factor = sum(diff_loc(diff_loc<=intv)) %// desired output/score
For sample 1, spread_factor gives 4 and for sample 2 it is 23.
Another theory that you can employ would be if you assume an interval such that distance between consecutive ones must be greater than or equal to that interval. This theory would lead us to a code like this -
intv = 3; %// Interval
diff_loc = diff(find(input_array))
spread_factor = sum(diff_loc>=intv)
With this new approach - For sample 1, spread_factor is 1 and for sample 2 it is 5.

MATLAB swap columns of two different matrices

Im using matlab and am having some difficulty. I am trying to swap the columns of one matrix (A) with the column of another matrix (B). For Example:
A =
4 6 5
7 8 4
6 5 9
1 0 0
0 1 0
0 0 1
B =
1 0 0 0 0 0
0 1 0 0 0 0
0 0 1 0 0 0
0 0 0 -1 0 0
0 0 0 0 -1 0
0 0 0 0 0 -1
Is there a way to tell Matlab to switch, for instance, column 1 in A with column 3 in B?
You can actually perform this column swap in one line and without the need for dummy variables using the function DEAL:
[A(:,1),B(:,3)] = deal(B(:,3),A(:,1));
tmp = A(:,1);
A(:,1) = B(:,3);
B(:,3) = tmp;
Use
A(:,1) = B(:,3);
Or to actually swap them, you can use:
dummy = A(:,1);
A(:,1) = B(:,3);
B(:,3) = dummy;