【问题标题】:Cannot import all values at once in Matlab using TextScan无法使用 TextScan 在 Matlab 中一次导入所有值
【发布时间】:2013-10-18 20:05:25
【问题描述】:

我有一个包含 1911518 个值的数据集。我已经使用了 textscan 功能。但该函数仅返回 1424458 个值。我再次创建了一个新变量来获取剩余的值,但这次它给了我大约 9000 个值。有谁知道这是什么原因?

n=9
N=1911518

file_id=fopen('CRSP.csv');

C=textscan(file_id,'%s',n,'delimiter', ','); %To get the headers
C_text=textscan(file_id,'%s %s %s %d %d %d %d %f %f',N, 'delimiter' , ','); 

%Returns 1424458

C_text1=textscan(file_id,'%s %s %s %d %d %d %d %f %f',N, 'delimiter' , ','); 

%Returns only 9000 values    

fclose(file_id);

样本数据

DATE,COMNAM,TICKER,PERMNO,PERMCO,SHROUT,VOL,RET,sprtrn

01/02/1996, ACME CLEVELAND CORP NEW, AMT, 10057, 20020, 6313, 23700,  0.000000,  0.007793
01/03/1996, ACME CLEVELAND CORP NEW, AMT, 10057, 20020, 6313, 20800,  0.020000,  0.000950
01/04/1996, ACME CLEVELAND CORP NEW, AMT, 10057, 20020, 6313, 65300, -0.026144, -0.005826
01/05/1996, ACME CLEVELAND CORP NEW, AMT, 10057, 20020, 6313, 340600, 0.000000, -0.001587
01/08/1996, ACME CLEVELAND CORP NEW, AMT, 10057, 20020, 6313, 3400,   0.000000,  0.002821
01/09/1996, ACME CLEVELAND CORP NEW, AMT, 10057, 20020, 6313, 27200, -0.006711, -0.014568
01/10/1996, ACME CLEVELAND CORP NEW, AMT, 10057, 20020, 6313, 25400, -0.033784, -0.018000
01/11/1996, ACME CLEVELAND CORP NEW, AMT, 10057, 20020, 6313, 14000,  0.000000,  0.007034

【问题讨论】:

  • 你需要提供一些示例数据,否则很难帮助你;)
  • 我不知道上面的例子能提供多少帮助:P
  • 如果换行符没有丢失会有所帮助。请编辑您的问题并将数据和代码添加为“代码示例”。这将保留所有线刹车。

标签: matlab csv import textscan


【解决方案1】:

我会假设,数据中有一些错误,或者格式模式与数据不匹配。尝试提取这些行:

file_id=fopen('CRSP.csv');
for idx=1:1424456
    fgetl(file_id); %dump data
end
for idx=1:10
    fprintf('%s\n',fgetl(file_id));
end

如果有错误,应该在第 2 或第 3 行打印。那里有什么特别的吗?也许是带有特殊字符的COMNAM

要读取文件,我会使用以下代码逐行读取:

file_id=fopen('CRSP.csv');
line=fgetl(file_id);
data={};
int ix=1;
while(ischar(line))
    [parsed,sindex,eindex] = regexpi(line,'(\d\d/\d\d/\d\d\d\d)\s*, ([\w ]+), ([\w ]+), ([\d]+), ([\d]+), ([\d]+), ([\d]+), ([\d \.]+), ([\d \.]+)','tokens')
    if ~isempty(sindex)&&numel(sindex)==1&&(sindex==1)&&(eindex==numel(x))
        data{end+1}=parsed{1};
    else
        fprintf('Unable to parse line %d with content: %S',ix,line);
    end
    line=fgetl(file_id);
    ix=ix+1;
end

正则表达式的简短总结:

'(...)' 之间的所有内容都是返回的“令牌”

'([\d .]+)' 数字、空格和“.”

'([\d .]+)' 数字和空格

'([\w ]+)' 单词,包括空格

'(\d\d/\d\d/\d\d\d\d)'日期

这个表达式有点“懒惰”。它不仅接受“0.000”作为数字,还接受“0.0 00”。或其他一些组合,但应该足以检测所有错误。如果不是,则表达式必须改进。

【讨论】:

  • 您是对的,数据中的某些值存在错误。例如sprrtn,有字符串值。但我的想法是将所有值提取到 matlab 中,然后检查 NA 或 infs
  • 现在我发现有错误值,如何在不破坏顺序的情况下删除它们并存储剩余值
  • 我更新了我的答案。使用 textscan 可能还有一个更简单的解决方案,但我只是习惯于正则表达式。
  • 我有点理解代码。现在,如果满足 IF 条件,我不需要做任何事情。但是我现在如何在 ELSE 条件下完全删除列??
  • 我添加了一些额外的行,解决方案的外观。为了读取文件,我基本上使用了这里的示例代码:mathworks.de/de/help/matlab/ref/fgets.html 最后数据应该包含整个有效数据,并且应该打印每个损坏的数据。
【解决方案2】:

Daniel R 的回答基本正确。详细说明(我会将此作为评论发布,但我缺乏声誉),MATLAB 中的textscan 非常挑剔,只要遇到与您指定的格式不完全匹配的内容,它就会自动退出。

如果您的数据文件可能包含一些错误或不一致,您的主要选择是以某种方式预处理文件以删除这些错误,或者(如 Daniel 建议的那样)逐行读取文件 -行并根据需要进行解析。前者的工作量可能与后者差不多,除非您打算手动完成并且没有太多需要修复的错误,因此在大多数情况下,编写自己的解析器可能更容易。

您唯一可能做的另一件事-如果唯一的错误是类型错误(例如,列应该是整数,但有时会出现浮点数),您仍然可以使用 textscan 并替换格式具有更通用的说明符。例如,在该示例中,您可以将 %d(整数)替换为 %f(浮点数)。由于所有整数都是浮点数,因此应该可以正常工作。在最极端的情况下,您可以将所有列读取为字符串 (%s),但无论如何您都需要解析它们,而且您最好在没有 textscan 的情况下这样做。

【讨论】:

  • 如何删除错误。你能帮我解释一下如何去掉有错误的列吗