I want to convert the char matrix into numbers in matlab - arrays

I want to convert the string into numbers for example x=[abacaaaabb] I want to assign values a=1 b=2 and c=-1 and store in new matrix x=[1 2 1 -1....}

You can create a mapping:
map = zeros(1,256);
map('abc') = [1, 2, -1];
Then you can just index it with your input:
x = 'abacaaaabb';
mx = map(x);

A simpler way (unless your mapping really does have to be arbitrary like in your example):
x=['abacaaaabb'];
num = x - 96
results in
num =
1 2 1 3 1 1 1 1 2 2

Related

MATLAB: Check if a value in a cell array remains the same

My question may be a bit "silly", but I am stucked here, so I would really need your help.
So, we have a cell array Q 5520x1, like the one below:
I'm only interested in the first two numbers of each row. To be specifically clear, giving
K>> Q{1}
ans = 0 1 0 238
I only care about 0 and 1, and so on with the other rows. Only the first two numbers of each row. Let's just ignore the rest values in each row of Q, they are more or less irrelevant.
My problem is, how is it possible to check if the first value of each row in the cell array Q, in the example above 0, remains the same? What I would like to achieve, is while the first value is the same, I want to store in another cell array, all the second values. In case of number 0, I want to store the values
[1,3,127,129,216,217,252,253,302,303,342,343]
and so on. How could this be done?
Any help or advice would be really appreciated.
% Example Q
Q = {[0 1 135 134];
[0 3 154 26];
[0 16 146 234];
[1 2 324 125];
[1 7 213 252]};
A = cell2mat(Q(1:2760));
[~,~,ind2] = unique(A(:,1));
C = arrayfun(#(x)A(find(ind2==x),2),1:max(ind2),'UniformOutput',false);
C{1}
ans =
1
3
16
C{2}
ans =
2
7
You can use unique and accumarray as follows:
Q = {[0 1 0 238]
[0 3 1 84]
[1 2 1 85]
[3 4 5 6]}; %// example data. Cell array of equal-size row vectors
Qm = vertcat(Q{:}); %// convert Q into matrix
[vals, ~, id] = unique(Qm(:,1)); %// get unique id for 1st col
result = accumarray(id, Qm(:,2), [], #(x){x.'}); %'// gather 2nd col values according to id
This gives:
vals =
0
1
3
result{1} =
1 3
result{2} =
2
result{3} =
4
You can do it with a for loop :
cell_range = max(cellfun(#(x) x(1),Q));
C = cell(cell_range,1)
for i = 1:length(Q)
M = Q{i};
disp(M(1));
C{M(1)} = [C{M(1)}, M(2)];
end

Vectorization- Matlab

Given a vector
X = [1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3]
I would like to generate a vector such
Y = [1 2 3 4 5 1 2 3 4 5 6 1 2 3 4 5]
So far what I have got is
idx = find(diff(X))
Y = [1:idx(1) 1:idx(2)-idx(1) 1:length(X)-idx(2)]
But I was wondering if there is a more elegant(robust) solution?
One approach with diff, find & cumsum for a generic case -
%// Initialize array of 1s with the same size as input array and an
%// intention of using cumsum on it after placing "appropriate" values
%// at "strategic" places for getting the final output.
out = ones(size(X))
%// Find starting indices of each "group", except the first group, and
%// by group here we mean run of identical numbers.
idx = find(diff(X))+1
%// Place differentiated and subtracted values of indices at starting locations
out(idx) = 1-diff([1 idx])
%// Perform cumulative summation for the final output
Y = cumsum(out)
Sample run -
X =
1 1 1 1 2 2 3 3 3 3 3 4 4 5
Y =
1 2 3 4 1 2 1 2 3 4 5 1 2 1
Just for fun, but customary bsxfun based alternative solution -
%// Logical mask with each column of ones for presence of each group elements
mask = bsxfun(#eq,X(:),unique(X(:).')) %//'
%// Cumulative summation along columns and use masked values for final output
vals = cumsum(mask,1)
Y = vals(mask)
Here's another approach:
Y = sum(triu(bsxfun(#eq, X, X.')), 1);
This works as follows:
Compare each element with all others (bsxfun(...)).
Keep only comparisons with current or previous elements (triu(...)).
Count, for each element, how many comparisons are true (sum(..., 1)); that is, how many elements, up to and including the current one, are equal to the current one.
Another method is using the function unique
like this:
[unqX ind Xout] = unique(X)
Y = [ind(1):ind(2) 1:ind(3)-ind(2) 1:length(X)-ind(3)]
Whether this is more elegant is up to you.
A more robust method will be:
[unqX ind Xout] = unique(X)
for ii = 1:length(unqX)-1
Y(ind(ii):ind(ii+1)-1) = 1:(ind(ii+1)-ind(ii));
end

Vectorizing the subtraction of multiple vectors from one individual vector

I am trying to vectorize, or make the following code more efficient:
[Y,k] = min(abs(dxcp-X));
X = dxcp(k);
The objective of the code is to compare a value X to an array of accepted values for x (dxcp) and assign X to the closest value in the array dxcp. For example:
X is equal to 9 and the dxcp array is: [ 1, 2, 3, 6, 10, 20]. The second line would change X to be equal to 10.
I am trying to change my script so that X can be inputted as an array of numbers and was wondering what would be the most efficient way to go about making the above code work for this case. Of course I could use:
for i = 1:numel(X)
[Y,k] = min(abs(dxcp-X(i)));
X(i) = dxcp(k);
end
But I have the feeling that there must be a way to accomplish this more efficiently. Cheers, nzbru.
You need to use bsxfun to extend your case to a vector case.
Code
dxcp = [1 2 3 6 10 20];
X = [2 5 9 18]
abs_diff_vals = abs(bsxfun(#minus,dxcp,X')); %%//'
[~,k] = min(abs_diff_vals,[],2);
X = dxcp(k)
Output
X =
2 5 9 18
X =
2 6 10 20

Create all possible Mx1 vectors from an Nx1 vector in MATLAB

I am trying to create all possible 1xM vectors (word) from a 1xN vector (alphabet) in MATLAB. N is > M. For example, I want to create all possible 2x1 "words" from a 4x1 "alphabet" alphabet = [1 2 3 4];
I expect a result like:
[1 1]
[1 2]
[1 3]
[1 4]
[2 1]
[2 2]
...
I want to make M an input to my routine and I do not know it beforehand. Otherwise, I could easily do this using nested for-loops. Anyway to do this?
Try
[d1 d2] = ndgrid(alphabet);
[d2(:) d1(:)]
To parameterize on M:
d = cell(M, 1);
[d{:}] = ndgrid(alphabet);
for i = 1:M
d{i} = d{i}(:);
end
[d{end:-1:1}]
In general, and in languages that don't have ndgrid in their library, the way to parameterize for-loop nesting is using recursion.
[result] = function cartesian(alphabet, M)
if M <= 1
result = alphabet;
else
recursed = cartesian(alphabet, M-1)
N = size(recursed,1);
result = zeros(M, N * numel(alphabet));
for i=1:numel(alphabet)
result(1,1+(i-1)*N:i*N) = alphabet(i);
result(2:M,1+(i-1)*N:i*N) = recursed; % in MATLAB, this line can be vectorized with repmat... but in MATLAB you'd use ndgrid anyway
end
end
end
To get all k-letter combinations from an arbitrary alphabet, use
n = length(alphabet);
aux = dec2base(0:n^k-1,n)
aux2 = aux-'A';
ind = aux2<0;
aux2(ind) = aux(ind)-'0'
aux2(~ind) = aux2(~ind)+10;
words = alphabet(aux2+1)
The alphabet may consist of up to 36 elements (as per dec2base). Those elements may be numbers or characters.
How this works:
The numbers 0, 1, ... , n^k-1 when expressed in base n give all groups of k numbers taken from 0,...,n-1. dec2base does the conversion to base n, but gives the result in form of strings, so need to convert to the corresponding number (that's part with aux and aux2). We then add 1 to make the numbers 1,..., n. Finally, we index alphabet with that to use the real letters of numbers of the alphabet.
Example with letters:
>> alphabet = 'abc';
>> k = 2;
>> words
words =
aa
ab
ac
ba
bb
bc
ca
cb
cc
Example with numbers:
>> alphabet = [1 3 5 7];
>> k = 2;
>> words
words =
1 1
1 3
1 5
1 7
3 1
3 3
3 5
3 7
5 1
5 3
5 5
5 7
7 1
7 3
7 5
7 7
use ndgrid function in Matlab
[a,b] = ndgrid(alphabet)

How to remove elements of one array from another?

I have two arrays:
A=[1 1 2 2 3 3 3];
B=[1 3];
Is there any function that can remove elements which are contained in B from A?
The result should be
C=[1 2 2 3 3];
The order is not important, but if there is more specific elements like two times 1 in A, then I need operation that removes (from A) only as many of these specific elements is in B (in this case only one of 1 and one of 3; meaning other 1 and 3 should remain in final product C). This function should be analogous to setdiff, with the difference that it should take care of multiple instances of array elements. This analogy can hold because my B only contains elements that are in A.
For loop solution:
C = A;
for ii = 1:length(B)
C(find(C == B(ii), 1,'first')) = [];
end
Result
C =
1 2 2 3 3
Here's a vectorized solution using accumarray and repelem:
maxValue = max([A B]);
counts = accumarray(A(:), 1, [maxValue 1])-accumarray(B(:), 1, [maxValue 1]);
C = repelem(1:maxValue, max(counts, 0));
And the result for your sample data A = [1 1 2 2 3 3 3]; B = [1 3];:
C =
1 2 2 3 3
This will even work for cases where there are values in B not in A (like B = [1 4];) or more of a given value in B than in A (like B = [1 1 1];).
Note: The above works sinceA and B contain integers. If they were to contain floating-point values, you could map the unique values to integers first using unique and ismember. Let's say we had the following sample data:
A = [0 0 pi pi 2*pi 2*pi 2*pi];
B = [0 2*pi];
Here's a variant of the above code that can handle this:
uniqueValues = unique([A B]);
[~, A] = ismember(A, uniqueValues);
[~, B] = ismember(B, uniqueValues);
maxValue = max([A B]);
counts = accumarray(A(:), 1, [maxValue 1])-accumarray(B(:), 1, [maxValue 1]);
C = uniqueValues(repelem(1:maxValue, max(counts, 0)));
And the results:
C =
0 3.1416 3.1416 6.2832 6.2832 % [0 pi pi 2*pi 2*pi]

Resources