anonuser0428
anonuser0428

Reputation: 12343

matlab parse file into cell array

I have a file in the following format in 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)
....
....

so each line has values separated by a colon where the value to the left of the colon is a number representing user_id and the values to the right are tuples of item_ids (also numbers) and rating (numbers not floats).

I would like to read this data into a matlab cell array or better yet ultimately convert it into a sparse matrix wherein the user_id represents the row index, and the item_id represents the column index and store the corresponding rating in that array index. (This would work as I know a-priori the number of users and items in my universe so ids cannot be greater than that ).

Any help would be appreciated.

I have thus far tried the textscan function as follows:

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

Now if I try to do something like str2mat(c{2}), it works but it stores the '(' and ')' characters also in the matrix. I would like to store a sparse matrix in the fashion that I described above.

I am fairly new to matlab and would appreciate any help regarding this matter.

Upvotes: 3

Views: 353

Answers (2)

schodge
schodge

Reputation: 901

I think newer versions of Matlab have a stringsplit function that makes this approach overkill, but the following works, if not quickly. It splits the file into userid's and "other stuff" as you show, initializes a large empty matrix, and then iterates through the other stuff, breaking it apart and placing in the correct place in the matrix.

(I Didn't see the previous answer when I opened this for some reason - it is more sophisticated than this one, though this may be a little easier to follow at the expense of slowness). I throw in the \s* into the regex in case the spacing is inconsistent, but otherwise don't perform much in the way of data-sanity-checking. Output is the full array, that you can then turn into a sparse array if desired.

% 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

Upvotes: 0

Luis Mendo
Luis Mendo

Reputation: 112659

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

For the example file

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

this gives the following sparse matrix:

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

Upvotes: 1

Related Questions