Efficiently convert cell to double

Hi, I have a cell array of strings ("position") and need to convert the first cell column into a vector of doubles ("pointX"). The following loop works as intended, but takes a very long time. Is there a more efficient way to accomplish the same goal? Thank you.
parfor j = 1:length(position)
pointX(j,1) = str2num(cell2mat(position{j,1}(1)));
end

댓글 수: 6

Jan
Jan 2012년 5월 22일
If "position" is really a cell string, "cell2mat(position{j,1}(1))" fails, because "position{j,1}(1)" is the first character of the first string, such that CELL2MAT does not get a cell as input.
John
John 2012년 5월 23일
The variable "position" is actually a cell array, having dimension 6000 x 1 cell. Each cell in that column is a 3x1 consisting of 3 strings that give x, y, z coordinate strings. What I need to do is step into position{1,1} which is then a 3x1 cell array and convert the entire string in (1,1) to a double. Then repeat down the position column until position{6000,1}(1). The desired result is a 6000x1 vector of doubles that represents all the X points.
Oleg Komarov
Oleg Komarov 2012년 5월 23일
Shouldn't you get then a 6000 by 3 matrix where the columns are respectively the x,y,z?
John
John 2012년 5월 23일
What I would really like to do is:
pointX = str2double(position{:,1}(1));
but it gives me a "bad cell reference" error.
Oleg Komarov
Oleg Komarov 2012년 5월 23일
You cannot do that.
You can try to change the problem at the core, e.g. by importing a file in a different way or by changing the routine that generates the cell, or you have to manipulate the cell array.
Jan
Jan 2012년 5월 24일
@John, reading the textual description is still complictaed. It would reduce the chance of misunderstanding, if you post the Matlab code to create the test data and the wanted result, e.g.
position = {{'21', '34.5', '-17'}, {'324', '1e-19', '15'}}
result = [21, 324]
3 contributors tried to guess as good as they can, but there is a large chance, that we have wasted half an hour, because we did not understand the problem completely.

댓글을 달려면 로그인하십시오.

답변 (3개)

Jan
Jan 2012년 5월 22일

6 개 추천

[EDITED: THIS DOES NOT MEET YOUR DEMANDS] Sorry, due to a missing example, I've overseen the fact, that you need the first column only. Before I guess to much around, could you please add some example values by editing the original question?
str2double is slow. sscanf is fast:
c = cell(1, 10000); % Create test data
for i = 1:numel(c)
c{i} = sprintf('%d', floor(rand*1000));
end
tic;
v1 = str2double(c);
toc
tic;
S = sprintf('%s*', c{:});
v2 = sscanf(S, '%d*');
toc
Elapsed time is 0.411949 seconds. (Matlab 2009a/64 Win7.)
Elapsed time is 0.013777 seconds.
But sprintf cannot pre-allocate sufficiently, such that a dedicated MEX-function for concatenating cell elements beat this, see FEX: CStr2String:
tic;
S = CStr2String(c, '*');
v2 = sscanf(S, '%d*');
toc
Elapsed time is 0.005835 seconds.
71 times faster. To my deep surprise calling SSCANF inside the MEX directly is not faster, although it avoids the expensive allocation of the large string, see e.g. FEX: String to double. Therefore I'd rely either on the pure Matlab sscanf(sprint()) or use CStr2String in addition.

댓글 수: 4

dzid_
dzid_ 2019년 3월 19일
This only works with integers
madhan ravi
madhan ravi 2019년 3월 19일
@dzid: read about sscanf() in the documentation
MacMilan ZHANG
MacMilan ZHANG 2022년 3월 15일
Amazing speed up sscanf

댓글을 달려면 로그인하십시오.

Sean de Wolski
Sean de Wolski 2012년 5월 22일

1 개 추천

str2double() will be faster than str2num()
Also, could probably skip the parfor loop altogether and just call str2double() on the cell array of strings:
str2double({'3';'45'})
Oleg Komarov
Oleg Komarov 2012년 5월 23일

0 개 추천

To address the OP comments:
Suppose you have this fake input (6000 by 1 cell array where each cell is a 1 by 3 cellstring):
position = repmat({{'23','43','120'}},6000,1);
tic
% Manipulate into 6000 by 3
position = cat(1,position{:,1});
% Use str2double
position = str2double(position);
toc
Elapsed time is 0.754681 seconds.
If you want to achieve results faster, consider Jan's suggestions.

댓글 수: 6

Jan
Jan 2012년 5월 24일
I guess, that this is wanted:
positionM = cat(1, position{:, 1});
Btw, the JIT profits from variable not changing their type. Therefore I avoid reusing of names in general, but this can increase the memory footprint.
Sean de Wolski
Sean de Wolski 2012년 5월 24일
@Jan:
function jitxtype
t1 = 0;
t2 = 0;
for ii = 1:1000;
A = rand(1000);
tic
B = uint8(A);
t1 = t1+toc;
tic
A = uint8(A);
t2 = t2+toc;
end
[t1 t2]
That is signifanct.
Jan
Jan 2012년 5월 24일
@Sean: Please add the timings you get and the Matlab version. I'm not at my Matlab machine currently.
Oleg Komarov
Oleg Komarov 2012년 5월 24일
win64 R2012a
ans =
0.0054 5.7938
I also added pause(0.01) before each tic.
Jan
Jan 2012년 5월 24일
I'd dare to call it "significant" also.
Daniel Shub
Daniel Shub 2012년 5월 24일
With Oleg's pause on 64-bit Linux with R2011a I get:
0.6394 6.1356

댓글을 달려면 로그인하십시오.

카테고리

도움말 센터File Exchange에서 Loops and Conditional Statements에 대해 자세히 알아보기

태그

질문:

2012년 5월 22일

댓글:

2022년 3월 15일

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by