Эффективный импорт полуструктурированного текста - PullRequest
0 голосов
/ 08 июня 2018

У меня есть несколько текстовых файлов, сохраненных из системы картографирования давления Tekscan.Я пытаюсь найти наиболее эффективный способ импорта матриц с несколькими запятыми в одну трехмерную матрицу типа uint8.Я разработал решение, которое делает повторные вызовы функции MATLAB dlmread.К сожалению, для импорта данных требуется примерно 1,5 минуты.Я включил код ниже.

Этот код вызывает две другие функции, которые я написал: metaextract и framecount, которые я не включил, поскольку они не имеют отношения к ответу на рассматриваемый вопрос.

Здесьдве ссылки на образцы файлов, которые я использую.

Первый - более короткий файл с 90 выборками

Второй - более длинный файл с 3458образцы

Любая помощь будет оценена

function pressureData = tekscanimport
% Import TekScan data from .asf file to 3d matrix of type double.

[id,path] = uigetfile('*.asf'); %User input for .asf file
if path == 0 %uigetfile returns zero on cancel
    error('You must select a file to continue')
end

path = strcat(path,id); %Concatenate path and id to full path

% function calls
pressureData.metaData = metaextract(path);
nLines = linecount(path); %Find number of lines in file
nFrames = framecount(path,nLines);%Find number of frames

rowStart = 25; %Default starting row to read from tekscan .asf file
rowEnd = rowStart + 41; %Frames are 42 rows long
colStart = 0;%Default starting col to read from tekscan .asf file
colEnd = 47;%Frames are 48 rows long
pressureData.frames = zeros([42,48,nFrames],'uint8');%Preallocate for speed

f = waitbar(0,'1','Name','loading Data...',...
    'CreateCancelBtn','setappdata(gcbf,''canceling'',1)');
setappdata(f,'canceling',0);

for i = 1:nFrames %Loop through file skipping frame metadata
    if getappdata(f,'canceling')
        break
    end
    waitbar(i/nFrames,f,sprintf('Loaded %.2f%%', i/nFrames*100));

    %Make repeated calls to dlmread
    pressureData.frames(:,:,i) = dlmread(path,',',[rowStart,colStart,rowEnd,colEnd]);
    rowStart = rowStart + 44;
    rowEnd = rowStart + 41;
end
delete(f)
end

1 Ответ

0 голосов
/ 08 июня 2018

Я попробовал.Этот код открывает ваш большой файл за 3,6 секунды на моем ПК.Хитрость заключается в том, чтобы использовать sscanf вместо функций str2double и str2number.

clear all;tic
fid = fopen('tekscanlarge.txt','rt');
%read the header, stop at frame
header='';
l = fgetl(fid);
while length(l)>5&&~strcmp(l(1:5),'Frame')
    header=[header,l,sprintf('\n')];
    l = fgetl(fid);
    if length(l)<5,l(end+1:5)=' ';end
end
%all data at once
dat = fread(fid,inf,'*char');
fclose(fid);
%allocate space
res = zeros([48,42,3458],'uint8');
%get all line endings
LE = [0,regexp(dat','\n')];
i=1;
for ct = 2:length(LE)-1 %go line by line
    L = dat(LE(ct-1)+1:LE(ct)-1);
    if isempty(L),continue;end
    if all(L(1:5)==['Frame']')
        fr = sscanf(L(7:end),'%u');
        i=1;
        continue;
    end
    % sscan can only handle row-char with space seperation.
    res(:,i,fr) = uint8(sscanf(strrep(L',',',' '),'%u'));
    i=i+1;
end
toc

Кто-нибудь знает более быстрый способ конвертации, чем sscanf?Потому что он тратит большую часть времени на эту функцию (2,17 секунды).Для набора данных объемом 13,1 МБ я нахожу это очень медленным по сравнению со скоростью памяти.

Нашел способ сделать это за 0,2 секунды, что может быть полезно и для других.Этот mex-файл просматривает список значений символов для чисел и сообщает о них.Сохраните его как mexscan.c и запустите mex mexscan.c.

#include "mex.h" 
/* The computational routine */
void calc(unsigned char *in, unsigned char *out, long Sout, long Sin)
{
    long ct = 0;
    int newnumber=0; 
    for (int i=0;i<Sin;i+=2){
        if (in[i]>=48 && in[i]<=57) { //it is a number
            out[ct]=out[ct]*10+in[i]-48;
            newnumber=1;
        } else { //it is not a number
            if (newnumber==1){
                ct++;
                if (ct>Sout){return;}
            }
            newnumber=0;
        }
    }    
}

/* The gateway function */
void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    unsigned char *in;             /* input vector */
    long Sout;                     /* input size of output vector */
    long Sin;                      /* size of input vector */
    unsigned char *out;            /* output vector*/

    /* check for proper number of arguments */
    if(nrhs!=2) {
        mexErrMsgIdAndTxt("MyToolbox:arrayProduct:nrhs","two input required.");
    }
    if(nlhs!=1) {
        mexErrMsgIdAndTxt("MyToolbox:arrayProduct:nlhs","One output required.");
    }
    /* make sure the first input argument is type char */
    if(!mxIsClass(prhs[0], "char"))  {
        mexErrMsgIdAndTxt("MyToolbox:arrayProduct:notDouble","Input matrix must be type char.");
    }
    /* make sure the second input argument is type uint32 */
    if(!mxIsClass(prhs[0], "char"))  {
        mexErrMsgIdAndTxt("MyToolbox:arrayProduct:notDouble","Input matrix must be type char.");
    }

    /* get dimensions of the input matrix */
    Sin = mxGetM(prhs[0])*2;
    /* create a pointer to the real data in the input matrix  */
    in = (unsigned char *) mxGetPr(prhs[0]);
    Sout = mxGetScalar(prhs[1]);

    /* create the output matrix */
    plhs[0] = mxCreateNumericMatrix(1,Sout,mxUINT8_CLASS,0);

    /* get a pointer to the real data in the output matrix */
    out = (unsigned char *) mxGetPr(plhs[0]);

    /* call the computational routine */
    calc(in,out,Sout,Sin);
}

Теперь этот скрипт выполняется за 0,2 секунды и возвращает тот же результат, что и предыдущий скрипт.

clear all;tic
fid = fopen('tekscanlarge.txt','rt');
%read the header, stop at frame
header='';
l = fgetl(fid);
while length(l)>5&&~strcmp(l(1:5),'Frame')
    header=[header,l,sprintf('\n')];
    l = fgetl(fid);
    if length(l)<5,l(end+1:5)=' ';end
end
%all data at once
dat = fread(fid,inf,'*char');
fclose(fid);
S=[48,42,3458];
d = mexscan(dat,uint32(prod(S)+3458));
d(1:prod(S(1:2))+1:end)=[];%remove frame numbers
d = reshape(d,S);
toc
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...