如何在Octave中高效读取来自CSV的大矩阵

5

有很多关于Octave的dlmread性能缓慢的报告。我曾希望这个问题在3.2.4中得到解决,但当我尝试加载一个大约8*4百万(总共32百万)大小的CSV文件时,它也需要非常长的时间。我在网上搜索,但找不到解决方法。是否有人知道一个好的解决方法?


你所说的“大约8*4毫米大小”,是指矩阵有3200万个条目,还是具有800万乘以400万的尺寸? - Woltan
@Woltan:总共3200万。抱歉没有表达清楚。 - Enno Shioji
3个回答

3

我曾经遇到过同样的问题,而且我会使用R语言,所以我的解决方案是使用R中的"read.csv"函数,然后使用R包"R.matlab"来写入一个".mat"文件,最后在Octave中加载这个文件。

"read.csv"也可能会很慢,但在我的情况下这个方法非常有效。


你的机器内存大小是多少?我有一个一千万条目的数据库,我想知道什么更好,R、Octave还是其他程序?我的电脑有4GB内存。如果我能使用R,那就太棒了... - Manoel Galdino

2
原因是Octave存在一个bug,向非常大的矩阵添加数据所需的时间比向小矩阵添加相同数量的数据需要更长的时间。
以下是我的尝试。我选择每50000行保存一次数据,这样同时我就可以先看一下数据而不必被迫等待。对于小文件来说速度较慢,但对于大文件来说速度要快得多。
function alldata = load_data(filename)
    fid = fopen(filename,'r');
    s=0;
    data=[];
    alldata=[];
    save "temp.mat" alldata;
    if fid == -1
        disp("Couldn't find file mydata");
    else
        while (~feof(fid))
            line = fgetl(fid);
            [t1,t2,t3,t4,d] = sscanf(line,'%i:%i:%i:%i %f', "C"); #reading time as hh:mm:ss:ms and data as float
            s++;
            t = (t1 * 3600000 + t2 * 60000 + t3 * 1000 + t4);
            data = [data; t, d];
            if (mod(s,10000) == 0)
                #disp(s), disp("  "), disp(t), disp("  "), disp(d), disp("\n");
                disp(s);
                fflush(stdout);
            end
            if (mod(s,50000) == 0)
                load "temp.mat";
                alldata=[alldata; data];
                data=[];
                save "temp.mat" alldata;
                disp("data saved");
                fflush(stdout);
            end
        end
        disp(s);
        load "temp.mat";
        alldata=[alldata; data];
        save "temp.mat" alldata;
        disp("data saved");
        fflush(stdout); 
    end
    fclose(fid);

1

这里是我正在使用的解决方法。

我发现sscanf不会像上面所示那样解析输入行。此外,我没有使用临时文件。

我的.csv文件有大量的行。它们以18行的标题开头,然后是一个数据块,每个块有135列。以下代码已经过测试。我的文件还以dd/mm/yyyy hh:mm字段开始每一行。这也将通过使用try/catch捕获错误的行并指出它们的位置。

我的.csv文件来自一个客户,他将PARCView负载转储到Excel文件中。

function [tags,descr,alldata] = fbcsvread(filename)
  fid = fopen(filename,'r');
  s = 0;
  data=[];
  alldata=zeros(1,135);
  if fid==-1
    disp("Couldn't find file %s\n",filename);
  else
    linecount = 1;
    while (~feof(fid))
      line = fgetl(fid);
      data2 = zeros(1,135);
      if linecount == 1
    tags = strsplit(line,",");
      elseif linecount == 2
    descr = strsplit(line,",");
      elseif linecount >= 19
    data = strsplit(line,",");
    datetime = strsplit(char(data(1))," ");
    modyyr = strsplit(char(datetime(1)),"/");
    hrmin = strsplit(char(datetime(2)),":");
    year1 = sscanf(char(modyyr(3)),"%d","C");
    day1 = sscanf(char(modyyr(2)),"%d","C");
    month1 = sscanf(char(modyyr(1)),"%d","C");
    hour1 = sscanf(char(hrmin(1)),"%d","C");
    minute1 = sscanf(char(hrmin(2)),"%d","C");
    realtime = datenum(year1,month1,day1,hour1,minute1);
    data2(1) = realtime;
    for location = 2:134
      try
        data2(location) = sscanf(char(data(location)),"%f","C");
      catch
        printf("Error at %s %s\n",char(datetime(1)),char(datetime(2)) );
        fflush(stdout);
      end_try_catch
    endfor
    alldata(linecount-18,:) = data2;
    if mod(linecount,50) == 0
      printf(".");
      fflush(stdout);
    endif
      endif
      linecount = linecount + 1;
    endwhile
    fclose(fid);
  endif
endfunction

我应该补充一下,在我编写并执行上面的代码的时间里,csvread在另一个窗口中启动了两个小时,但仍未返回。 - JohnS

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接