I need to import a txt file into Matlab which has this format
text text text
1 0 1 2 3
4 5 6 7
2 10 11 15 18
15 1 18 3
The first column is separated with the second one by a tab delimiter, while the rest of the data are separated by a space.
I tried to import it using this:
g = importdata('file.txt',delimiterIn,headerlinesIn);
delimiterIn = ' ';
headerlinesIn = 1;
but then the extracted table is like this:
text text text
1 0 1 2 3
4 5 6 7 nan
2 10 11 15 18
15 1 18 3 nan
What I want is a table that maintains the format, with the first column of g.data on its own and then all the others.
I want an output matrix like
1 0 1 2 3
4 5 6 7
2 10 11 15 18
15 1 18 3
Then if I need to extract data represented by 2 in the first column, I can put it into another matrix with the values
10 11 15 18
15 1 18 3
each number inside a cell of a matrix
How can I do it?
A sollution might be:
fid = fopen('test.txt');
M = {[]};Midx=1;
l = fgetl(fid); %header
l = fgetl(fid);
while ~isnumeric(l)
idx = str2double(l(1));
if ~isnan(idx)
Midx=idx;
M{Midx}=[];
l = l(2:end);
end
val = cell2mat(textscan(l,'%f'))';
M{Midx}=[M{Midx};val];
l=fgetl(fid);
end
fclose(fid);
Maybe a bit too pragmatic, but this might help:
for i=1:size(A,1)
if isnan(A(i,end))==1
A(i,2:end) = A(i,1:4);
A(i,1) = NaN;
end
end
for i=1:size(A,1)
if A(i,1)==2
B = A(i:i+1,2:end);
end
end
Related
I would like to sum specific columns of each row in a matrix using a for loop. Below I have included a simplified version of my problem. As of right now, I am calculating the column sums individually, but this is not effective as my actual problem has multiple matrices (data sets).
a = [1 2 3 4 5 6; 4 5 6 7 8 9];
b = [2 2 3 4 4 6; 3 3 3 4 5 5];
% Repeat the 3 lines of code below for row 2 of matrix a
% Repeat the entire process for matrix b
c = sum(a(1,1:3)); % Sum columns 1:3 of row 1
d = sum(a(1,4:6)); % Sum columns 4:6 of row 1
e = sum(a(1,:)); % Sum all columns of row 1
I would like to know how to create a for loop that automatically loops through and sums the specific columns of each row for each matrix that I have.
Thank you.
Here is a solution that you don't need to use for loop.
Assuming that you have a matrix a of size 2x12, and you want to do the row sums every 4 columns, then you can use reshape() and squeeze() to get the final result:
k = 4;
a = [1:12
13:24];
% a =
% 1 2 3 4 5 6 7 8 9 10 11 12
% 13 14 15 16 17 18 19 20 21 22 23 24
s = squeeze(sum(reshape(a,size(a,1),k,[]),2));
and you will get
s =
10 26 42
58 74 90
I have a matrix A in Matlab of dimension Nx(N-1), e.g.
N=5;
A=[1 2 3 4;
5 6 7 8;
9 10 11 12;
13 14 15 16;
17 18 19 20];
I want to rearrange the elements of A in a certain way. Specifically I want to create a matrix B of dimension (N-1)xN such that:
for i=1,...,N,
B(:,i) collects
1) the first i-1 elements of the i-1th column of A and
2) the last N-i elements of the ith column of A.
Notice that for i=1 the i-1th column of A does not exist and therefore 1) is skipped; similarly, for i=N theith column of A does not exist and therefore 2) is skipped.
In the example above
B=[5 1 2 3 4
9 10 6 7 8
13 14 15 11 12
17 18 19 20 16];
This code does what I want. I am asking your help to vectorise it in an efficient way.
B=zeros(N-1,N);
for i=1:N
if i>1 && i<N
step1=A(1:i-1,i-1);
step2=A(i+1:N,i);
B(:,i)=[step1;step2];
elseif i==1
B(:,i)=A(i+1:N,i);
elseif i==N
B(:,i)=A(1:i-1,i-1);
end
end
Extract the lower and upper triangular matrices of A. Then reassemble them with a "diagonal shift":
u = triu(A);
l = tril(A,-1);
B = padarray(u(1:end-1,:),[0 1],'pre') + padarray(l(2:end,:),[0 1],'post');
Another valid approach using logical indexing combined with tril and triu:
B = zeros(size(A'));
B(tril(true(size(B)))) = A(tril(true(size(A)), -1));
B(triu(true(size(B)), 1)) = A(triu(true(size(A))));
Result:
>> B
B =
5 1 2 3 4
9 10 6 7 8
13 14 15 11 12
17 18 19 20 16
Is it possible to read a matrix under a specified headline from a text file?
I have a text file like this:
Header A (2x3):
3 6 7
5 8 8
Header B (4x4):
23 65 2 6
4 6 7 8
33 7 8 9
so what I want to accomplish is to take the header names as an argument and grab the matrix under it. Is it possible to do in Matlab?
Thanks in advance!!
In addition, try to use this code:
infilename = '1.txt'; % name of your file
m = memmapfile(infilename); % load file to memory (and after close it)
instrings = strsplit(char(m.Data.'),'\n','CollapseDelimiters',true).';
checkstr = 'Header B';
% find all string (their indices) starting with checkstr
ind = find(strncmpi(instrings,checkstr,length(checkstr)));
data = [];
if isempty(ind)
fprintf('\n No strings with %s',checkstr)
else
% first string with string checkstr
n = ind(1)+1;
N = length(instrings);
while n<=N % find all numerical data after string with `checkstr`
convert = str2num(instrings{n});
if isempty(convert), break, end % find non-numerical data
data(end+1,1:length(convert)) = convert; % it because you can have various number of columns
n = n+1;
end
end
data % display load data
output
23 65 2 6 7
4 6 7 8 0
33 7 8 9 0
for the file 1.txt:
Header A (2x3):
3 6 7
5 8 8
Header B (4x4):
23 65 2 6 7
4 6 7 8
33 7 8 9
The following would work, but might not be all that fast if you are dealing with a lot of data:
function [ matrixOut ] = readLineBasedOnHeader( headerString, FileName )
%readLineBasedOnHeader: Scan through a text file, and return matrix below
% a row which starts with the string `headerString`
% Read each row into cell array:
cellStrings = dataread('file', FileName, '%s', 'delimiter', '\n'); %#ok<DDTRD>
% Find the row matching headerString
headerIndex = ismember(cellStrings, headerString);
if sum(headerIndex) == 1
% We've found 1 match; return the matrix
% find how many rows have numberic
rowIdx = find(headerIndex)+1;
matrixOut = str2num(cellStrings{rowIdx}); %#ok<ST2NM>
stillAnumber = ~isempty(matrixOut);
if ~stillAnumber
error('row beneath header found not numeric');
end
while stillAnumber && rowIdx < length(cellStrings)
rowIdx = rowIdx+1;
nextRow = str2num(cellStrings{rowIdx}); %#ok<ST2NM>
stillAnumber = ~isempty(nextRow);
matrixOut = [matrixOut; nextRow]; %#ok<AGROW>
end
elseif sum(headerIndex) > 1
% More than 1 match; throw an error
error('More than 1 copy of header string found');
else % Less than 1 match; throw an error
error('Header string not found');
end
end
Assuming you have a file text_file.txt with the content you have given above, then running:
readLineBasedOnHeader('Header A (2x3):', 'text_file.txt') should return:
ans =
3 6 7
5 8 8
And running:
readLineBasedOnHeader('Header B (4x4):', 'text_file.txt')
Should return:
ans =
23 65 2 6
4 6 7 8
33 7 8 9
Note that this requires you input the full header line (i.e. an exact match for the row); but I'm sure you could have a play with this to get it to match just the Header A bit.
I have a none rectangular text file like A which has 10 values in first line, 14 values in 2nd line, 16 values in 3rd line and so on. Here is an example of 4 lines of my text file:
line1:
1.68595314026 -1.48498177528 2.39820933342 27 20 15 2 4 62 -487.471069336 -517.781921387 5 96 -524.886108398 -485.697143555
Line2:
1.24980998039 -0.988095104694 1.89048337936 212 209 191 2 1 989 -641.149658203 -249.001220703 3 1036 -608.681762695 -300.815673828
Line3:
8.10434532166 -4.81520080566 4.90576314926 118 115 96 3 0 1703 749.967773438 -754.015136719 1 1359 1276.73632813 -941.855895996 2 1497 1338.98852539 -837.659179688
Line 4:
0.795098006725 -0.98456710577 1.89322447777 213 200 68 5 0 1438 -1386.39111328 -747.421386719 1 1565 -1153.50915527 -342.951965332 2 1481 -1341.57043457 -519.307800293 3 1920 -1058.8828125 -371.696960449 4 1303 -1466.5802002 -308.764587402
Now, I want to load this text file in to a matrix M in Matlab. I tired to use importdata function for loading it
M = importdata('A.txt');
but it loads the file in a rectangular matrix (all rows have same number of columns!!!) which is not right. The expected created matrix size should be like this:
size(M(1,:))= 1 10
size(M(2,:))= 1 14
size(M(3,:))= 1 16
How can I load this text file in a correct way into Matlab?
As #Jens suggested, you should use a cell array. Assuming your file contains only numeric values separated by whitespaces, for instance:
1 3 6
7 8 9 12 15
1 2
0 3 7
You can parse it into cell array like this:
% Read full file
str = fileread('A.txt');
% Convert text in a cell array of strings
c = textscan(str, '%s', 'Delimiter', '\n');
c = c{1};
% Convert 'string' elements to 'double'
n = cellfun(#str2num, c, 'UniformOutput', false)
You can then access individual lines like this:
>> n{1}
ans =
1 3 6
>> n{2}
ans =
7 8 9 12 15
i want to control the creation of random numbers in this matrix :
Mp = floor(1+(10*rand(2,20)));
mp1 = sort(Mp,2);
i want to modify this code in order to have an output like this :
1 1 2 2 3 3 3 4 5 5 6 7 7 8 9 9 10 10 10 10
1 2 3 3 3 3 3 3 4 5 6 6 6 6 7 8 9 9 9 10
i have to fill each row with all the numbers going from 1 to 10 in an increasing order and the second matrix that counts the occurences of each number should be like this :
1 2 1 2 1 2 3 1 1 2 1 1 2 1 1 2 1 2 3 4
1 1 1 2 3 4 5 6 1 1 1 2 3 4 1 1 1 2 3 1
and the most tricky matrix that i'v been looking for since the last week is the third matrix that should skim through each row of the first matrix and returns the numbers of occurences of each number and the position of the last occcurence.here is an example of how the code should work. this example show the intended result after running through the first row of the first matrix.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 (positions)
1 2
2 2
3 3
4 1
5 2
6 1
7 2
8 1
9 2
10 4
(numbers)
this example show the intended result after running through the second row of the first matrix.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 (positions)
1 1 2
2 1 2
3 3 6
4 1 1
5 3
6 1 4
7 2 1
8 1 1
9 2 3
10 4
(numbers)
so the wanted matrix must be filled up with zeros from the beginning and each time after running through each row of the first matrix, we add the new result to the previous one...
I believe the following code does everything you asked for. If I didn't understand, you need to get a lot clearer in how you pose your question...
Note - I hard coded some values / sizes. In "real code" you would never do that, obviously.
% the bit of code that generates and sorts the initial matrix:
Mp = floor(1+(10*rand(2,20)));
mp1 = sort(Mp, 2);
clc
disp(mp1)
occCount = zeros(size(mp1));
for ii = 1:size(mp1,1)
for jj = 1:size(mp1,2)
if (jj == 1)
occCount(ii,jj) = 1;
else
if (mp1(ii,jj) == mp1(ii,jj-1))
occCount(ii,jj) = occCount(ii, jj-1) + 1;
else
occCount(ii,jj) = 1;
end
end
end
end
% this is the second matrix you asked for
disp(occCount)
% now the third:
big = zeros(10, 20);
for ii = 1:size(mp1,1)
for jj = 1:10
f = find(mp1(ii,:) == jj); % index of all of them
if numel(f) > 0
last = f(end);
n = numel(f);
big(jj, last) = big(jj, last) + n;
end
end
end
disp(big)
Please see if this is indeed what you had in mind.
The following code solves both the second and third matrix generation problems with a single loop. For clarity, the second matrix M2 is the 2-by-20 array in the example containing the cumulative occurrence count. The third matrix M3 is the sparse matrix of size 10-by-20 in the example that encodes the number and position of the last occurrence of each unique value. The code only loops over the rows, using accumarray to do most of the work. It is generalized to any size and content of mp1, as long as the rows are sorted first.
% data
mp1 = [1 1 2 2 3 3 3 4 5 5 6 7 7 8 9 9 10 10 10 10;
1 2 3 3 3 3 3 3 4 5 6 6 6 6 7 8 9 9 9 10]; % the example first matrix
nuniq = max(mp1(:));
% accumulate
M2 = zeros(size(mp1));
M3 = zeros(nuniq,size(mp1,2));
for ir=1:size(mp1,1),
cumSums = accumarray(mp1(ir,:)',1:size(mp1,2),[],#numel,[],true)';
segments = arrayfun(#(x)1:x,nonzeros(cumSums),'uni',false);
M2(ir,:) = [segments{:}];
countCoords = accumarray(mp1(ir,:)',1:size(mp1,2),[],#max,[],true);
[ii,jj] = find(countCoords);
nzinds = sub2ind(size(M3),ii,nonzeros(countCoords));
M3(nzinds) = M3(nzinds) + nonzeros(cumSums);
end
I won't print the outputs because they are a bit big for the answer, and the code is runnable as is.
NOTE: For new test data, I suggest using the commands Mp = randi(10,[2,20]); mp1 = sort(Mp,2);. Or based on your request to user2875617 and his response, ensure all numbers with mp1 = sort([repmat(1:10,2,1) randi(10,[2,10])],2); but that isn't really random...
EDIT: Error in code fixed.
I am editing the previous answer to check if it is fast when mp1 is large, and apparently it is:
N = 20000; M = 200; P = 100;
mp1 = sort([repmat(1:P, M, 1), ceil(P*rand(M,N-P))], 2);
tic
% Initialise output matrices
out1 = zeros(M, N); out2 = zeros(P, N);
for gg = 1:M
% Frequencies of each row
freqs(:, 1) = mp1(gg, [find(diff(mp1(gg, :))), end]);
freqs(:, 2) = histc(mp1(gg, :), freqs(:, 1));
cumfreqs = cumsum(freqs(:, 2));
k = 1;
for hh = 1:numel(freqs(:, 1))
out1(gg, k:cumfreqs(hh)) = 1:freqs(hh, 2);
out2(freqs(hh, 1), cumfreqs(hh)) = out2(freqs(hh, 1), cumfreqs(hh)) + freqs(hh, 2);
k = cumfreqs(hh) + 1;
end
end
toc