I have a tensor stored in a file (each line of file is a matrix). In Matlab, I would like to read each line and then create a tensor of size
number of lines * size(matrix at each line)
I am just wondering how to create a tensor from n matrix of same size?
You can use cat instruction, for creating a tensor.
See http://www.mathworks.com/help/matlab/ref/cat.html
Example:
Suppose you have 3 matrices: R, G, and B, size 100x100 each.
Use: RGB = cat(3, R, G, B);
Now RGB is 100x100x3 tensor.
You can also use the following example:
%Initialize tensor with dimensions 3x4x5
T = zeros(3, 4, 5);
%Fill T with random 3x4 "plain" matrices:
for i = size(T, 5);
A = rand(3, 4);
T(:, :, i) = A;
end
Reading lines, converting to matrices using reshape, and place matrices in a tensor:
Suppose you have a text file were each line is a matrix.
Suppose you know matrix size, and number of matrices, and you want to create a tensor.
I created the following example file called rows.txt.
1 1 1 1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2 2 2 2
3 3 3 3 3 3 3 3 3 3 3 3
4 4 4 4 4 4 4 4 4 4 4 4
5 5 5 5 5 5 5 5 5 5 5 5
The following code, initialize a 3x4x5 tensor, read a line, convert it to matrix, and insert to the tensor:
%Initialize tensor with dimensions 3x4x5
T = zeros(3, 4, 5);
f = fopen('rows.txt', 'r');
for i = 1:5
R = fscanf(f, '%f\n', [1, 3*4]); %Read row from file into row vector R.
A = reshape(R, [3, 4]); %Reshape R to 3x4 matrix.
T(:, :, i) = A;
end
fclose(f);
Result:
T(:,:,1) =
1 1 1 1
1 1 1 1
1 1 1 1
T(:,:,2) =
2 2 2 2
2 2 2 2
2 2 2 2
T(:,:,3) =
3 3 3 3
3 3 3 3
3 3 3 3
T(:,:,4) =
4 4 4 4
4 4 4 4
4 4 4 4
T(:,:,5) =
5 5 5 5
5 5 5 5
5 5 5 5
Another alternative:
Read entire text file into a vector, and use reshape to convert it to a tensor:
f = fopen('rows.txt', 'r');
%Read entire file into vector A.
A = fscanf(f, '%f');
%Reshape vector A into 3x4x5 tensor.
T = reshape(A, [3, 4, 5]);
fclose(f);
Related
I have a series of numbers:
test = [1 1 1 2 2 2 3 3 3 4 4 4 5 5 5]
which I want to randomely fill into a 3x5 matrix without having the same number in the same row.
How can I do this in matlab? Potentially I could randomize the test vector and fill it into the 5x3 matrix but I don't know how to do this without getting the same number in the same row.
If you want to fill a 3-by-5 matrix with all of the values in test, making sure each row has no repeated values, you can do this very succinctly by using toeplitz to first generate an index matrix, then randomly permute the dimensions with randperm:
index = toeplitz(1:3, [3 5:-1:2]);
index = index(randperm(3), randperm(5));
And a sample index:
index =
1 5 4 2 3
4 3 2 5 1
5 4 3 1 2
If your values in test are the numbers 1 through 5, this should be all you need to do. If test could be any vector with with 5 different numbers, three of each, then you can get the unique values of your test vector and index them with index. This solution will generalize to any test vector:
test = [3 3 3 7 7 7 5 5 5 9 9 9 4 4 4]; % Sample data
uniqueValues = unique(test); % Get the unique values [3 4 5 7 9]
M = uniqueValues(index); % Use index as generated above
And the result will be guaranteed to be a reordered version of what's in test:
M =
3 9 7 4 5
7 5 4 9 3
9 7 5 3 4
You can take the unique matrix of test and pick any three elements out of it and fill in the required 5X3 matrix.
test = [1 1 1 2 2 2 3 3 3 4 4 4 5 5 5] ;
test_unique = unique(test) ;
A = zeros(5,3) ;
for i = 1:size(A,1)
A(i,:) = randsample(test_unique,3) ;
end
randsample needs a statistics toolbox, if you doesn't have it, you may use randperm as shown below.
test = [1 1 1 2 2 2 3 3 3 4 4 4 5 5 5] ;
test_unique = unique(test) ;
A = zeros(5,3) ;
for i = 1:size(A,1)
A(i,:) = test_unique(randperm(length(test_unique),3)) ;
end
If you want 3X5 matrix:
test = [1 1 1 2 2 2 3 3 3 4 4 4 5 5 5] ;
test_unique = unique(test) ;
A = zeros(3,5) ;
for i = 1:size(A,1)
A(i,:) = randsample(test_unique,5) ;
end
Here is a brute-force way of doing it
% data
test = [1 1 1 2 2 2 3 3 3 4 4 4 5 5 5];
% randomly permute the indices
indices = randperm(numel(test));
% create a random matrix
matrix = reshape(test(indices), 5, 3);
% while number of unique elements in any of the rows is other than 3
while any(arrayfun(#(x) numel(unique(matrix(x,:))), (1:size(matrix,1)).')~=3)
% keep generating random matrices
indices = randperm(numel(test));
matrix = reshape(test(indices), 5, 3);
end;
% here is the result
result=matrix;
EDIT : If you want 3x5 like you mentioned in your comment, it is a lot easier. Just one line below.
[~, result] = sort(rand(3,5),2);
The Mean Square Error(MSE), is a method used to define the difference in between two blocks, and can be calculated as follow:
a and b two blocks equal size
MSE = sqrt(sum(sum((a-b).^2)))/size(a or b)
If the MSE is less than a given threshold, than the two blocks are not diffrent.
Given two matrix A and B, the purpose is to divide the two matrix to blocks of a given size, then extract the first block from A and let it be a, then search for a block b from B where the Mean Square Error between a and b is less then a given threshold, then return the position of the block b from the matrix B. and so on. and here is an example:
Given two matrix A and B where:
A= [1 1 4 4 2 2
1 1 4 4 2 2
2 2 9 9 5 5
2 2 9 9 5 5
3 3 4 4 9 9
3 3 4 4 9 9];
B = [ 2 2 4 4 9 9
2 2 4 4 9 9];
the threshold is 2
The first block a obtained from the matrix A is:
1 1
1 1
The block b obtained from the matrix B that MSR between a and b is less than the threshold is:
2 2
2 2
Therefore we return the position of the block b in the matrix B which is 1
The second block a obtained from the matrix A is:
4 4
4 4
The block b obtained from the matrix B where MSR between a and b is less than threshold is:
4 4
4 4
Therefore we return the position of the block b in the matrix B which is 2. and so on.
The final result should be as follow
RES= [1 2 1
1 3 2
1 2 3];
Is there a faster way?
Here's a vectorized approach with bsxfun.
First define data:
A = [1 1 4 4 2 2
1 1 4 4 2 2
2 2 9 9 5 5
2 2 9 9 5 5
3 3 4 4 9 9
3 3 4 4 9 9]; %// data: A
B = [2 2 4 4 9 9
2 2 4 4 9 9]; %// data: B
m = 2; %// number of rows per block
n = 2; %// number of cols per block
Then apply the following steps:
Reshape matrices so that each block is a row (inspired by this great answer).
Compute the MSE for all pairs of blocks.
Find the argmin of the MSE with respect to blocks of B (for each block of A). Note that if there are several minimizing blocks in B this finds the first.
Reshape result into a matrix.
Code:
A2 = reshape(permute(reshape(A, size(A, 1), n, []), [2 1 3]), n*m, []); %// step 1
B2 = reshape(permute(reshape(B, size(B, 1), n, []), [2 1 3]), n*m, []);
mse = squeeze(sum(bsxfun(#minus, A2, permute(B2,[1 3 2])).^2, 1)); %// step 2
[~, result] = min(mse, [], 2); %// step 3
result = reshape(result, size(A,1)/m, size(A,2)/n); %// step 4
For the sake of argument, let's say I have this 3 x 3 x 2 matrix:
A = [5 7 8; 0 1 9; 4 3 6];
A(:,:,2) = [1 0 4; 3 5 6; 9 8 7];
And I'd like to pick out the first matrix (dimension: 3 x 3 x 1), how do I do it?
Short answer, already in the comments, is:
A(:,:,1)
Longer answer:
You can pick out any (hyper)-rectangular subset of a matric by simply specifying the elements you want per dimension, weather there are 1, 2, 3, 4 or more dimensions in the array. In short:
Each dimension is specified, in order. Dimension 1 is specifies row, dimension 2 specifies column, dimensions 3 and up are not usually visualized, so just represnt 3 and up
For each dimension you can specify one of the following: a) A single index number, b) A vector of index numbers, or c) a logical vector the same length as the dimension you are selecting from d) :, which represents all elements in this dimension.
Per dimension specifiers are ANDed together, resulting in a (hyper)-rectangular array.
For example, using your A array:
A = [5 7 8; 0 1 9; 4 3 6];
A(:,:,2) = [1 0 4; 3 5 6; 9 8 7];
To subset the first matrix you need: all of dimension 1 ":", all of dimension 2 ":", and the first element of dimension 3 "1". Therefore:
A(:,:,1) %Returns 5 7 8
% 0 1 9
% 4 3 6
To get the first and third columns of the second page, use:
A(:, [1 3], 2) %Returns 1 4
% 3 6
% 9 7
To get all rows which end in 9 from the first matrax, you can use:
mask = A(:,3,1)==9; %Returns logical [0; 1; 0];
A(mask, :, 1); %Returns [0 1 9;
In Matlab, I'm trying to transform a matrix A to another matrix B such that B's columns are made up of square submatrices of A. For example, if A is:
A = [1 1 2 2
1 1 2 2
3 3 4 4
3 3 4 4];
I'd like B to be:
B = [1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4]
A could be, say 16-by-16, and constructing B from 4-by-4 squares would result in B being 4-by-64.
Is there an efficient way to do this using reshape in combination with some other commands? Or some other approach? I am currently iterating in a loop, which is very slow with a large number of large source matrices.
Assume your matrix is a bit more general, and made of 3x2 blocks:
A = [1 1 2 2
1 1 2 2
1 1 2 2
3 3 4 4
3 3 4 4
3 3 4 4
5 5 6 6
5 5 6 6
5 5 6 6];
b = [3 2];
szA = size(A);
Transpose, reshape, permute, reshape.
nb = prod(szA./b); % Number of blocks
nelb = prod(b); % Number of elements per block
out1 = reshape(permute(reshape(A',szA(2),b(1),szA(1)/b(1)),[2,1,3]),nelb,nb)
Alternatively, slower and memory intensive but more readable:
d1 = repmat(b(1),1,szA(1)/b(1));
d2 = repmat(b(2),1,szA(2)/b(2));
out = reshape(mat2cell(A,d1,d2)',1,nelb);
out = reshape([out{:}],nelb,nb)
Now, if the blocks are square, simply set b = [2,2] or b = [3,3], etc..., or simplify the general formulation removing indexing of b and prod.
I need some help in converting a 2X2 matrix to a 4X4 matrix in the following manner:
A = [2 6;
8 4]
should become:
B = [2 2 6 6;
2 2 6 6;
8 8 4 4;
8 8 4 4]
How would I do this?
In newer versions of MATLAB (R2015a and later) the easiest way to do this is using the repelem function:
B = repelem(A, 2, 2);
For older versions, a short alternative to the other (largely) indexing-based solutions is to use the functions kron and ones:
>> A = [2 6; 8 4];
>> B = kron(A, ones(2))
B =
2 2 6 6
2 2 6 6
8 8 4 4
8 8 4 4
Can be done even easier than Jason's solution:
B = A([1 1 2 2], :); % replicate the rows
B = B(:, [1 1 2 2]); % replicate the columns
Here's one more solution:
A = [2 6; 8 4];
B = A( ceil( 0.5:0.5:end ), ceil( 0.5:0.5:end ) );
which uses indexing to do everything and doesn't rely on the size or shape of A.
This works:
A = [2 6; 8 4];
[X,Y] = meshgrid(1:2);
[XI,YI] = meshgrid(0.5:0.5:2);
B = interp2(X,Y,A,XI,YI,'nearest');
This is just two-dimensional nearest-neighbor interpolation of A(x,y) from x,y ∈ {1,2} to x,y ∈ {0.5, 1, 1.5, 2}.
Edit: Springboarding off of Jason S and Martijn's solutions, I think this is probably the shortest and clearest solution:
A = [2 6; 8 4];
B = A([1 1 2 2], [1 1 2 2]);
A = [2 6; 8 4];
% arbitrary 2x2 input matrix
B = repmat(A,2,2);
% replicates rows & columns but not in the way you want
B = B([1 3 2 4], :);
% swaps rows 2 and 3
B = B(:, [1 3 2 4]);
% swaps columns 2 and 3, and you're done!
Here's a method based on simple indexing that works for an arbitrary matrix. We want each element to be expanded to an MxN submatrix:
A(repmat(1:end,[M 1]),repmat(1:end,[N 1]))
Example:
>> A=reshape(1:6,[2,3])
A =
1 3 5
2 4 6
>> A(repmat(1:end,[3 1]),repmat(1:end,[4 1]))
ans =
1 1 1 1 3 3 3 3 5 5 5 5
1 1 1 1 3 3 3 3 5 5 5 5
1 1 1 1 3 3 3 3 5 5 5 5
2 2 2 2 4 4 4 4 6 6 6 6
2 2 2 2 4 4 4 4 6 6 6 6
2 2 2 2 4 4 4 4 6 6 6 6
To see how the method works, let's take a closer look at the indexing. We start with a simple row vector of consecutive numbers
>> m=3; 1:m
ans =
1 2 3
Next, we extend it to a matrix, by repeating it M times in the first dimension
>> M=4; I=repmat(1:m,[M 1])
I =
1 2 3
1 2 3
1 2 3
1 2 3
If we use a matrix to index an array, then the matrix elements are used consecutively in the standard Matlab order:
>> I(:)
ans =
1
1
1
1
2
2
2
2
3
3
3
3
Finally, when indexing an array, the 'end' keyword evaluates to the size of the array in the corresponding dimension. As a result, in the example the following are equivalent:
>> A(repmat(1:end,[3 1]),repmat(1:end,[4 1]))
>> A(repmat(1:2,[3 1]),repmat(1:3,[4 1]))
>> A(repmat([1 2],[3 1]),repmat([1 2 3],[4 1]))
>> A([1 2;1 2;1 2],[1 2 3;1 2 3;1 2 3;1 2 3])
>> A([1 1 1 2 2 2],[1 1 1 1 2 2 2 2 3 3 3 3])
There is a Reshape() function that allows you to do this...
For example:
reshape(array, [64, 16])
And you can find a great video tutorial here
Cheers