在Matlab中解析PC轴(.px)文件
背景:PC Axis是一种用于传播统计信息的文件格式。许多国家统计组织使用该格式传播官方统计数据 PC Axis文件看起来有点像这样,尽管它们通常要长得多:在Matlab中解析PC轴(.px)文件,matlab,text-parsing,Matlab,Text Parsing,背景:PC Axis是一种用于传播统计信息的文件格式。许多国家统计组织使用该格式传播官方统计数据 PC Axis文件看起来有点像这样,尽管它们通常要长得多: CHARSET=”ANSI”; MATRIX="BE001"; SUBJECT-CODE="BE"; SUBJECT-AREA="Population"; TITLE="Population by region, time, marital status and sex."; Data= ".." ".." ".." ".." ".."
CHARSET=”ANSI”;
MATRIX="BE001";
SUBJECT-CODE="BE";
SUBJECT-AREA="Population";
TITLE="Population by region, time, marital status and sex.";
Data=
".." ".." ".." ".." ".."
".." ".." ".." ".." ".."
".." 24.80 34.20 52.00 23.00
".." 32.10 40.30 50.70 1.00
".." 31.60 35.00 49.10 2.30
41.20 43.00 50.80 60.10 0.00
50.90 52.00 53.90 65.90 0.00
28.90 31.80 39.60 51.00 0.00;
有关PC Axis文件的更多详细信息可以在中找到,但基本要点是元数据位于文件的顶部,在“DATA=”之后是实际数据本身。还值得注意的是,数据的组织更像是一个数据表,而不是列
问题:我想用Matlab解析PC Axis文件,但我有点困惑,不知道该怎么做。有人知道如何在Matlab中解析这些文件吗?使用其他语言(如Perl)解析这种类型的文件,然后将数据导入Matlab会更容易吗?或者,Matlab是一个足够适合这项工作的工具吗?注意,计划是在文本处理阶段之后在Matlab中分析数据
我尝试过使用Matlab的文本处理工具,如fgetl、textscan、fscanf和其他一些工具,但这非常棘手。有人对如何着手做这件事有什么建议吗
本质上,我希望将每个关键字(字符集、矩阵等)及其对应的值(ANSI、BE001等)作为元数据存储在Matlab中——也许是作为一种结构。我也希望将数据存储在Matlab中,例如,作为矩阵
注意:我知道in R,它将.px文件作为data.frame对象读入工作区。还有一个叫做Perl的模块,它也很好,但我特别想知道如何使用Matlab解析.px文件
更新:我应该提到,除了元数据和数据之外,还有变量。这最好用一个例子来解释。下面的示例PC Axis文件与上面的相同,只是我添加了两个变量。它们被命名为值(“月”)和值(“区域”),位于元数据之后和数据之前
CHARSET=”ANSI”;
MATRIX="BE001";
SUBJECT-CODE="BE";
SUBJECT-AREA="Population";
TITLE="Population by region, time, marital status and sex.";
VALUES("Month")="1976M01","1976M02","1976M03","1976M04",
"1976M05","1976M06","1976M07","1976M08",
"1976M09","1976M10","1976M11","1976M12";
VALUES("region")="Sweden","Germany","France",
"Ireland","Finland";
Data=
".." ".." ".." ".." ".."
".." ".." ".." ".." ".."
".." 24.80 34.20 52.00 23.00
".." 32.10 40.30 50.70 1.00
".." 31.60 35.00 49.10 2.30
41.20 43.00 50.80 60.10 0.00
50.90 52.00 53.90 65.90 0.00
28.90 31.80 39.60 51.00 0.00;
当以字符串形式(在单元格数组中)读取文本文件的每一行时,Textscan起到了处理作用。但是,两个变量(即值(“月”)和值(“区域”)的“=”符号后的元素跨越多行。在本例中使用textscan似乎意味着必须连接一些字符串,例如,为了收集月份列表(1976M01到1976M12)
问题:收集变量数据的最佳方式是什么?将文本文件作为单个字符串读取,然后使用strtok两次提取日期的子字符串?也许有更好的(更系统的)方法?我个人对PC Axis文件并不熟悉,但以下是我的想法 首先解析头。如果标题大小固定,那么可以读入那么多行并解析出所需的值。regexp方法对此可能很有用 数据似乎是字符串和数字。我会将“.”值更改为NaN(当然,首先进行原始备份),然后使用textscan扫描矩阵。Textscan可能很棘手,因此请确保文件完全解析。如果textscan遇到与格式字符串不匹配的行,它将停止解析。您可以检查文件句柄的位置(使用ftell)以查看它是否与文件结尾匹配(您可以fseek到文件结尾以查找该值应该是什么)。textscan返回的单元格数组的长度应该都相同。如果没有,则长度将告诉您哪一行失败-您可以使用文本编辑器检查这一行,查看哪一行违反了格式 可以使用字符串参数指定和访问Matlab结构中的字段。例如:
foo.('a') = 1;
foo.a
ans =
1
因此,我建议的工作流程是解析标题行,将每个属性/值对指定为struct中的字段/值对。然后解析矩阵(经过一些简短的文本预处理以确保所有数据都是数字)。通常
textscan
和regexp
是解析字符串字段的方法(如图所示):
textscan
以字符串形式读取输入行:
fid = fopen('input.px', 'r');
C = textscan(fid, '%s', 'Delimiter', '\n');
fclose(fid);
regexp
解析标题字段名称和值。选择正确的正则表达式应该可以做到这一点
X = regexp(C{:}, '^\s*([^=\(\)]+)\s*=\s*"([^"]+)"\s*', 'tokens');
X = [X{:}]; %// Flatten the cell array
X = reshape([X{:}], 2, []); %// Reshape into name-value pairs
idx_data = find(~cellfun('isempty', regexp(C{:}, '^\s*Data')), 1);
idx_values = find(~cellfun('isempty', regexp(C{:}, '^\s*VALUES')));
Y = arrayfun(@(m, n){[C{:}{m:m + n - 1}]}, ...
idx_values(idx_values < idx_data), diff([idx_values; idx_data]));
X = [X, Y]; %// Store all fields in one array
X(1, :) = lower(regexprep(X(1, :), '-+|\s+', '_'));
S = struct(X{:});
。“
值(例如,NaN
):
显然,这假设在“数据”字段之后只有数字数据。但是,如果情况并非如此,则可以很容易地修改此项D = cellfun(@str2num, D, 'UniformOutput', false);
S.data = vertcat(D{:})
s.data
:
S.data =
NaN NaN NaN NaN NaN
NaN NaN NaN NaN NaN
NaN 24.80000 34.20000 52.00000 23.00000
NaN 32.10000 40.30000 50.70000 1.00000
NaN 31.60000 35.00000 49.10000 2.30000
41.20000 43.00000 50.80000 60.10000 0.00000
50.90000 52.00000 53.90000 65.90000 0.00000
希望这有帮助 我很确定Matlab足以满足您的需要。我会试一试,然后发布你的具体挑战。例如,尝试使用textscan解析矩阵(请参阅下面的答案)。如果你遇到麻烦,发布你的特定文本扫描问题。祝你好运回答得很好,伊坦T!非常感谢你的帮助。我已经能够修改您建议的代码来处理一些我在最初的问题中没有提到的其他事情。我想知道你是否可以就我对这个问题的更新提供第二轮帮助。如果你能看一下,那就太好了。非常感谢你的帮助
D = strrep(C{:}(idx_data + 1:end), '".."', 'NaN');
D = cellfun(@str2num, D, 'UniformOutput', false);
S.data = vertcat(D{:})
S.data =
NaN NaN NaN NaN NaN
NaN NaN NaN NaN NaN
NaN 24.80000 34.20000 52.00000 23.00000
NaN 32.10000 40.30000 50.70000 1.00000
NaN 31.60000 35.00000 49.10000 2.30000
41.20000 43.00000 50.80000 60.10000 0.00000
50.90000 52.00000 53.90000 65.90000 0.00000