I have the following row vector:
A = zeros(1,200);
I'd like to insert a '1' every 2-3 columns until I have exactly 80 ones in total that are approximately evenly spaced - as opposed to having fixed spacing - with the first 2 columns being zeros.
e.g.
0 0 1 0 1 0 0 1 0 0 1 0 1 ...
It would be nice if the combination could be permuted as well so that more than one row vector satisfies the criteria.
Thanks!
You could use repelem (run-length encoding) to do this. The way that repelem works is that we have two inputs: the values and the number of times each value is repeated.
For example
values = [0 1];
repeats = [1 2];
repelem(values, repeats)
% 0 1 1
We can also have duplicate values in the values array
values = [0 1 0 1];
repeats = [2 1 1 1];
repelem(values, repeats)
% 0 0 1 0 1
We can utilize this to solve your problem.
First we construct the values matrices to simply alternate between 0 and 1 meaning that we want the expanded matrix to contain some 0's followed by a 1, some 0's followed by a 1, etc.
values = ~mod(1:80, 2);
% 0 1 0 1 0 1 0 1 ....
In your case, the number of times each 0 is going to be repeated is going to be either 1 or 2. Each 1 however, is only going to be repeated once. To make this happen we use rand to pick randomly between 1 and 2 repeats. Then we assign all the repeats for 1 values to be a single repeat.
repeats = randi([1 2], size(values));
% Make sure that the 1's are always only repeated once
repeats(values) = 1;
We use 80 entries in the repeats and values arrays just to make sure that we end up with at least 80 values in the final (expanded) array.
Now apply the repelem and keep only the first 80 values
result = repelem(values, repeats);
result = result(1:80);
% 0 1 0 0 1 0 0 1 0 1 0 0 1
You can do this with a few standard functions and array indexing. Something like this ...
A = zeros(1,200);
ixs = round(cumsum(2 + rand(200,1)));
A(ixs(ixs<200))=1;
%Sample result here, first 20 entries: 0 0 1 0 1 0 0 1 0 0 1 0 1 0 0 1 0 1 0 1
What we're doing here is:
Setting up the A array (this is clear)
Defining an oversized array of index values to set to one (more on that below)
Then using that index to set values to one, trimming the oversize.
In terms of creating the index ixs, in innermost portion (2 + rand(200,1)) creates a 200x1 array of values between 2 and 3. Using cumsum generates the cumulative sum of this array, and then round rounds the values to an integer, which can be used for indexing. For example, the first 10 values is ixs look like this, for a particular run:
>> ixs(1:10)'
ans =
3 5 8 11 13 16 18 20 22 24
Since the number of 1 values will vary each time, I set this up to be oversized. That is, the last few values are [487 489 491 497 500], larger than the actual size required. This is why the values need to be trimmed with applying the index.
A = zeros(1,200);
idx = cumsum(1 + randi(2,80,1)); % This is the main trick
A(idx) = 1;
cumsum(1 + randi(2,80,1)) gets you the indexes for exactly 80 elements in A which need to be switched to 1 spaced by 2 or 3 (randomly)
Related
I would like to enter the same vector of numbers repeatedly to an existing matrix at specific (row) logical indices. This is like an extension of entering just a single number at all logical index positions (at least in my head).
I.e., it is possible to have
mat = zeros(5,3);
rowInd = logical([0 1 0 0 1]); %normally obtained from previous operation
mat(rowInd,1) = 15;
mat =
0 0 0
15 0 0
0 0 0
0 0 0
15 0 0
But I would like to do sth like this
mat(rowInd,:) = [15 6 3]; %rows 2 and 5 should be filled with these numbers
and get an assignment mismatch error.
I want to avoid for loops for the rows or assigning vector elements single file. I have the strong feeling there is an elementary matlab operation that should be able to do this? Thanks!
The problem is that your indexing picks two rows from the matrix and tries to assign a single row to them. You have to replicate the targeted row to fit your indexing:
mat = zeros(5,3);
rowInd = logical([0 1 0 0 1]);
mat(rowInd,:) = repmat([15 6 3],sum(rowInd),1)
This returns:
mat =
0 0 0
15 6 3
0 0 0
0 0 0
15 6 3
I have two matrix with more than 1000 rows, and two columns.
Everytime the first column is '0', the second has a value, and everytime the first column is '1', the second is zero.
Example:
M = [0 23;0 35;1 0;1 0;0 2;1 0]
M =
0 23
0 35
1 0
1 0
0 2
1 0
Let's think about the second column as a non periodic cycle.
What I want is, everytime the first column is 0 (until is one again), having the opportunity to analyse the size and sum of the second column. In the end I want to know which cycle is bigger in size and sum. (in the example matrix, as output, I know the first cycle is the bigger with a sum of 58).
Assuming A as the input two-column array, here's one approach with accumarray -
%// Create ID array for using with accumarray
id = cumsum([1;diff(A(:,1))~=0]);
%// Get summations and counts for all IDs
sums = accumarray(id,A(:,2));
counts = accumarray(id,1);
%// Get offset in case the starting element in first column is not 0
offset = (A(1,1)~=0)+1;
%// Consider only even IDs corresponding to 0 elements cycle
sums = sums(offset:2:end)
counts = counts(offset:2:end)
Sample run -
A =
1 34
1 45
0 23
0 35
1 0
1 0
0 2
0 8
0 6
1 9
sums =
58
16
counts =
2
3
I have [sentence cross words] logical matrix where value = 1 shows presence of a word in that sentence and 0 shows absence like as follows:
0 0 1 1
1 0 1 0
0 0 0 1
1 1 0 0
I have done some processing and selected specific words i.e. 2 & 3
result = 2 3
Now, I want to select only those rows in which value of words 2 & 3 are equal to 1 and return there row number as follows:
row = 1 2 4
This should be done for every word that is in result variable - thanks.
Think you are looking for something like this, assuming A as the input binary array -
result = [2 3]; %// select words by IDs
row = find(any(A(:,result),2))
Sample run -
A =
0 0 1 1
1 0 1 0
0 0 0 1
1 1 0 0
row =
1
2
4
For fun-sake, you can also use matrix-multiplication as an alternative approach -
row = find(A(:,result)*ones(numel(result),1))
First choose the columns that you want to extract and create a matrix that concatenates all of these columns together. Next, use any and operate along the columns in combination with find to obtain the desired locations.
Therefore, given your logical matrix stored in X, do:
ind = [2 3];
matr = X(:,ind);
vals = find(any(matr, 2));
With your above example, we get:
vals =
1
2
4
I would line to find the number of the first consecutive zero elements. For example in [0 0 1 -5 3 0] we have two zero consecutive elements that appear first in the vector.
could you please suggest a way without using for loops?
V=[0 0 1 -5 3 0] ;
k=find(V);
Number_of_first_zeros=k(1)-1;
Or,
Number_of_first_zeros=find(V,1,'first')-1;
To solve #The minion comment (if that was the purpose):
Number_of_first_zeros=find(V(find(~V,1,'first'):end),1,'first')-find(~V,1,'first');
Use a logical array to find the zeros and then look at where the zeros and ones are alternating.
V=[1 2 0 0 0 3 5123];
diff(V==0)
ans =
0 1 0 0 -1 0
Create sample data
V=[1 2 0 0 0 3 5123];
Find the zeros. The result will be a logical array where 1 represents the location of the zeros
D=V==0
D =
0 0 1 1 1 0 0
Take the difference of that array. 1 would then represent the start and -1 would represent the end.
T= diff(D)
ans =
0 1 0 0 -1 0
find(T==1) would give you the start and find(T==-1) would give you the end. The first index+1 of T==1 would be the start of the first set of zeros and the first index of T==-1 would be the end of the first set of zeros.
You could find position the first nonzero element using find.
I=find(A, 1);
The number of leading zeros is then I-1.
My solution is quite complex yet it doesn't use the loops and it does the trick. I am pretty sure, that there is a more direct approach.
Just in case no one else posts a working solution here my idea.
x=[1 2 4 0 20 0 10 1 23 45];
x1=find(x==0);
if numel(x1)>1
x2=[x1(2:end), 0];
x3=x2-x1;
y=find(x3~=1);
y(1)
elseif numel(x1)==1
display(1)
else
display('No zero found')
end
x is the dataset. x1 contains the index of all zero elements. x2 contains all those indices except the first one (because matrix dimensions must agree, one zero is added. x3 is the difference between the index and the previous index of zeros in your dataset. Now I find all those differences which are not 1 (do not correspond to sequences of zeros) and the first index (of this data is the required result. The if case is needed in case you have only one or no zero at all.
I'm assuming your question is the following: for the following vector [0 0 1 -5 3 0], I would like to find the index of the first element of a pair of 0 values. Is this correct? Therefore, the desired output for your vector would be '1'?
To extend the other answers to find any such pairs, not just 0 0 (eg. 0 1, 0 2, 3 4 etc), then this might help.
% define the pattern
ptrn = [ 0 0 ];
difference = ptrn(2) - ptrn(1)
V = [0 0 1 -5 3 0 0 2 3 4 0 0 1 0 0 0]
x = diff(V) == difference
indices = find(x)
indices =
1 6 11 14 15
I want to create a variable that finds a pattern (let's say [1 1]) in different rows of a matrix (A). Of course there aren't an equal number of occurrences of this string in each row.
A = [ 0 0 0 1 1
1 1 1 0 0
0 1 0 1 1
1 1 1 0 0
0 1 0 0 1
1 0 1 1 1
0 1 0 1 0
1 1 1 0 1];
I could do:
for i = 1:n
var(i,:) = strfind(A(i,:),[1 1]);
end
but then both sides of the equation won't be equal.
ERROR: ??? Subscripted assignment dimension mismatch.
I try to preallocate. I create a matrix with what I think would be the maximum number of occurrences of this string in each row of matrix A (let's say 50).
for i = 1:n
var(i, :) = NaN(1,50)
end
That's followed by the previous bit of code and it's no good either.
I've also tried:
for i = 1:n
var(i,1:numel(strfind(A(i,:),[1 1])) = strfind(A(i,:),[1 1])
end
Error: The expression to the left of the equals sign is not a valid
target for an assignment.
How should I go about doing this?
The output I expect is a matrix var(i,:) that gives me the position in the matrix where each of these patterns occur. It works fine for just one row.
For example:
var(1,:) = [1 2 5 8 10 22 48]
var(2,:) = [2 3 4 7 34 45 NaN]
var(3,:) = [4 5 21 32 33 NaN]
Thanks!
In your first try: you tried to build a matrix with different length of rows.
In your second try: you pre-allocated, but then run it over by re-definning var(i,:), while you tried to put there your desired result.
In your third try: unfortunately you just missed one brackets- ) at the end of left expression.
This code suppose to work (what you did at 2nd and 3rd attempts, with pre-allocate and fixed brackets):
var=NaN(1,50);
for i = 1:n
var(i,1:numel(strfind(A(i,:),[1 1]))) = strfind(A(i,:),[1 1])
end