Matlab Insert NaN into array - matlab

I need to insert NaNs into in specific positions of an array.
I wrote the code that is correctly doing it, but as I need to do it for really large arrays, it's taking too long to run. Numpy has the function insert(i, x) that inserts an item at a given position. Is there a similar function in Matlab? Or is there a more efficient way to do it?
a = [1 2 3 5 6 7 9 10 13 14];
insertNanIndex = [0 1 0 1 1 0 0 0 1 1 0 0 1 0 0 0];
for i = find(insertNanIndex)
a = [a(1:i-1), NaN, a(i:end)]
end

The efficient way to do this would be to pre-compute the size of the result, make sure that insertNanIndex was large enough to serve as a mask, and insert a into the correct indices all at once. Right now, you are literally re-allocating the entire array for every NaN. Numpy's insert function would be equally inefficient because it would be doing the same operation.
If, as in your example, the number of zeros matches the number of elements of a, you can allocate an array based on insertNanIndex and mask it directly:
result = nan(size(insertNanIndex));
result(~insertNanIndex) = a;
If the number of zeros in insertNanIndex is not equal to the size of a, you can pad or trim it, but in that case, it becomes more of a moot point as to what the whole thing means.

Related

How to vectorize sub2ind?

I have a 2 dimensional array L, and I am trying to create a vector of linear indices ind for each row of this array.
L=
1 5 25 4 0 0
2 3 3 45 5 6
45 5 6 0 0 0
I am using lenr to store the number of non zero elements in each row (starting from column 1).
lenr=
4
6
3
Then I have 1x45 array RULES. Indices stored in L refer to elements in RULES. Since I want to vectorize the code, I decided to create linear indices and then run RULES(ind).
This works perfectly:
ind=sub2ind(size(L),1,lenr(1));
while this doesn't work:
ind=sub2ind(size(L),1:3,1:lenr(1:3));
Any ideas?
UPDATE:
This is what I initially tried to vectorize the code, but it did not works and that's why I checked linear indices:
rul=repmat(RULES,3);
result = rul((L(1:J,1:lenr(1:J))));
If I correctly interpret your edit, you want to create a variable result that contains the elements of RULES indicated by the non-zero elements of L. Note that in general, the best way to vectorize sub2ind is to not use sub2ind.
If you want result to be a linear array, you can simply write
%// transpose so that result is ordered by row
L_transposed = L.';
result = RULES(L_transposed(L_transposed>0));
If, instead, you want result to be an array of the same size as L, with all numbers in L replaced by the corresponding element in RULES, it's even simpler:
result = L;
result(result>0) = RULES(result>0);

sum matrix using logical matrix - index exceeds matrix dimensions

I have two matrices.
mcaps which is a double 1698 x 2
index_g which is a logical 1698 x 2
When using the line of code below I get the error message that Index exceeds matrix dimensions. I don't see how this is the case though?
tsp = nansum(mcaps(index_g==1, :));
Update
Sorry I should have mentioned that I need the sum of each column in the mcaps vector
** Example of data **
mcaps index_g
5 6 0 0
4 3 0 0
6 5 1 1
4 6 0 1
8 7 0 0
There are two problems here. I missed one. Original answer is below.
What I missed is that when you use the logical index in this way, you are picking out elements of the matrix that may have different numbers of elements in each column, so MATLAB can't return a well formed matrix back to nansum, and so returns a vector. To get around this, use the fact that 0 + anything = 0
% create a mask of values you don't want to sum. Note that since
% index_g is already logical, you don't have to test equal to 1.
mask = ~index_g & isnan(mcaps)
% create a temporary variable
mcaps_to_sum = mcaps;
% change all of the values that you don't want to sum to zero
mcaps_to_sum(mask) = 0;
% do the sum
sum(mcaps_to_sum,1);
This is basically all that the nansum function does internally, is to set all of the NaN values to zero and then call the sum function.
index_g == 1 returns a 1698 x 2 logical matrix, but then you add in an extra dimension with the colon. To sum the columns, use the optional dim input. You want:
tsp = nansum(mcaps(index_g == 1),1);

What does it mean to use logical indexing/masking to extract data from a matrix? (MATLAB)

I am new to matlab and I was wondering what it meant to use logical indexing/masking to extract data from a matrix.
I am trying to write a function that accepts a matrix and a user-inputted value to compute and display the total number of values in column 2 of the matrix that match with the user input.
The function itself should have no return value and will be called on later in another loop.
But besides all that hubbub, someone suggested that I use logical indexing/masking in this situation but never told me exactly what it was or how I could use it in my particular situation.
EDIT: since you updated the question, I am updating this answer a little.
Logical indexing is explained really well in this and this. In general, I doubt, if I can do a better job, given available time. However, I would try to connect your problem and logical indexing.
Lets declare an array A which has 2 columns. First column is index (as 1,2,3,...) and second column is its corresponding value, a random number.
A(:,1)=1:10;
A(:,2)=randi(5,[10 1]); //declares a 10x1 array and puts it into second column of A
userInputtedValue=3; //self-explanatory
You want to check what values in second column of A are equal to 3. Imagine as if you are making a query and MATLAB is giving you binary response, YES (1) or NO (0).
q=A(:,2)==3 //the query, what values in second column of A equal 3?
Now, for the indices where answer is YES, you want to extract the numbers in the first column of A. Then do some processing.
values=A(q,2); //only those elements will be extracted: 1. which lie in the
//second column of A AND where q takes value 1.
Now, if you want to count total number of values, just do:
numValues=length(values);
I hope now logical indexing is clear to you. However, do read the Mathworks posts which I have mentioned earlier.
I over simplified the code, and wrote more code than required in order to explain things. It can be achieved in a single-liner:
sum(mat(:,2)==userInputtedValue)
I'll give you an example that may illustrate what logical indexing is about:
array = [1 2 3 0 4 2];
array > 2
ans: [0 0 1 0 1 0]
using logical indexing you could filter elements that fullfil a certain condition
array(array>2) will give: [3 4]
you could also perform alterations to only those elements:
array(array>2) = 100;
array(array<=2) = 0;
will result in "array" equal to
[0 0 100 0 100 0]
Logical indexing means to have a logical / Boolean matrix that is the same size as the matrix that you are considering. You would use this as input into the matrix you're considering, and any locations that are true would be part of the output. Any locations that are false are not part of the output. To perform logical indexing, you would need to use logical / Boolean operators or conditions to facilitate the selection of elements in your matrix.
Let's concentrate on vectors as it's the easiest to deal with. Let's say we had the following vector:
>> A = 1:9
A =
1 2 3 4 5 6 7 8 9
Let's say I wanted to retrieve all values that are 5 or more. The logical condition for this would be A >= 5. We want to retrieve all values in A that are greater than or equal to 5. Therefore, if we did A >= 5, we get a logical vector which tells us which values in A satisfy the above condition:
>> A >= 5
ans =
0 0 0 0 1 1 1 1 1
This certainly tells us where in A the condition is satisfied. The last step would be to use this as input into A:
>> B = A(A >= 5)
B =
5 6 7 8 9
Cool! As you can see, there isn't a need for a for loop to help us select out elements that satisfy a condition. Let's go a step further. What if I want to find all even values of A? This would mean that if we divide by 2, the remainder would be zero, or mod(A,2) == 0. Let's extract out those elements:
>> C = A(mod(A,2) == 0)
C =
2 4 6 8
Nice! So let's go back to your question. Given your matrix A, let's extract out column 2.
>> col = A(:,2)
Now, we want to check to see if any of column #2 is equal to a certain value. Well we can generate a logical indexing array for that. Let's try with the value of 3:
>> ind = col == 3;
Now you'll have a logical vector that tells you which locations are equal to 3. If you want to determine how many are equal to 3, you just have to sum up the values:
>> s = sum(ind);
That's it! s contains how many values were equal to 3. Now, if you wanted to write a function that only displayed how many values were equal to some user defined input and displayed this event, you can do something like this:
function checkVal(A, val)
disp(sum(A(:,2) == val));
end
Quite simply, we extract the second column of A and see how many values are equal to val. This produces a logical array, and we simply sum up how many 1s there are. This would give you the total number of elements that are equal to val.
Troy Haskin pointed you to a very nice link that talks about logical indexing in more detail: http://www.mathworks.com/help/matlab/math/matrix-indexing.html?refresh=true#bq7eg38. Read that for more details on how to master logical indexing.
Good luck!
%% M is your Matrix
M = randi(10,4)
%% Val is the value that you are seeking to find
Val = 6
%% Col is the value of the matrix column that you wish to find it in
Col = 2
%% r is a vector that has zeros in all positions except when the Matrix value equals the user input it equals 1
r = M(:,Col)==Val
%% We can now sum all the non-zero values in r to get the number of matches
n = sum(r)
M =
4 2 2 5
3 6 7 1
4 4 1 6
5 8 7 8
Val =
6
Col =
2
r =
0
1
0
0
n =
1

Is there an array creation function for full arrays that has the same signature as sparse matrix constructor?

I'd like to accumulate indexed elements in a matrix, like table and tapply function in R.
I found sparse(i,j,s,m,n) fit my need perfectly,
As the document says:"Any elements of s that have duplicate values of i and j are added together."
But I have to convert the obtained sparse matrix to a full one using full():
a = a + full(sparse(i,j,s,m,n));
Is this a efficient way to do so?
By the way, is there anything like below, no matter whether adding duplicated i,j pairs?
a = setelements(a, i,j,s);
and
vector = getelement(a,i,j);
where i&j take meanings in sparse() function.
And what if a is a multidimensional array? sparse() only deal with matrix.
Do I have to set the entries page by page with outer loops?
Take a look at accumaray. For example,
ii = [1 2 2 3 3];
jj = [3 2 2 2 2];
s = [10 20 30 40 50];
a = accumarray([ii(:) jj(:)],s(:));
gives
a =
0 0 10
0 50 0
0 90 0
Note that each row of the first argument ([ii(:) jj(:)]) defines an N-dimensional index into the output array (N is 2 in this example).
accumarray is very flexible. It works for N-dimensional arrays, lets you specify size of the result (it may be larger than inferred from the supplied indices), and can even apply an arbitrary function (different from sum) to each set of values defined by the same index.
As a more general example, with the above data,
a = accumarray([ii(:) jj(:)],s(:),[4 4],#max)
gives
a =
0 0 10 0
0 30 0 0
0 50 0 0
0 0 0 0

Deleting columns in array with zeros

I have an array that starts of with zeros and continues into other numbers
I would like to delete the columns in the array that start off with zero but keep the other numbers
example of an column array below:
x= [0 0 0 0 0 2 4 6 8 0 1 2];
Answer of column array would look like
x= 2 4 6 8 0 1 2
I'm using octave 3.4.2/matlab
Thanks
Here is the code:
x = x(find(x~=0, 1):end);
or
x(1:find(x~=0,1)-1) = [];
The find command should work for this.
Assuming your vector is x:
find(x ~= 0)
Will return all indices where x is non-zero. Just grab the first index and go from there to delete all values from 1 to index.
Logical indexing will work just fine in this case: i.e.,
y = x(:,x(1,:)~=0)
will do the job for you. The inner logical comparison, x(1,:)~=0 returns true for every column whose first element is not zero. The indexing operation, x(:,...) selects only those columns for which the logical comparison returned true.