Delete adjacent repeated terms - matlab

I have the following vector a:
a=[8,8,9,9,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8]
From a I want to delete all "adjacent" repetitions to obtain:
b=[8,9,1,2,3,4,5,6,7,8]
However, when I do:
unique(a,'stable')
ans =
8 9 1 2 3 4 5 6 7
You see, unique only really gets the unique elements of a, whereas what I want is to delete the "duplicates"... How do I do this?

It looks like a run-length-encoding problem (check here). You can modify Mohsen's solution to get the desired output. (i.e. I claim no credit for this code, yet the question is not a duplicate in my opinion).
Here is the code:
a =[8,8,9,9,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8]
F=find(diff([a(1)-1, a]));
Since diff(a) returns an array of length (length(a) -1), we want to add a value at the beginning (i.e the a(1)) to get a vector the same size as a. Here we subtract 1 so that, as mentioned by #surgical_tubing, the command find effectively finds it because it looks for non zero elements, so we want to make sure the value is non zero.
Hence diff([a(1)-1, a]) looks like this:
Columns 1 through 8
1 0 1 0 -8 0 1 0
Columns 9 through 16
1 0 1 0 1 0 1 0
Columns 17 through 20
1 0 1 0
Now having found the repeated elements, we index back into a with the positions found by find:
newa=a(F)
and output:
newa =
Columns 1 through 8
8 9 1 2 3 4 5 6
Columns 9 through 10
7 8

Related

Calculated field in Tableau

I have a very simple problem but i am totally new in Tableau. So needs some help in solving this problem.
My Data Set contain
Year_Track_4,Year_Track_5,Year_Track_6,Year_Track_7,.... N
Each Year_Track contain 1 /0 values. 1 means graduated and 0 means didnot graduated or failed
enter image description here
y4 y5 N
1 8
0 5
1 6
0 1
1 2
1 5
1 7
1 8
1 5
0 7
1 5
1 8
1 6
1 1
So , I want to create a placeholder in Tableau or Calculated Field or parameter to select one YEAR and count number of graduated or didn't graduated.
I need to create the same for OverAll_0 and OverAll_1 as one Calculated field and it contains the value of 1 and 0 . So, that i can use the SUM(N) and and calculate it.
I used IFF statement to solve this problem
IIF(Year_Track_4 = 0) then 'graduated in 4 year '
.......
......

Matlab returning matrix with value of element's rank in descending order [duplicate]

Hi I need to sort a vector and assign a ranking for the corresponding sorting order. I'm using sort function [sortedValue_X , X_Ranked] = sort(X,'descend');
but the problem is it assigns different ranks for the same values (zeros).
i.e. x = [ 13 15 5 5 0 0 0 1 0 3] and I want zeros to take the same last rank which is 6 and fives needs to share the 3rd rank etc..
any suggestions?
The syntax [sortedValues, sortedIndexes] = sort(x, 'descend') does not return rank as you describe it. It returns the indexes of the sorted values. This is really useful if you want to use the sort order from one array to rearrange another array.
As suggested by #user1860611, unique seems to do what you want, using the third output as follows:
x = [ 13 15 5 5 0 0 0 1 0 3];
[~, ~, forwardRank] = unique(x);
%Returns
%forwardRank =
% 5 6 4 4 1 1 1 2 1 3
To get the order you want (decending) you'll need to reverse the order, like this:
reverseRank = max(forwardRank) - forwardRank + 1
%Returns
%reverseRank =
% 2 1 3 3 6 6 6 5 6 4
You may be done at this point. But you may want to sort these into the into an acsending order. This is a reorder of the reverseRank vector which keeping it in sync with the original x vector, which is exactly what the 2nd argument of sort is desined to help with. So we can do something like this:
[xSorted, ixsSort] = sort(x, 'descend'); %Perform a sort on x
reverseRankSorted = reverseRank(ixsSort); %Apply that sort to reverseRank
Which generates:
xSorted = 15 13 5 5 3 1 0 0 0 0
reverseRankSorted = 1 2 3 3 4 5 6 6 6 6
tiedrank.m might be the thing you are looking for.
>> x = round(rand(1,5)*10)
x =
8 7 3 10 0
>> tiedrank(x)
ans =
4 3 2 5 1

Vector-defined cross product application matrix and vectorization in Matlab

I ran into an operation I cannot seem to achieve via vectorization.
Let's say I want to find the matrix of the application defined by
h: X -> cross(V,X)
where V is a predetermined vector (both X and V are 3-by-1 vectors).
In Matlab, I would do something like
M= cross(repmat(V,1,3),eye(3,3))
to get this matrix. For instance, V=[1;2;3] yields
M =
0 -3 2
3 0 -1
-2 1 0
Let's now suppose that I have a 3-by-N matrix
V=[V_1,V_2...V_N]
with each column defining its own cross-product operation. For N=2, here's a naive try to find the two cross-product matrices that V's columns define
V=[1,2,3;4,5,6]'
M=cross(repmat(V,1,3),repmat(eye(3,3),1,2))
results in
V =
1 4
2 5
3 6
M =
0 -6 2 0 -3 5
3 0 -1 6 0 -4
-2 4 0 -5 1 0
while I was expecting
M =
0 -3 2 0 -6 5
3 0 -1 6 0 -4
-2 1 0 -5 4 0
2 columns are inverted.
Is there a way to achieve this without for loops?
Thanks!
First, make sure you read the documentation of cross very carefully when dealing with matrices:
It says:
C = cross(A,B,DIM), where A and B are N-D arrays, returns the cross
product of vectors in the dimension DIM of A and B. A and B must
have the same size, and both SIZE(A,DIM) and SIZE(B,DIM) must be 3.
Bear in mind that if you don't specify DIM, it's automatically assumed to be 1, so you're operating along the columns. In your first case, you specified both the inputs A and B to be 3 x 3 matrices. Therefore, the output will be the cross product of each column independently due to the assumption that DIM=1. As such, you expect that the i'th column of the output contains the cross product of the i'th column of A and the i'th column of B and the number of rows is expected to be 3 and the number of columns needs to match between A and B.
You're getting what you expect because the first input A has [1;2;3] duplicated correctly over the columns three times. From your second piece of code, what you're expecting for V as the first input (A) looks like this:
V =
1 1 1 4 4 4
2 2 2 5 5 5
3 3 3 6 6 6
However, when you do repmat, you are in fact alternating between each column. In fact, you are getting this:
V =
1 4 1 4 1 4
2 5 2 5 2 5
3 6 3 6 3 6
repmat tile matrices together and you specified that you wanted to tile V horizontally three times. That's obviously not correct. This explains why the columns are swapped because the second, fourth and sixth columns of V actually should appear at the last three columns instead. As such, the ordering of your input columns is the reason why the output appears swapped.
As such, you need to re-order V so that the first three vectors are [1;2;3], followed by the next three vectors as [4;5;6] after. Therefore, you can generate your original V matrix first, then create a new matrix such that the odd column comes first in a group of three, followed by the even column in a group of three after:
>> V = [1,2,3;4,5,6].';
>> V = V(:, [1 1 1 2 2 2])
V =
1 1 1 4 4 4
2 2 2 5 5 5
3 3 3 6 6 6
Now use V with cross and maintain the same second input:
>> M = cross(V, repmat(eye(3), 1, 2))
M =
0 -3 2 0 -6 5
3 0 -1 6 0 -4
-2 1 0 -5 4 0
Looks good to me!

sort in matlab and assign ranking

Hi I need to sort a vector and assign a ranking for the corresponding sorting order. I'm using sort function [sortedValue_X , X_Ranked] = sort(X,'descend');
but the problem is it assigns different ranks for the same values (zeros).
i.e. x = [ 13 15 5 5 0 0 0 1 0 3] and I want zeros to take the same last rank which is 6 and fives needs to share the 3rd rank etc..
any suggestions?
The syntax [sortedValues, sortedIndexes] = sort(x, 'descend') does not return rank as you describe it. It returns the indexes of the sorted values. This is really useful if you want to use the sort order from one array to rearrange another array.
As suggested by #user1860611, unique seems to do what you want, using the third output as follows:
x = [ 13 15 5 5 0 0 0 1 0 3];
[~, ~, forwardRank] = unique(x);
%Returns
%forwardRank =
% 5 6 4 4 1 1 1 2 1 3
To get the order you want (decending) you'll need to reverse the order, like this:
reverseRank = max(forwardRank) - forwardRank + 1
%Returns
%reverseRank =
% 2 1 3 3 6 6 6 5 6 4
You may be done at this point. But you may want to sort these into the into an acsending order. This is a reorder of the reverseRank vector which keeping it in sync with the original x vector, which is exactly what the 2nd argument of sort is desined to help with. So we can do something like this:
[xSorted, ixsSort] = sort(x, 'descend'); %Perform a sort on x
reverseRankSorted = reverseRank(ixsSort); %Apply that sort to reverseRank
Which generates:
xSorted = 15 13 5 5 3 1 0 0 0 0
reverseRankSorted = 1 2 3 3 4 5 6 6 6 6
tiedrank.m might be the thing you are looking for.
>> x = round(rand(1,5)*10)
x =
8 7 3 10 0
>> tiedrank(x)
ans =
4 3 2 5 1

How to count number of elements in specific row? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Count number of values in matrix within given range
I have the following matrix
A=[ 1 2 3 4 5 6 7;
3 4 5 6 8 9 1;
3 4 2 5 6 7 8]
How to find out how many element there are in the first row, which have a value in the range >2 & <6?
If I understood well what you mean with account, if you want to find elements that meet your criteria:
B = A(1,:)
find(B > 2 & B < 6)
or in one line:
find(A(1,:) > 2 & A(1,:) < 6)
You must know also that find gives you the indices, not the actual elements, of the array that satisfy the logical expression given.
You need to think in terms of matrices, using vectorized computations. (Using find is not a good solution here, since it is not vectorized to operate independently on the rows.)
First, what happens if you try the test, A > 2, in MATLAB? TRY IT!
A=[ 1 2 3 4 5 6 7;
3 4 5 6 8 9 1;
3 4 2 5 6 7 8];
>> A > 2
ans =
0 0 1 1 1 1 1
1 1 1 1 1 1 0
1 1 0 1 1 1 1
MATLAB generates a logical array, true where an element of A was greater than 2. Similarly, if we type A < 6, we get another logical array.
>> A < 6
ans =
1 1 1 1 1 0 0
1 1 1 0 0 0 1
1 1 1 1 0 0 0
What if we combine the two ops into one expression?
>> (A > 2) & (A < 6)
ans =
0 0 1 1 1 0 0
1 1 1 0 0 0 0
1 1 0 1 0 0 0
Ok, so this array tells us where both sub-expressions were true. Note that we can operate on a logical array using sum and other arithmetic ops.
>> sum((A > 2) & (A < 6),2)
ans =
3
3
3
So the above expression counts the number of elements that satisfy your goal for each row, and it will be quite fast. Learn to use MATLAB as it should be used. Your code will get better.