finding values located in one column in a multidimensional array - arrays

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)).

Related

Converting Rows into Columns in a cell array in MATLAB

I have a 99x1 cell array and I would like to convert it into a 33x3 cell array for example.
I would like the first 3 rows of the 99x1 cell array to make up the first row in the 33x3 cell array and then the 3rd through 6th row in the 99x1 cell array to make up the second row in the 33x3 cell array.
I also need the data when being reshaped to go over column by column before it goes down. For example I would need:
1
2
3
4
to become
1, 2; 3, 4
not
1, 3; 2, 4
Help with this would be greatly appreciated
You can simply use the reshape-function. Since reshape(yourcell,[],3) would first fill the first column and then the second and so on instead of row-wise, you will need to combine it with the transpose operator .':
newcell=reshape(yourcell,3,[]).'
This way, you will first create a 3x33 cell using the reshape and then transform it into the desired 33x3 cell. The [] tells reshape to create as many columns as needed.

Mapping a 2D array into 1D array with variable column width

I know mapping 2D array into 1D array has been asked many times, but I did not find a solution that would fit a where the column count varies.
So I want get a 1-dimensional index from this 2-dimensional array
Col> _0____1____2__
Row 0 |_0__|_1__|_2__|
V 1 |_3__|_4__|
2 |_5__|_6__|_7__|
3 |_8__|_9__|
4 |_10_|_11_|_12_|
5 |_13_|_14_|
The normal formula index = row * columns + column does not work, since after the 2nd row the index is out of place.
What is the correct formula here?
EDIT:
The specific issue is that I have a list of items in with the layout like in the grid, but a one dimensional array for the data. So while looping through the elements in the UI, I need to get the correct data, but can only get the row and column for that element. I need to find a way to turn a row/column value into an index for the data-array
Bad picture trying to explain it
A truly optimal answer (or even a provably correct one) will depend on the language you are using and how it lays out memory for such arrays.
However, taking your question simply at face value, you have to know what the actual length of each row is in order to calculate a 1D index.
So either the row length follows some pattern that can be inferred from the data, or you have (or can write) a rlen = rowLength( 2dTable, RowNumber) function.
Then, depending on how big the tables are and how fast you need to run, you can calculate a 1D index from the 2d table by adding all the previous row lengths until the current row length is less than the 2d column index.
or build a 1d table of the row lengths (or commulative rowlengths) so you can scan it and so only call your rowlength function for each row only once.
With a better description of your problem, you might get a better answer...
For your example which alternates between 3 and 2 columns you can construct a formula:
index = (row / 2) * (3 + 2) + (row % 2 ? 3 : 0) + column
(C-like syntax, assuming integer division)
In general though, the one and only way to implement what you're doing here, jagged arrays, is to make an array of arrays, a.k.a. an Iliffe vector. That means, use the row number as index into an array of pointers which point to the individual row arrays containing the actual data.
You can have an additional 1D array having the length of the columns say "length". Then your formula is index=sum {length(i)}+column. i runs from 0 to row.

Adding multiple rows in Array

I have an array A size of 16X16 and I want to add first 3 rows out of 16 in A. What is the most efficient solution in MATLAB?
I tried this code but this is not efficient because I want to extend it for large arrays:
filename = 'n1.txt';
B = importdata(filename);
i = 1;
D = B(i,:)+ B(i+1,:)+ B(i+2,:);
For example, if I want to extend this for an array of size 256x256 and I want to extract 100 rows and add them, how I will do this?
A(1:3,:);%// first three rows.
This uses the standard indices of matrix notation. Check Luis's answer I linked for the full explanation on indices in all forms. For summing things:
B = A(1:100,:);%// first 100 rows
C = sum(B,1);%// sum per column
D = sum(B,2);%// sum per row
E = sum(B(:));%// sum all elements, rows and columns, to a single scalar

Is there a better/faster way of randomly shuffling a matrix in MATLAB?

In MATLAB, I am using the shake.m function (http://www.mathworks.com/matlabcentral/fileexchange/10067-shake) to randomly shuffle each column. For example:
a = [1 2 3; 4 5 6; 7 8 9]
a =
1 2 3
4 5 6
7 8 9
b = shake(a)
b =
7 8 6
1 5 9
4 2 3
This function does exactly what I want, however my columns are very long (>10,000,000) and so this takes a long time to run. Does anyone know of a faster way of achieving this? I have tried shaking each column vector separately but this isn't faster. Thanks!
You can use randperm like this, but I don't know if it will be any faster than shake:
[m,n]=size(a)
for c = 1:n
a(randperm(m),c) = a(:,c);
end
Or you can try switch the randperm around to see which is faster (should produce the same result):
[m,n]=size(a)
for c = 1:n
a(:,c) = a(randperm(m),c);
end
Otherwise how many rows do you have? If you have far fewer rows than columns, it's possible that we can assume each permutation will be repeated, so what about something like this:
[m,n]=size(a)
cols = randperm(n);
k = 5; %//This is a parameter you'll need to tweak...
set_size = floor(n/k);
for set = 1:set_size:n
set_cols = cols(set:(set+set_size-1))
a(:,set_cols) = a(randperm(m), set_cols);
end
which would massively reduce the number of calls to randperm. Breaking it up into k equal sized sets might not be optimal though, you might want to add some randomness to that as well. The basic idea here though is that there will only be factorial(m) different orderings, and if m is much smaller than n (e.g. m=5, n=100000 like your data), then these orderings will be repeated naturally. So instead of letting that occur by itself, rather manage the process and reduce the calls to randperm which would be producing the same result anyway.
Here's a simple vectorized approach. Note that it creates an auxiliary matrix (ind) the same size as a, so depending on your memory it may be usable or not.
[~, ind] = sort(rand(size(a))); %// create a random sorting for each column
b = a(bsxfun(#plus, ind, 0:size(a,1):numel(a)-1)); %// convert to linear index
Obtain shuffled indices using randperm
idx = randperm(size(a,1));
Use the indices to shuffle the vector:
m = size(a,1);
for i=1:m
b(:,i) = a(randperm(m,:);
end
Look at this answer: Matlab: How to random shuffle columns of matrix
Here's a no-loop approach as it processes all indices at once and I believe this is as random as one could get given the requirements of shuffling among each column only.
Code
%// Get sizes
[m,n] = size(a);
%// Create an array of randomly placed sequential indices from 1 to numel(a)
rand_idx = randperm(m*n);
%// segregate those indices into rows and cols for the size of input data, a
col = ceil(rand_idx/m);
row = rem(rand_idx,m);
row(row==0)=m;
%// Sort both these row and col indices based on col, such that we have col
%// as 1,1,1,1 ...2,2,2,....3,3,3,3 and so on, which would represent per col
%// indices for the input data. Use these indices to linearly index into a
[scol,ind1] = sort(col);
a(1:m*n) = a((scol-1)*m + row(ind1))
Final output is obtained in a itself.

How do you pick out rows from an array based on a specific value in a column?

I have an array of data. For simplicity, let's call it a 4 x 3 matrix. Let's say I want to find a data point in column 2 that has a value of 5. Then, I want to take all rows that contains the value of 5 in column 2 and place it in its own array. My data is much larger than the one displayed below, so I don't want to go through by eye and look at every line of data and identify all the 5's.
% My idea of the code:
data = [1 2 3 4; 5 5 5 6; 6 4 5 6]
if data(:,2) == 5
% This is the part I can't figure out
end
Let's call the finaldata the array in which the data with 5's will be stored. How do I do this?
You should use logical indexing:
all_fives_rows = data(data(:, 2) == 5, :)
You can use the FIND Function to search that value, and give the coords back (it might be a vector) to retrieve the rows:
data(find (data(:,2)==5),:)
Why not using logical indexing: Performance

Resources