Structure array assigning - arrays

I have a 1x5 structure array called Game with two fields i.e.
Game(5) = struct(Points, Scorers);
Now, I also have a cell-array (5x2 cell array) (imported from xlsread - so its all in cell-array form).
pts = [1 2;3 4;5 6;7 8;9 10];
How should I go about assigning each row of pts, to each of the 5 structures in Game, respectively?
For example: Game(3).Points should be row 3 of pts (which is [5 6]).
Game(2).Points should be [3 4]. Game(1).Points will be [1 2].

If your worksheet is organized such that rows correspond to observations and columns correspond to variables - e.g. points (numeric) and scorers (string) - you can import the data into Matlab using:
[pts, scr] = xlsread(file);
Then you can simply read the matrix pts and cell array scr into each field of a structure array as:
Game = struct('Points', num2cell(pts,2), 'Scorers', scr);
This takes advantage of struct()'s built-in ability to match output dimensions to its inputs, avoiding the use of a for loop to iteratively assign imported values to the fields.

Related

How to get the mean of first values in arrays in matrix in Matlab

If I have a square matrix of arrays such as:
[1,2], [2,3]
[5,9], [1,4]
And I want to get the mean of the first values in the arrays of each row such:
1.5
3
Is this possible in Matlab?
I've used the mean(matrix, 2) command to do this with a matrix of single values, but I'm not sure how to extend this to deal with the arrays.
Get the first elements in all arrays of matrix, then call mean function
mean(matrix(:,:,1))
maybe you need to reshape before call mean
a = matrix(:,:,1);
mean(a(:))
You can apply mean function inside mean function to get the total mean value of the 2D array at index 1. You can do similary with array at index 2. Consider the following snapshot.
After staring at your problem for a long time, it looks like your input is a 3D matrix where each row of your formatting corresponds to a 2D matrix slice. Therefore, in proper MATLAB syntax, your matrix is actually:
M = cat(3, [1,2; 2,3], [5,9; 1,4]);
We thus get:
>> M = cat(3, [1,2; 2,3], [5,9; 1,4])
M(:,:,1) =
1 2
2 3
M(:,:,2) =
5 9
1 4
The first slice is the matrix [1,2; 2,3] and the second slice is [5,9; 1,4]. From what it looks like, you would like the mean of only the first column of every slice and return this as a single vector of values. Therefore, use the mean function and index into the first column for all rows and slices. This will unfortunately become a singleton 3D array so you'll need to squeeze out the singleton dimensions.
Without further ado:
O = squeeze(mean(M(:,1,:)))
We thus get:
>> O = squeeze(mean(M(:,1,:)))
O =
1.5000
3.0000

Drop Julia array dimensions of length 1

Say if I have a 5D Array with size 1024x1024x1x1x100. How can I make a new array that is 1024x1024x100?
The following works if you know which dimensions you want to keep ahead of time:
arr = arr[:, :, 1, 1, :]
But I don't know which dimensions are what size ahead of time and I would like to only keep dimensions given a boolean mask; something like this...
arr2 = arr[(size(arr) .> 1)]
The squeeze function was defined specifically for the purpose of removing dimensions of length 1. From the manual:
Base.squeeze — Function.
squeeze(A, dims)
Remove the dimensions
specified by dims from array A. Elements of dims must be unique and
within the range 1:ndims(A). size(A,i) must equal 1 for all i in dims.
To "squeeze" all the dimensions of size 1 (when they are unknown in advance), we need to find them and make them into a tuple. This is accomplished by ((size(arr).==1)...). So the result is:
squeeze(a,(find(size(a).==1)...))

Fill a vector in Julia with a repeated list

I would like to create a column vector X by repeating a smaller column vector G of length h a number n of times. The final vector X will be of length h*n. For example
G = [1;2;3;4] #column vector of length h
X = [1;2;3;4;1;2;3;4;1;2;3;4] #ie X = [G;G;G;G] column vector of
length h*n
I can do this in a loop but is there an equivalent to the 'fill' function that can be used without the dimensions going wrong. When I try to use fill for this case, instead of getting one column vector of length h*n I get a column vector of length n where each row is another vector of length h. For example I get the following:
X = [[1,2,3,4];[1,2,3,4];[1,2,3,4];[1,2,3,4]]
This doesn't make sense to me as I know that the ; symbol is used to show elements in a row and the space is used to show elements in a column. Why is there the , symbol used here and what does it even mean? I can access the first row of the final output X by X[1] and then any element of this by X[1][1] for example.
Either I would like to use some 'fill' equivalent or some sort of 'flatten' function if it exists, to flatten all the elements of the X into one column vector with each entry being a single number.
I have also tried the reshape function on the output but I can't get this to work either.
Thanks Dan Getz for the answer:
repeat([1, 2, 3, 4], outer = 4)
Type ?repeat at the REPL to learn about this useful function.
In older versions of Julia, repmat was an alternative, but it has now been deprecated and absorbed into repeat
As #DanGetz has pointed out in a comment, repeat is the function you want. From the docs:
repeat(A, inner = Int[], outer = Int[])
Construct an array by repeating the entries of A. The i-th element of inner specifies the number of times that the individual entries of the i-th dimension of A should be repeated. The i-th element of outer specifies the number of times that a slice along the i-th dimension of A should be repeated.
So an example that does what you want is:
X = repeat(G; outer=[k])
where G is the array to be repeated, and k is the number of times to repeat it.
I will also attempt to answer your confusion about the result of fill. Julia (like most languages) makes a distinction between vectors containing numbers and numbers themselves. We know that fill(5, 5) produces [5, 5, 5, 5, 5], which is a one-dimensional array (a vector) where each element is 5.
Note that fill([5], 5), however, produces a one-dimensional array (a vector) where each element is [5], itself a vector. This prints as
5-element Array{Array{Int64,1},1}:
[5]
[5]
[5]
[5]
[5]
and we see from the type that this is indeed a vector of vectors. That of course is not the same thing as the concatenation of vectors. Note that [[5]; [5]; [5]; [5]; [5]] is syntax for concatenation, and will return [5, 5, 5, 5, 5] as you might expect. But although ; syntax (vcat) does concatenation, fill does not do concatenation.
Mathematically (under certain definitions), we may imagine R^(kn) to be distinct (though isomorphic to) from (R^k)^n, for instance, where R^k is the set of k-tuples of real numbers. fill constructs an object of the latter, whereas repeat constructs an object of the former.
As long as you are working with 1-dimensional arrays (Vectors)...
X=repmat(G,4) should do it.
--
On another note, Julia makes no distinction between row and column vector, they are both one-dimensional arrays.
[1,2,3]==[1;2;3] returns true as they are both 3-element Array{Int64,1} or vectors (Array{Int,1} == Vector{Int} returns true)
This is one of the differences between Matlab and Julia...
If, for some specific reason you want to do it, you can create 2-dimensional Arrays (or Matrices) with one of the dimensions equal to 1.
For example:
C = [1 2 3 4] will create a 1x4 Array{Int64,2} the 2 there indicates the dimensions of the Array.
D = [1 2 3 4]' will create a 4x1 Array{Int64,2}.
In this case, C == D returns false of course. But neither is a Vector for Julia, they are both Matrices (Array{Int,2} == Matrix{Int} returns true).

How to permute the arrays within a cell array without using loops

I have a two arrays within a <1x2 cell>. I want to permute those arrays. Of course, I could use a loop to permute each one, but is there any way to do that task at once, without using loops?
Example:
>> whos('M')
Name Size Bytes Class Attributes
M 1x2 9624 cell
>> permute(M,p_matrix)
This does not permute the contents of the two arrays within M.
I could use something like:
>> for k=1:size(M,2), M{k} = permute(M{k},p_matrix); end
but I'd prefer not to use loops.
Thanks.
This seems to work -
num_cells = numel(M) %// Number of cells in input cell array
size_cell = size(M{1}) %// Get sizes
%// Get size of the numeric array that will hold all of the data from the
%// input cell array with the second dimension representing the index of
%// each cell from the input cell array
size_num_arr = [size_cell(1) num_cells size_cell(2:end)]
%// Dimensions array for permuting with the numeric array holding all data
perm_dim = [1 3:numel(size_cell)+1 2]
%// Store data from input M into a vertically concatenated numeric array
num_array = vertcat(M{:})
%// Reshape and permute the numeric array such that the index to be used
%// for indexing data from different cells ends up as the final dimension
num_array = permute(reshape(num_array,size_num_arr),perm_dim)
num_array = permute(num_array,[p_matrix numel(size_cell)+1])
%// Save the numeric array as a cell array with each block from
%// thus obtained numeric array from its first to the second last dimension
%// forming each cell
size_num_arr2 = size(num_array)
size_num_arr2c = num2cell(size_num_arr2(1:end-1))
M = squeeze(mat2cell(num_array,size_num_arr2c{:},ones(1,num_cells)))
Some quick tests show that mat2cell would prove to be the bottleneck, so if you don't mind indexing into the intermediate numeric array variable num_array and use it's last dimension for an equivalent indexing into M, then this approach could be useful.
Now, another approach if you would like to preserve the cell format would be with arrayfun, assuming each cell of M to be a 4D numeric array -
M = arrayfun(#(x) num_array(:,:,:,:,x),1:N,'Uniform',0)
This seems to perform much better than with mat2cell in terms of performance.
Please note that arrayfun isn't a vectorized solution as most certainly it uses loops behind-the-scenes and seems like mat2cell is using for loops inside its source code, so please do keep all these issues in mind.

finding values located in one column in a multidimensional array

I'm trying to find values in a multidimensional array which are only in one column. I can find the correct values when searching the entire multidimensional array. But if I try and limit the find in the multidimensional array to say just the second column the values are not the expected ones.
example of code and correct output:
A = [2 4 6; 8 10 12]
A(:,:,2) = [5 7 9; 11 13 15]
A(:,:,3) = [55 4 55; 167 167 154]
[row,col,page]=ind2sub(size(A), find(A(:,1,:)==4))
row =1,1
col =2,2
page =1,3
But If I try and limit the find to just the second column using these commands
[row,col,page]=ind2sub(size(A), find(A(:,2,:)==4))
row =1,1
col =1,3
page =1,1
I get values that are different from the expected ones. I'm trying to limit the multidimensional find to search all pages, all rows, and one specific column. The output should be the same as the first example. How can I fix this?
With [m,n,o]=size(A), you are using A(:,2,:)==4 which is a matrix n*1*o. ind2sub expects a n*m*o matrix. Typical approach is using a mask:
mask=false(size(A));
mask(:,2,:)=true;
[i,j,k]=ind2sub(size(A), find((A(:,:,:)==4)&mask))
The mask selects the entries you are interested in.
Daniel's answer works by defining a mask and then searching throughout the whole array with that mask applied. The following limits the search to the desired column, and thus may be faster for large arrays:
col = 2; %// desired column
[row, page] = ind2sub([size(A,1) size(A,3)], find(A(:,col,:)==4));
If you need col as a vector the same size as row and page, you can of course achieve it with col = repmat(col,size(row)).

Resources