How do I change cell array to numeric values in MATLAB? - matlab

I want to the do the following
Input: (cell array)
ab
ac
ad
aab
ac
aac
aab
ac
I want the output to map to unique numeric values, like
1
2
3
4
2
5
4
2
Is there an easy way to do this?
The input is about 250,000 and of variable length. I just want to map the cells with the same content to the same number.
Thanks.

If we call your cell array A, then the following command does what you need:
[uniqueCells,~,idxYouWant] = unique(A);
In this, the uniqueCells are the unique values you have (in sorted order); and idxYouWant is an array of numbers like you want, where
A = uniqueCells(idxYouWant);
I think this is exactly what you need.

Related

Select a number of random rows based on one columan condition in matlab

I have a table 'X' like this:
name value score
joy 3 60
rony 8 50
macheis 20 20
joung 2 80
joy 8 3
joy 90 0
joung 4 78
machies 3 23
joy 7 99
I want to select 2 random rows(with name, value, score) where the name is 'joy'.
I applied something like this:
mnew = datasample(find(X.name=='joy'),2); but it does not work! and gives me the error: Undefined operator '==' for input arguments of type 'cell'.
The rows should be selected randomly (with all columns values) where the name is joy.
Does anyone any other solution of this problem? how can i do it in MATLAB?
You have the right idea, but in order to check for the presence of a string within a cell array of strings, you need to use strcmp, ismember, or another method for comparing a string to a cell array.
You probably also want to specify that you don't want to use replacement when calling datasample so you don't get the same row twice.
subx = X(datasample(find(strcmp(X.name, 'joy')), 2, 'Replace', false),:);

Selecting all columns in a cell array that contain a certain value in the first row?

I currently have a 4x3500 cell array. First row is a single number, 2 row is a single string, 3rd and 4th rows are also single numbers.
Ex:
1 1 2 3 3 4 5 5 5 6
hi no ya he ........ % you get the idea
28 34 18 0 3 ......
55 2 4 42 24 .....
I would like to be able to select all columns that have a certain value in the first row. ie if I wanted '1' as the first row value, it would return
1 1
hi no
28 34
55 2
Then I would like to sort based on the 2nd row's string. ie if I wanted to have'hi', it would return:
1
hi
28
55
I have attempted to do:
variable = cellArray{:,find(cellArray{1,:} == 1)}
However I keep getting:
Error using find
Too many input arguments.
or
Error using ==
Too many input arguments.
Any help would be much appreciated! :)
{} indexing will return a comma separated list which will provide multiple outputs. When you pass this to find, it's the same as passing each element of your cell array as a separate input. This is what leads to the error about to many input arguments.
You will want to surround the comma-separated list with [] to create an array or numbers. Also, you don't need find because you can just use logical indexing to grab the columns you want. Additionally, you will want to index using () to grab the relevant rows, again to avoid the comma-separated list.
variable = cellArray(:, [cellArray{1,:}] == 1)

Is there a quick way to assign unique text entries in an array a number?

In MatLab, I have several data vectors that are in text. For example:
speciesname = [species1 species2 species3];
genomelength = [8 10 5];
gonometype = [RNA DNA RNA];
I realise that to make a plot, arrays must be numerical. Is there a quick and easy way to assign unique entries in an array a number, for example so that RNA = 1 and DNA = 2? Note that some arrays might not be binary (i.e. have more than two options).
Thanks!
So there is a quick way to do it, but im not sure that your plots will be very intelligible if you use numbers instead of words.
You can make a unique array like this:
u = unique(gonometype);
and make a corresponding number array is just 1:length(u)
then when you go through your data the number of the current word will be:
find(u == current_name);
For your particular case you will need to utilize cells:
gonometype = {'RNA', 'DNA', 'RNA'};
u = unique(gonometype)
u =
'DNA' 'RNA'
current = 'RNA';
find(strcmp(u, current))
ans =
2

Delete rows from a cell given a specific condition

I have a cell type big-variable sorted out by FIRM (A(:,2)) and I want to erase all the rows in which the same firm doesn't appear at least 3 times in a row. In this example, A:
FIRM
1997 'ABDR' 0,56 464 1641 19970224
1997 'ABDR' 0,65 229 9208 19970424
1997 'ABDR' 0,55 125 31867 19970218
1997 'ABD' 0,06 435 8077 19970311
1997 'ABD' 0,00 150 44994 19970804
1997 'ABFI' 2,07 154 46532 19971209
I would keep only A:
1997 'ABDR' 0,56 464 1641 19970224
1997 'ABDR' 0,65 229 9208 19970424
1997 'ABDR' 0,55 125 31867 19970218
Thanks a lot.
Notes:
I used fopen and textscanto import the csv file.
I performed some changes on some variables for all of them to fit in a cell-type variable
I converted some number-elements into stings
F_x=num2cell(Data{:,x});
I got new variable just with year
F_ya=max(0,fix(log10(F_y)+1)-4);
F_yb=fix(F_y./10.^F_ya);
F_yc = num2cell(F_yb);
Create new cell A w/ variables I need
A=[F_5C Data{:,1} Data{:,2} Data{:,3} Data{:,4} F_xa F_xb];
Meaning that within the cell I have some variables that are strings and others that are numbers.
I'm going to assume that your names are stored in a cell array. As such, your names would actually be:
names = {'ABDR', 'ABDR', 'ABDR', 'ABD', 'ABD', 'ABFI'};
We can then use strcmpi. What this function does is that it string compares two strings together. It returns true if the strings match and false otherwise. This is also case insensitive, so ABDR would be the same as abdr.
You would call strcmpi like so:
v = strcmpi(str1, str2);
Alternatively str2 can be a cell array. How this would work is that it would take a single string str1 and compare with each string in each cell of the cell array. It would then return a logical vector that is the same size as str2 which indicates whether we have a match at this particular location or not.
As such, we can go through each element of names and see how many matches we have overall with the entire names cell array. We can then figure out which locations we need to select by checking to see if we have at least 3 matches or more per name in the names array. In other words, we simply sum up the logical vector for each string within names and filter those that sum up to 3 or more. We can use cellfun to help us perform this. As such:
sums = cellfun(#(x) sum(strcmpi(x,names)), names);
Doing this thus gives:
sums =
3 3 3 2 2 1
Now, we need those locations that have three or more. As such:
locations = sums >= 3
locations =
1 1 1 0 0 0
As such, these are the rows that you can use to filter out your matrix. This is also a logical vector. Assuming that A contains your data, you would simply do A(locations,:) to filter out all those rows that have occurrences of three or more times for a particular name. I really don't know how you constructed A, so I'm assuming it's like a 2D matrix. If you put in the code that you used to construct this matrix, I'll modify my post to get it working for you. In any case, what's important is locations. This tells you what rows you need to select to match your criteria.

Using SUM and UNIQUE to count occurrences of value within subset of a matrix

So, presume a matrix like so:
20 2
20 2
30 2
30 1
40 1
40 1
I want to count the number of times 1 occurs for each unique value of column 1. I could do this the long way by [sum(x(1:2,2)==1)] for each value, but I think this would be the perfect use for the UNIQUE function. How could I fix it so that I could get an output like this:
20 0
30 1
40 2
Sorry if the solution seems obvious, my grasp of loops is very poor.
Indeed unique is a good option:
u=unique(x(:,1))
res=arrayfun(#(y)length(x(x(:,1)==y & x(:,2)==1)),u)
Taking apart that last line:
arrayfun(fun,array) applies fun to each element in the array, and puts it in a new array, which it returns.
This function is the function #(y)length(x(x(:,1)==y & x(:,2)==1)) which finds the length of the portion of x where the condition x(:,1)==y & x(:,2)==1) holds (called logical indexing). So for each of the unique elements, it finds the row in X where the first is the unique element, and the second is one.
Try this (as specified in this answer):
>>> [c,~,d] = unique(a(a(:,2)==1))
c =
30
40
d =
1
3
>>> counts = accumarray(d(:),1,[],#sum)
counts =
1
2
>>> res = [c,counts]
Consider you have an array of various integers in 'array'
the tabulate function will sort the unique values and count the occurances.
table = tabulate(array)
look for your unique counts in col 2 of table.