Info
La pregunta está cerrada. Vuélvala a abrir para editarla o responderla.
Can I eliminate loop from this function?
3 visualizaciones (últimos 30 días)
Mostrar comentarios más antiguos
Hello Matlab Community,
I have a table T with couple of million lines and 3 fields: gene1, gene2, sample. Here is what I want to do:
1) Find rows that have the same gene1-gene2 value (both string): This can be easily done by unique function.
2) For each unique pair of gene1-gene2, find their unique "sample", count them and generate a string from those sample-ids. This is where I have problem with. Below is what I have done which works but looping over a large table takes a long time. I was thinking maybe passing a function handle and doing a "varfun" improves it, but would love to hear if you have a better solution?
[T_uniq]= unique(T(:,1:2),'rows');
T_uniq_annot= myFun(T_uniq, T);
function [x]= myFun(x, A)
for i=1:size(x,1)
ix_A=(strcmp(x.gene1(i),A.gene1) & strcmp(x.gene2(i),A.gene2));
temp=unique(A.sample(ix_A));
x.uniq_samples(i)=numel(temp);
if numel(temp)>1
temp=temp.';
x.sample(i) = cellstr(strjoin(temp,', '));
else
x.sample(i)= cellstr(temp);
end
clear ix_A temp;
end
Thank You,
Nfarnoud
3 comentarios
Jan
el 9 de Mzo. de 2016
"size(x, 1)" looks like x is an array. "x.sample(i)" looks like x is a scalar. Is this a typo in pseudo code?
What is the type of "temp"? Is this a cell string already? If so:
x.sample{i} = strjoin(strjoin(temp.', ', ');
is faster. Is "x.sample" pre-allocated?
Respuestas (2)
Jan
el 9 de Mzo. de 2016
Is x.sample pre-allocated?
function [x]= myFun(x, A)
n = size(x.gene1, 1); % Is "size(x, 1)" a typo?!
x.sample = cell(1, n); % Pre-allocate!!!
x.uniq_samples = zeros(1, n); % Pre-allocate!!!
for i = 1:n
ix_A = (strcmp(x.gene1(i),A.gene1) & strcmp(x.gene2(i),A.gene2));
temp = unique(A.sample(ix_A));
x.uniq_samples(i) = numel(temp);
x.sample{i} = strjoin(strjoin(temp.', ', ');
% Don't clear inside the loop, this wastes time only
end
Is A.gene1 and A.gene2 large? Then sorting them might be useful, because this is done in each call of unique again.
1 comentario
Ced
el 9 de Mzo. de 2016
All columns in the table have the same length, so I believe
size(x,1)
should be fine, no? Maybe even a tiny bit faster than size(x.gene1,1).
Ced
el 9 de Mzo. de 2016
Editada: Ced
el 9 de Mzo. de 2016
Do your genes have upper and lower case letters? Otherwise, use strcmpi for a minor speed-up.
instead of strcmp.
Small dummy example gave the following:
base = 'gAuC';
N = 10000000; % we have a lot of genes
Tt = table(base(randi(4,N,4)),base(randi(4,N,4))); % create dummy genes
tic
Tt_unique = unique(Tt,'rows');
toc
M = 1000; % repeat tests 1000 times
% Using strcmp
tic
bla1 = zeros(M,1);
for i = 1:1000
ix1 = strcmp(Tt_unique(:,1),'gauc');
bla1(i) = numel(Tt_unique.Var1(ix1));
end
toc
% Using strcmpi
tic
bla2 = zeros(M,1);
for i = 1:1000
ix2 = strcmpi(Tt_unique(:,1),'gauc');
bla2(i) = numel(Tt_unique.Var1(ix2));
end
toc
% passing logical directly
tic
bla3 = zeros(M,1);
for i = 1:1000
bla3(i) = numel(Tt_unique.Var1(strcmpi(Tt_unique(:,1),'gauc')));
end
toc
% Speed-up by sorting first?
tic
[ ~, ind_sort ] = sort(Tt.Var1);
Tt = Tt(ind_sort,:);
Tt_unique = unique(Tt,'rows');
toc
Result:
Elapsed time is 17.418828 seconds. % just applying unique
Elapsed time is 0.197103 seconds. % using strcmp
Elapsed time is 0.178446 seconds. % using strcmpi
Elapsed time is 0.177748 seconds. % not saving the logical
Elapsed time is 73.118320 seconds.
I have no idea was real genes look like, so your results might be different. :) As we can see, the main burden comes from "unique" though, unless your samples are also huge. Sorting your table as @Jan suggested sounds like a good idea, but seems to be extremely slow here. Maybe someone knows what the mistake is?
EDIT: There is actually no need for
ix_A = (strcmp(x.gene1(i),A.gene1) & strcmp(x.gene2(i),A.gene2));
Using
[ T_uniq, index, rev_index ] = unique(T(:,1:2),'rows');
You can now extract how often each element of T_uniq appears from rev_index, i.e. just check how often each rev_index is repeated. This integer count should be a lot faster than checking two strings.
2 comentarios
Ced
el 9 de Mzo. de 2016
Editada: Ced
el 9 de Mzo. de 2016
There might be, but I don't think cellfun & co would be the solution. They can be elegant because they allow to write more compact code. However, they are not always faster, since they generally have to loop internally as well, and on top of that may generate a significant overhead.
La pregunta está cerrada.
Ver también
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!