2013-09-11 2 views
2

Фон: PC-Axis - формат файла, используемый для распространения статистической информации. Формат используется рядом национальных статистических организаций для распространения официальной статистики.Анализ файла PC-Axis (.px) в Matlab

Файл PC-Axis выглядит немного как это, хотя они, как правило, намного больше:

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, можно найти на Statistics Sweden website, но основная суть в том, что метаданные располагаются в верхней части файла и после того, как «DATA =» - это фактические данные. Также стоит отметить, что данные организованы скорее как таблица данных, а не столбцы.

Проблема: Я хотел бы проанализировать файл PC-Axis с помощью Matlab, но я немного зациклен на том, как это сделать. Кто-нибудь знает, как разобрать один из этих файлов в Matlab? Было бы проще проанализировать этот тип файла с помощью какого-либо другого языка, например Perl, а затем импортировать данные в Matlab или, может быть, Matlab будет достаточно подходящим инструментом для этой работы? Обратите внимание, что план будет состоять в анализе данных в Matlab после этапа обработки текста.

Я пробовал использовать инструменты обработки текста Matlab, такие как fgetl, textscan, fscanf и несколько других, но это ужасно сложно. Есть ли у кого-нибудь указания относительно того, как это сделать?

По существу, я хотел бы хранить каждое из ключевых слов (CHARSET, MATRIX и т. Д.) И их соответствующие значения (ANSI, BE001 и т. Д.) Как метаданные в Matlab - возможно, как структура. Я хотел бы также иметь данные, хранящиеся в Matlab, например, в качестве матрицы.

Примечание: Я знаю о pxR package (CRAN) в R, который работает лакомство для чтения .px файлов в рабочую область в качестве объекта data.frame. Там также есть модуль Perl с именем Data::PcAxis (CPAN), который тоже очень хорош, но я специально хочу знать, как разбирать .px-файл с помощью Matlab.

UPDATE: я должен отметить, что в дополнение к метаданных и данных, есть также переменные. Это лучше всего объясняется примером. Пример файла PC-Axis ниже совпадает с приведенным выше, за исключением того, что я добавил две переменные. Они называются VALUES («Месяц») и VALUES («область») и позиционируются после метаданных и до данных.

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 работает удовольствие при чтении каждой строки текстового файла в виде строки (в массиве ячеек). Однако элементы после знака «=» для обеих переменных (т. Е. VALUES («Месяц») и VALUES («region»)) охватывают более одной строки. Похоже, что использование textscan в этом случае означает, что некоторые строки должны быть объединены, скажем, например, чтобы собрать список месяцев (1976M01 по 1976M12).

Вопрос: Каков наилучший способ сбора данных переменных? Прочитайте текстовый файл как одну строку, а затем дважды используйте strtok для извлечения подстроки дат? Может быть, есть лучший (более систематический) способ?

+2

Я уверен, что Matlab достаточно, чтобы делать то, что вы хотите. Я бы дал ему уйти, а затем разместил ваши конкретные задачи. Например, попробуйте использовать textscan для анализа матрицы (см. Мой ответ ниже). Если вы столкнулись с трудностями, разместите свои конкретные текстовые вопросы. Удачи! –

ответ

2

Обычно textscan и regexp это путь при разборе строки поля (как показано here):

  1. Прочитайте входные строки как строки с textscan:

    fid = fopen('input.px', 'r'); 
    C = textscan(fid, '%s', 'Delimiter', '\n'); 
    fclose(fid); 
    
  2. Разбирает заголовок имена полей и значения с использованием regexp. Выбор правильного регулярного выражения должен сделать трюк!

    X = regexp(C{:}, '^\s*([^=\(\)]+)\s*=\s*"([^"]+)"\s*', 'tokens'); 
    X = [X{:}];       %// Flatten the cell array 
    X = reshape([X{:}], 2, []);   %// Reshape into name-value pairs 
    
  3. поле "значение" может охватывать более нескольких строк, поэтому они должны быть объединены первым:

    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])); 
    

    ...а затем лексемы:

    Y = regexp(Y, '"([^,"]+)"', 'tokens'); %// Tokenize values 
    Y = cellfun(@(x){{x{1}{1}, {[x{2:end}]}}}, Y); %// Group values in one array 
    Y = reshape([Y{:}], 2, []);    %// Reshape into name-value pairs 
    
  4. Убедитесь, что имена полей являются законными (я решил преобразовать все в нижний регистр и заменить апострофы и любой пробел с подчеркиванием), и подключить их в структуры:

    X = [X, Y];        %// Store all fields in one array 
    X(1, :) = lower(regexprep(X(1, :), '-+|\s+', '_')); 
    S = struct(X{:}); 
    

Вот что я получаю для входного файла (только поля заголовка):

S = 
      charset: 'ANSI' 
      matrix: 'BE001' 
    subject_code: 'BE' 
    subject_area: 'Population' 
      title: 'Population by region, time, marital status and sex.' 
      month: {1x12 cell} 
      region: {1x5 cell} 

Что касается самих данных, он должен быть обработан отдельно:

  1. линии Извлечение данных после поля «Данные» и заменить все ".." значения со значениями по умолчанию (например, NaN):

    D = strrep(C{:}(idx_data + 1:end), '".."', 'NaN'); 
    

    Очевидно, это предполагает, что после поля «Данные» есть только числовые данные. Однако это может быть легко изменено, если это не так.

  2. Преобразование данных в числовую матрицу и добавить его в структуру:

    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 

Надеется, что это помогает!

+1

Отличный ответ, Eitan T! Большое спасибо за Вашу помощь. Я смог изменить предлагаемый код, чтобы позаботиться о нескольких других вещах, о которых я не упоминал в моем первоначальном вопросе. Мне было интересно, можете ли вы предложить второй раунд помощи в отношении обновления, которое я сделал на этот вопрос. Если бы вы могли взглянуть, это было бы здорово. Ваша помощь очень ценится. –

+0

@GraemeWalsh Рад помочь. Как вы хотите, чтобы поле «values» интерпретировалось? То есть, как должно выглядеть соответствующее поле в результирующей структуре? –

+0

Спасибо, что вернулись ко мне, Эйтан. Возможно, что-то вроде следующего. S.month = 1976M01 1976M02 1976M03 1976M04 и т. Д. ... так, что выход является вектором/матрицей n x 1. Для S.region =, выход может быть либо n x 1, и 1 x n vector/matrix. –

1

Я лично не знаком с файлами PC-Axis, но вот мои мысли.

Сначала проанализируйте заголовок. Если заголовок имеет фиксированный размер, вы можете прочитать в этом количестве строк и проанализировать нужные значения. Для этого может быть полезным метод regexp.

Данные представляются как строковыми, так и числовыми. Я бы изменил значения «..» на NaN (сначала сделайте первоначальную резервную копию), а затем сканируйте матрицу с помощью textscan. Textscan может быть сложным, поэтому убедитесь, что файл полностью разбирается. Если textscan встречает строку, которая не соответствует строке формата, она прекратит разбор. Вы можете проверить позицию дескриптора файла (используя ftell), чтобы узнать, совпадает ли он с концом файла (вы можете fseek в конец файла, чтобы узнать, что это должно быть). Длина массивов ячеек, возвращаемых textscan, должна быть одинаковой. Если нет, длина сообщит вам, в какой строке они были сбой - вы можете проверить эту строку с помощью текстового редактора, чтобы увидеть, что нарушает формат.

Вы можете назначать и получать доступ к полям в структурах Matlab, используя строковые аргументы. Например:

foo.('a') = 1; 
foo.a 
ans = 
    1 

Таким образом, рабочий процесс я предлагаю разобрать строки заголовка, назначение каждого атрибута/значение пары в качестве пара поля/значения в структурах. Затем проанализируйте матрицу (после некоторой кратковременной предварительной обработки текста, чтобы убедиться, что все данные являются числовыми).

+0

Отличный ответ, Гордон Бин. Спасибо за помощь. Я хотел бы спросить вас, знаете ли вы, что нужно разобрать «переменные», о которых я упоминаю в «Обновлении», которое я сделал по моему вопросу. Любой совет, который вы можете дать, будет с благодарностью. –

Смежные вопросы