Reading data file with rows of variable sizes - matlab

I have a data file containing rows of variable sizes:
16 54 1 -3 5
15 5
1 9 10 5
How can I load it into a cell array data so that
data{1} = [16 54 1 -3 5];
data{2} = [15 5];
data{3} = [1 9 10 5];
?

Let data.txt contains
16 54 1 -3 5
15 5
1 9 10 5
You can read it into a cell array data with the following:
fid = fopen('datatest.txt');
allData = textscan(fid,'%s','Delimiter','\n');
data = cellfun(#str2num, allData{1}, 'UniformOutput', false);
fclose(fid);
>> data =
ans =
[1x5 double]
[1x2 double]
[1x4 double]
>> data{1}
ans =
16 54 1 -3 5

You can try impordata appproach that is short and concise -
%// Assuming filepath1 is the path to your file
data = cellfun(#str2num,importdata(filepath1,'%s'),'uni',0)
You can visualize the data, using celldisp tool that displays contents of a cell array, like this - celldisp(data). The output would be -
data{1} =
16 54 1 -3 5
data{2} =
15 5
data{3} =
1 9 10 5

Related

Replace one element of a column in another

Let A and B be column vectors:
A = (1:6).'; %'// [1;2;3;4;5;6]
B = (7:12).'; %'// [7;8;9;10;11;12]
How do I construct a matrix such that one element of A is replaced each time by an element from B to get C as:
C = [...
7 1 1 1 1 1
2 8 2 2 2 2
3 3 9 3 3 3
4 4 4 10 4 4
5 5 5 5 11 5
6 6 6 6 6 12];
If C is to be indexed as index = [1 1 1 2 2 3 3]', how is it possible to produce
c1 = [...
1 7 1 1
1 2 8 2
1 3 3 9];
c2 = [...
2 10 4
2 5 11];
c3 = [3 6]; %// either this
c3 = [3 12]; %// or this
Problem #1:
C = bsxfun(#plus,A.',-diag(A)+diag(B));
gives:
7 2 3 4 5 6
1 8 3 4 5 6
1 2 9 4 5 6
1 2 3 10 5 6
1 2 3 4 11 6
1 2 3 4 5 12
Problem #2:
As far as I understand, you want to extract blocks out of the previously found C matrix, in the following fashion:
Where c1, c2, c3 are the green, red and blue blocks, repectively; and "missing" elements are replaced with NaN (in the initial version of your question).
index = [1 1 1 2 2 3 3]; %// Block definition
[blkSz,~] = histcounts(index,numel(unique(index))); %// Conversion...
paddedC = padarray(C,numel(index)-numel(diag(C))*[1 1],NaN,'post');
blocks = mat2cell(paddedC,blkSz,blkSz);
This results in a cell-array blocks with the following contents:
blocks =
[3x3 double] [3x2 double] [3x2 double]
[2x3 double] [2x2 double] [2x2 double]
[2x3 double] [2x2 double] [2x2 double]
Where for example blocks{1,1} is:
ans =
7 2 3
1 8 3
1 2 9
Then you can pad the array using the index of the loop, to get the c cell, like so:
c = cell(numel(blkSz),1); %// Preallocation
for ind1 = 1:numel(blkSz)
c{ind1} = padarray(blocks{ind1,ind1},1,ind1,'pre');
end
Note that c1 is found in c{1} etc.
Addition:
In the case when you don't want c1...c3 to be (possibly) padded with NaNs, the best way in my opinion would be trimming the index vector to the length of A or B ("length(C)"). This ensures you won't access blocks outside your square matrix. For example:
newIdx = index(1:numel(A));
Then just use newIdx instead of index in the rest of the code.

Cell2mat for unequal lengths - MATLAB

I've got a simple 2D cell array that contains data in the form of:
What is the simplest way to be able to use cat/cell2mat when each column can be of an unequal length? Is there a way to replace [] entries with 0?
EDIT:
Desired output would be a matrix with the same number of columns. For the example shown above, the rows in the first column would contain:
42
58
81
19
84
16
40
60
40
36
and so on while the rows of the second column would contain:
57
29
14
5
9
69
17
84
12
4
and so on.
EDIT2:
Adding zeroes would look something like this:
Maybe this is what you want. Zeros are added at the end.
c = {[1;2] [10; 20; 30]; [3;4;5] [40]; [6; 7] []}; %// example
c1 = vertcat(c{:,1});
c2 = vertcat(c{:,2});
n1 = numel(c1);
n2 = numel(c2);
result = zeros(max(n1,n2),2);
result(1:n1,1) = c1;
result(1:n2,2) = c2;
In this example:
>> celldisp(c)
c{1,1} =
1
2
c{2,1} =
3
4
5
c{3,1} =
6
7
c{1,2} =
10
20
30
c{2,2} =
40
c{3,2} =
[]
>> result
result =
1 10
2 20
3 30
4 40
5 0
6 0
7 0
This solution proposes an almost vectorized approach to solve the stated problem and also makes it a generic one for any number of columns in an input cell array. This is categorized as "almost-vectorized" one because it uses cellfun('length'..) (if you look at the code) and AFAIK cellfun is basically a wrapper to a for-loop. But in this case, cellfun('length'..) is very lightweight and rest of the code is vectorized and that's why the term "almost-vectorized".
Code -
%// 3 column sized input cell array
c = {[1;2] [10; 20; 30] [3;8;42]; [3;4;5] [40] [3]; [6; 7] [] [5;9;11;32]}
lens = sum(cellfun('length',c),1)
out = zeros(max(lens),numel(lens))
out(bsxfun(#le,[1:max(lens)]',lens)) = vertcat(c{:})
Output -
>> c
c =
[2x1 double] [3x1 double] [3x1 double]
[3x1 double] [ 40] [ 3]
[2x1 double] [] [4x1 double]
>> out
out =
1 10 3
2 20 8
3 30 42
4 40 3
5 0 5
6 0 9
7 0 11
0 0 32
I would urge you to take a look at cellfun. My solution below would work really well, were it not for the 'UniformOutput', false-part. This is only necessary because some cells in my example are empty matrices, on which histc behaves differently.
cellarray = cell(3,2);
cellarray(:,1)= {[3, 2, 1]; [12, 3, 4, 6]; []};
edges = 1:13; % If you do not know the range of values, find them using cellfun(min, cellarray), and max
x = cellfun(#(x)histc(x, edges), cellarray, 'UniformOutput', false)

Parse text file in MATLAB

I am parsing multiple text files in MATLAB and each time I store the result in the main array, but the problem that the data haven't the same size!
example:
t(i,:) = x;
% x data array from file i
ex:
t(1,:) = [ 5 4 3 2 1];
t(2,:) = [ 10 9 8 7 6 5];
t(3,:) = [ 11 12 13 14];
the size of x's is different, how i can store such these data (dynamic size) in the array!
Thanks,
you can store it in a cell array like this:
t{1} = [ 5 4 3 2 1];
t{2} = [ 10 9 8 7 6 5];
t{3} = [ 11 12 13 14];
and use them like this:
>> t(1)
ans =
[1x5 double]
>> t{2}
ans =
10 9 8 7 6 5
>> t
t =
[1x5 double] [1x6 double] [1x4 double]
>> t{:}
ans =
5 4 3 2 1
ans =
10 9 8 7 6 5
ans =
11 12 13 14
>> t{2}(1,2)
ans =
9
>> t{2}(1,2:end)
ans =
9 8 7 6 5
You can use a cell array to hold numeric arrays of various sizes. For instance
rows_cell = {};
rows_cell{1} = [ 5 4 3 2 1];
rows_cell{2} = [ 10 9 8 7 6 5];
rows_cell{3} = [ 11 12 13 14];
To access data:
rows_cell{2}(1,2)
ans =
9
rows_cell{3}(1,4)
ans =
14

how do I combine some elements into one element of a row matrix

I need to combine some elements into one element of a row matrix in MATLAB. For example, my matrix is
[1 2 3 4 5 6 7 8]. I want to transform the matrix like [1234 5678]. Please help me do this.
Consider the following anonymous function for a generalized numeric solution for combining single digits:
combineDigits = #(x) x*(10.^(length(x)-1:-1:0)).';
Each element of x must be on [0,9] (i.e. single digits). For your example input:
>> x = [1 2 3 4 5 6 7 8]
x =
1 2 3 4 5 6 7 8
>> x1 = x(1:4); x2 = x(5:end);
>> combineDigits(x1)
ans =
1234
>> combineDigits(x2)
ans =
5678
>>
The anonymous function combinedDigits can be applied with any general utility function, such as cellfun, to process blocks of data. For example, consider the 2x8 matrix M of digits, partitioned into a 2x2 cell array of 1x4 digit arrays:
>> M = randi(9,2,8)
M =
4 8 6 8 7 7 6 7
9 9 1 9 7 4 2 1
>> Mpartitioned = mat2cell(M,[1 1],[4 4]) % specify ANY valid partitioning here
Mpartitioned =
[1x4 double] [1x4 double]
[1x4 double] [1x4 double]
>> Mcompacted = cellfun(combineDigits,Mpartitioned)
ans =
4868 7767
9919 7421
You can do it as following:
a=[1 2 3 4 5 6 7 8];
vec1=a(1:4) %put a suitable number here
vec1=num2str(vec1);
vec1(ismember(vec1,' ')) = [];
vec1=str2double(vec1);
Similarly, perform the above sequence of operation on the latter half of the vector and simply concatenate them in the final vector.
Note: This solution works only for a row vector as you mentioned in the question (you mentioned row matrix, but I assume this is what you meant).
It depends. If you can guarantee that your row will always be a multiple of 4, you could do the following:
reshape(sum(bsxfun(#times,reshape(Q',4,[])',[1000,100,10,1]),2),[],size(Q,1))';
What this does is reshape the matrix like so:
[1 2 3 4 5 6 7 8 -> [1 2 3 4
8 7 6 5 4 3 2 1] 5 6 7 8
8 7 6 5
4 3 2 1]
We then multiple each row by [1000,100,10,1] and sum each row:
[1 2 3 4 [1000 200 30 4 [1234
5 6 7 8 -> 5000 600 70 8 -> 5678
8 7 6 5 8000 700 60 5 8765
4 3 2 1] 4000 300 20 1] 4321]
Finally we reshape the matrix again to get back to the original shape.
[1234 [1234 5678
5678 -> 8765 4321]
8765
4321]
First define your values in a numeric array:
a = [1 2 3 4 5 6 7 8];
Next convert to a string:
b = num2str(a);
Now remove all the spaces:
b(find(b == ' ')) = '';
Insert an empty space in the middle and then convert back to a numeric array (I think this is what you want(?)):
c = str2num([b(1:4),' ',b(5:end)]);
So that
>> c(1)
ans =
1234
>> c(2)
ans =
5678
Edit: Added 'end' to cover an arbitrary range.

add a constant to a specified column of a matrix for a cell array in matlab

Assume I have a 4x1 cell array,A, inside each cell is a 2x5 matrix,
A={[1 1 1 1 1; 2 2 2 2 2];
[3 3 3 3 3; 4 4 4 4 4];
[5 5 5 5 5; 6 6 6 6 6];
[7 7 7 7 7; 8 8 8 8 8]}
what I want is to add a constant,let's say 100, to the 4th column of matrix for each cell to make B. For example
B={[ 1 1 1 101 1; 2 2 2 102 2];
[3 3 3 103 3; 4 4 4 104 4];
[5 5 5 105 5; 6 6 6 106 6];
[7 7 7 107 7; 8 8 8 108 8]}
What is the best way to do it?
I can get the addition result by using
B=cellfun(#(x) x(:,4)+100,A,'uni',0)
but have difficult to get B. Any help is greatly appreciated.
If you can guarantee that the matrix in cell in A is of the same dimensions (in your case, a 2x5 matrix), you can concatenate all matrices vertically:
B = cat(1, A{:});
then add 100 to the fourth column:
B(:, 4) = B(:, 4) + 100;
and then convert back it back to a cell array:
B = mat2cell(B, size(A{1}, 1) * ones(size(A)), size(A{1}, 2));
In this case consider representing the data as a three-dimensional matrix instead of a cell array. It would be much easier to manipulate.
In the general case, you would employ a for loop:
B = A;
for k = 1:numel(A)
B{k}(:, 4) = B{k}(:, 4) + 100;
end
You can add a matrix to each cell as shown below:
B=cellfun(#(x) x+[0 0 0 100 0;0 0 0 100 0],A,'UniformOutput',false);