【问题标题】:matlab parse file into cell arraymatlab 将文件解析为元胞数组
【发布时间】:2014-02-25 18:20:09
【问题描述】:

我在matlab中有一个格式如下的文件:

user_id_a: (item_1,rating),(item_2,rating),...(item_n,rating)
user_id_b: (item_25,rating),(item_50,rating),...(item_x,rating)
....
....

所以每一行都有用冒号分隔的值,其中冒号左边的值是代表 user_id 的数字,右边的值是 item_ids(也是数字)和评级(数字不是浮点数)的元组。

我想将此数据读入 matlab 单元数组,或者更好地最终将其转换为稀疏矩阵,其中 user_id 表示行索引,item_id 表示列索引,并将相应的评分存储在该数组索引中。 (这会起作用,因为我事先知道我的宇宙中的用户和项目的数量,所以 id 不能大于那个)。

任何帮助将不胜感激。

到目前为止,我已经尝试了如下的 textscan 功能:

c = textscan(f,'%d %s','delimiter',':')   %this creates two cells one with all the user_ids
                                          %and another with all the remaining string values.

现在,如果我尝试执行str2mat(c{2}) 之类的操作,它可以工作,但它会将“(”和“)”字符也存储在矩阵中。我想以上述方式存储一个稀疏矩阵。

我对 matlab 还很陌生,如果能提供任何有关此问题的帮助,我将不胜感激。

【问题讨论】:

  • 每行的 (item,rating) 对的数量是固定的吗?
  • 不,它是可变的,但每个元组由逗号','分隔

标签: matlab file-io matrix textscan


【解决方案1】:
f = fopen('data.txt','rt'); %// data file. Open as text ('t')
str = textscan(f,'%s'); %// gives a cell which contains a cell array of strings
str = str{1}; %// cell array of strings
r = str(1:2:end);
r = cellfun(@(s) str2num(s(1:end-1)), r); %// rows; numeric vector
pairs = str(2:2:end); 
pairs = regexprep(pairs,'[(,)]',' ');
pairs = cellfun(@(s) str2num(s(1:end-1)), pairs, 'uni', 0);
%// pairs; cell array of numeric vectors
cols = cellfun(@(x) x(1:2:end), pairs, 'uni', 0);
%// columns; cell array of numeric vectors
vals = cellfun(@(x) x(2:2:end), pairs, 'uni', 0);
%// values; cell array of numeric vectors
rows = arrayfun(@(n) repmat(r(n),1,numel(cols{n})), 1:numel(r), 'uni', 0);
%// rows repeated to match cols; cell array of numeric vectors
matrix = sparse([rows{:}], [cols{:}], [vals{:}]);
%// concat rows, cols and vals into vectors and use as inputs to sparse

对于示例文件

1: (1,3),(2,4),(3,5)
10: (1,1),(2,2)

这给出了以下稀疏矩阵:

matrix =
   (1,1)        3
  (10,1)        1
   (1,2)        4
  (10,2)        2
   (1,3)        5

【讨论】:

    【解决方案2】:

    我认为较新版本的 Matlab 有一个 stringssplit 函数,这使得这种方法过度杀伤,但以下工作,如果不是很快。如您所示,它将文件拆分为用户 ID 和“其他内容”,初始化一个大的空矩阵,然后遍历其他内容,将其拆分并放置在矩阵中的正确位置。

    (由于某种原因,当我打开这个答案时,我没有看到上一个答案 - 它比这个更复杂,尽管这可能更容易理解,但会以缓慢为代价)。如果间距不一致,我会将\s* 放入正则表达式中,否则在数据完整性检查方面不会执行太多操作。输出是完整的数组,如果需要,您可以将其转换为稀疏数组。

    % matlab_test.txt:
    % 101: (1,42),(2,65),(5,0)
    % 102: (25,78),(50,12),(6,143),(2,123)
    % 103: (23,6),(56,3)
    
    clear all;
    fclose('all');
    % your path will vary, of course
    file = '<path>/matlab_test.txt';
    f = fopen(file);
    c = textscan(f,'%d %s','delimiter',':');
    celldisp(c)
    uids = c{1}
    tuples = c{2}
    
    % These are stated as known
    num_users = 3;
    num_items = 40;
    
    desired_array = zeros(num_users, num_items);
    expression = '\((\d+)\s*,\s*(\d+)\)'
    % Assuming length(tuples) == num_users for simplicity
    for k = 1:num_users
        uid = uids(k)
        tokens = regexp(tuples{k}, expression, 'tokens');
        for l = 1:length(tokens)
            item_id = str2num(tokens{l}{1})
            rating = str2num(tokens{l}{2})
            desired_array(uid, item_id) = rating;
        end
    end
    

    【讨论】: