Selecting every other block of elements from MATLAB array - arrays

We all know how to select every other n element using index like A[1:n:end]. Suppose I have a 1000x1 array and I divide (conceptually) it into blocks of 5 elements, and I want to select every other block, i.e., to select A[1], A[2], A[3], A[4], A[5] and A[11], A[12], A[13], A[14], A[15], ..., you got the idea.
Of course I can generate an index array beforehand and use it, but I am wondering if there are more convenient ways.

So in effect you are trying to create a square wave indexing function, how about something like
n = 1:numel(A); %// assuming A is a vector (i.e. 1D)
w = 2^-3;
idx = sin(2*pi*w*n) > 0;
You then tune w to change block width.
Alternatively
w = 3
idx = floor(mod(0:n-1),2*w)/w);

You can reshape the array into a matrix:
A = rand(1000,1);
n = 5;
B = reshape(A,n,[]);
Now each column of B is a group:
B(:,1) == A(1:5)
B(:,2) == A(6:10)
...
From there you can select every other column of B the same way you would for a vector:
B = B(:,1:2:end);

Related

Modifying a numpy array efficiently

I have a numpy array A of size 10 with values ranging from 0-4. I want to create a new 2-D array B from this with its ith column being a vector corresponding to the ith element of A.
For example, the value 1 as the first element of A would correspond to B having a column vector [0,1,0,0,0] as it's first column. A having 4 as its third element would correspond to B having it's 3rd column as [0,0,0,1,0]
I have the following code:
import numpy as np
A = np.random.randint(0,5,10)
B = np.ones((5,10))
iden = np.identity(5, dtype=np.float64)
for i in range(0,10):
a = A[i]
B[:,i:i+1] = iden[:,a:a+1]
print A
print B
The code is doing what it's supposed to be doing but I am sure there are more efficient ways of doing this. Can anyone please suggest some?
That could be solved by initializing an array of zeros and then integer-indexing into it with indices from A and assigning 1s, like so -
M,N = 5,10
A = np.random.randint(0,M,N)
B = np.zeros((M,N))
B[A,np.arange(len(A))] = 1

Select entries from matrices according to indices in another matrix in MATLAB

I have matrices:
a= 0.8147 0.1270 0.6324
0.9058 0.9134 0.0975
b= 0.2785 0.9649 0.9572
0.5469 0.1576 0.4854
0.9575 0.9706 0.8003
c = 0.1419 0.7922
0.4218 0.9595
0.9157 0.6557
and also I have another matrix
I= 1 3 1 1
2 1 3 2
I want to get d matrix such that
d= a(1,3) b(3,1) c(1,1)
a(2,1) b(1,3) c(3,2)
where indices come as two consecutive entries of I matrix.
This is one example I get. However, I get different size matrices for a,b,c,.. and I.
Added: I is m x (n+3) which includes indices, and other (n+2) matrices which have corresponding entries are X,A1,A2,...,An,Y. When n is given, A1,A2,...,An matrices are generated.
Can someone please help me to write Matlab code for this task?
You can do it with varargin. Assuming that your matrices are constructed such that you can form your desired output in the way you want (Updated according to Carmine's answer):
function out = IDcombiner(I, varargin)
out = zeros(size(I, 1), nargin-1);
idx = #(m, I, ii) (sub2ind(size(m), I(:, ii), I(:, ii+1)));
for ii = 1:1:nargin-1
out(:, ii) = varargin{ii}(idx(varargin{ii}, I, ii));
end
Now using this function you can make your selection on a flexible number of inputs:
out = IDcombiner(I, a, b, c)
out =
0.6324 0.9575 0.1419
0.9058 0.9572 0.6557
There is also a one-liner solution, which I do not recommend, since it dramatically decreases the readability of the code and doesn't help you gain much:
IDcombiner = #(I,varargin) ...
cell2mat(arrayfun(#(x) varargin{x}(sub2ind(size(varargin{x}), ...
I(:,x), I(:,x+1))), 1:nargin-1, 'UniformOutput', false));
Normally a matrix is not interpreted as a list of indices, but you can have this if you use sub2ind. To use it you need the size of the matrix you are addressing. Let's make an example starting with a:
a(sub2ind(size(a), I(:,1), I(:,2)))
The code does not change if you first assign the newly generated matrices to a variable name.
will use the column I(:,1) as rows and I(:,2) as columns.
To make the code more readable you can define an anonymous function that does this, let's call it idx:
idx = #(m,I,i)(sub2ind(size(m), I(:,i), I(:,i+1)))
So finally the code will be
d = [a(idx(a,I,1)), b(idx(b,I,2)), c(idx(c,I,3))]
The code does not change if you first assign the newly generated matrices to a variable name.
Other details
Let's make an example with 2 central matrices:
a = rand(3,1) % 3 rows, 1 column
b = rand(3,3) % 3 rows, 3 columns
c = rand(3,3) % another squared matrix
d = rand(3,1) % 3 rows, 1 column
The definition of the anonymous function is the same, you just change the definition of the output vector:
output = [a(idx(a,I,1)), b(idx(b,I,2)), c(idx(c,I,3)), d(idx(d,I,3))]
Keep in mind that following that pattern you always need a I matrix with (n_matrices + 1) columns.
Generalization
Let's generalize this code for a number n of central matrices of size rxr and for "side matrices" of size rxc. I will use some values of those parameters for this example, but you can use what you want.
Let me generate an example to use:
r = 3;
c = 4;
n = 3;
a = rand(r,c); % 2D array
b = rand(r,r,n); % 3D array, along z = 1:n you have 2D matrices of size rxr
c = rand(r,c);
I = [1 3 1 2 1 3; 2 1 3 1 1 1];
The code I wrote can easily be extended using cat to append matrices (note the 2 in the function tells MATLAB to append on the direction of the columns) and a for cycle:
idx = #(m,I,i)(sub2ind(size(m), I(:,i), I(:,i+1)))
d = a(idx(a,I,1));
for i = 1:n
temp = b(:,:,i);
d = cat(2,d,temp(idx(tmp,I,i+1)));
end
d = cat(2,d,c(idx(c,I,n+1)));
If you really don't want to address anything "by hand", you can use cell arrays to put all the matrices together and then cyclically apply the anonymous function to each matrix in the cell array.

Nested for-loops and their formats

I am using Python 2.7. From previous posts, I am learning Python and I have moved from arrays and now I am working on loops. I am also trying to work with operations using arrays.
A1 = np.random.random_integers(35, size=(10.,5.))
A = np.array(A1)
B1 = np.random.random_integers(68, size=(10.,5.))
B = np.array(B1)
D = np.zeros(10,5) #array has 10 rows and 5 columns filled with zeros to give me the array size I want
for j in range (1,5):
for k in range (1,5):
D[j,k] = 0
for el in range (1,10):
D[j,k] = D[j,k] + A[j] * B[k]
The error I am getting is : setting an array element with a sequence
Is my formatting incorrect?
Because A, B and D are all 2D arrays, then D[j,k]
is a single element, while A[j] (the same as A[j,:]) is a 1D array which, in this case, has 5 elements. Similar for B[k] = B[k,:], i.e. also a 5 element array.
A[j] * B[k] is therefore also five element array, which can not be stored in the place of a single element, and you therefore get the error: setting an array element with a sequence.
If you want to select single elements from A and B, then the last line should be
D[j,k] = D[j,k] + A[j,k] * B[j,k]
Some further comments on your code:
# A is already a numpy array, so 'A = np.array(A1)' is redundant and can be omitted
A = np.random.random_integers(35, size=(10.,5.))
# Same as above
B = np.random.random_integers(68, size=(10.,5.))
D = np.zeros([10,5]) # This is the correct syntax for creating a 2D array with the np.zeros() function
for j in range(1,5):
for k in range(1,5):
# D[j,k] = 0 You have already defined D to be zero for all elements with the np.zeros function, so there is no need to do it again
for el in range(1,75):
D[j,k] = D[j,k] + A[j] * B[k]
EDIT:
Well, I do not have enough reputation to comment on your post #Caroline.py, so I will do it here instead:
First of all, remember that python uses zero indexing, so 'range(1,5)' gives you '[1,2,3,4]', which means that you would not reach the first index, i.e. index 0. Thus you would probably want to use 'range(0,5)', which is the same as just 'range(5)', instead.
I can see that you changed the el range from 75 to 10. If you don't use el to anything, it just means that you add perform the last line 10 times.
I don't know what you want to do, but if you want to store the multiple of A and B in D, then this should be right:
for j in range(10):
for k in range(5):
D[j,k] = A[j,k] * B[j,k]
or just
D = A * B

How to convert a character matrix into cell array?

I have 64 characters in a 4*4 matrix.I need to convert it into a cell array such that cell has 4 characters.For eg
Consider A=[TCTGCTCTCGGTTATATACACTGCCCAGAACACGTCAACAAGGCCAGTGTATCCTTCTTTGTGT]
i need to get a cell array as below
B={[TCTG][CTCT][CGGT][TATA]
[TACA][CTGC][CCAG][AACA]
[CGTC][AACA][AGGC][CAGT]
[GTAT][CCTT][CTTT][GTGT]}
i tried using the mat2cell function but im not able to understand it.please help.
Using a for-loop:
clc
clear
A = 'TCTGCTCTCGGTTATATACACTGCCCAGAACACGTCAACAAGGCCAGTGTATCCTTCTTTGTGT';
B = cell(4,4);
currentIdx = 0; % Use index to increment by steps of 4 when going through A
for k = 1:16
B{k} = A(currentIdx+1:currentIdx+4);
currentIdx = currentIdx+4;
end
B = B'
B =
'TCTG' 'CTCT' 'CGGT' 'TATA'
'TACA' 'CTGC' 'CCAG' 'AACA'
'CGTC' 'AACA' 'AGGC' 'CAGT'
'GTAT' 'CCTT' 'CTTT' 'GTGT'
You are starting with a 1xN matrix and want to convert it to a 1xN/4 cell array of 1x4 matrices. Your command should then be:
N = length(A);
M = 4;
B = mat2cell(A,1,ones(1,N/M)*M);
The first dimension is the 1, the second dimension is a string of 4's the size of the output cell array. The result:
B =
Columns 1 through 12
'TCTG' 'CTCT' 'CGGT' 'TATA' 'TACA' 'CTGC' 'CCAG' 'AACA' 'CGTC' 'AACA' 'AGGC' 'CAGT'
Columns 13 through 16
'GTAT' 'CCTT' 'CTTT' 'GTGT'
You can use method vec2mat that breaks your input vector to matrix
M = vec2mat(A, numberOfColumns)
(In your case numberOfColumns would be 16) and then use mat2cell. In your case, it would be:
C = mat2cell(M, [1,1,1,1], [4,4,4,4])
It means that all cels will have one row and 4 columns).
Effect of function c = mat2cell(x, [10, 20, 30], [25, 25]) would be:
The image shows why you have to convert vector to matrix. (example from matlab documentation)
You can also (ab)use the very versatile accumarray for this task:
A = 'TCTGCTCTCGGTTATATACACTGCCCAGAACACGTCAACAAGGCCAGTGTATCCTTCTTTGTGT';
n = 4;
B = accumarray(ceil(1/n:1/n:numel(A)/n).', A(:), [], #(x) {x.'}).'

Accessing elements in matlab, get pixels of color image (array) from indices stored in another array

A and B are mask indices (row and column respectively) and C is an image and I want to note the color values stored in C for which the indices are stored in A and B. If A and B would be something like [1, 2, 3] and [20, 30, 40] so I would like to find C(1, 20, :), C(2, 30, :) and C(3, 40, :).
If I do D = C(A, B, :), I get an array of size 3x3x3 in this case, however I want an array of size 3x1x3. I know I am messing with the indexing, is there a simple way to do this without writing a loop?
Simply stating, is there a way to do the following without a loop:
for i = 1:10
D(i, :) = C(A(i), B(i), :)
end
You need to convert subindices to linear indices. You can use sub2ind for that:
r = C(sub2ind([size(C,1) size(C,2) 1],A,B,1*ones(1,length(A))));
g = C(sub2ind([size(C,1) size(C,2) 2],A,B,2*ones(1,length(A))));
b = C(sub2ind([size(C,1) size(C,2) 3],A,B,3*ones(1,length(A))));
The n x 1 x 3 result you want would be simply cat(3, r.',g.',b.').
Why not something like
C = C(A,B(i),:);
You could use a for statement to get the value of i or set it some other way.
It sounds like everything is working as it should. In your example you've indexed 9 elements of C using A and B. Then D is a 3x3x3 array with the dimensions corresponding to [row x col x color_mask(RGB)]. Why would the second dimension be reduced to 1 unless B only contained one value (signifying you only want to take elements from one column)? Of course A and B must not contain values higher than the number of rows and columns in C.
A = [1 2 3];
B = [20];
D = C(A,B,:);
size(D)
>> 3 1 3
EDIT: Ok, I see what you mean now. You want to specify N number of points using A(Nx1) and B(Nx1). Not NxN number of points which is what you are currently getting.

Resources