how to read a matrix from a text file in matlab - matlab

I have a text file which has 500 columns and 500 rows, of numerical(integer) values . Every element in the row is separated by a tab. I want to read this file as a matrix in matlab. Example(my text file is like this):
1 2 2 1 1 2
0 0 0 1 2 0
1 2 2 1 1 2
0 0 0 1 2 0
And after reading this text file as a matrix (a[]) in matlab I want to do transpose.
Help me.

You can use importdata.
Something like:
filename = 'myfile01.txt';
delimiterIn = '\t';
headerlinesIn = 1;
A = importdata(filename,delimiterIn,headerlinesIn);
A_trans = A';
You can skip headerlines if your file does not have any haeder.. (It is the number of lines before the actual data starts)
Taken from Matlab documentation, improtdata

Have you tired load with -ascii option?
For example
a = load('myfile.txt', '-ascii'); % read the data
a = a.'; %' transpose

% Pre-allocate matrix
Nrow=500; Ncol=500;
a = zeros(Nrow,Ncol);
% Read file
fid = fopen('yourfile.txt','r');
for i:1:Nrow
a(i,:) = cell2mat(textscan(fid,repmat('%d ',Ncol));
end
fclose(fid);
% Trasnspose matrix
a_trans = a.';

You could simply do:
yourVariable = importdata('yourFile.txt')';
%Loads data from file, transposes it and stores it into 'yourVariable'.

Related

Matlab from text file to sparse matrix.

I have a huge text file in the following format:
1 2
1 3
1 10
1 11
1 20
1 376
1 665255
2 4
2 126
2 134
2 242
2 247
First column is the x coordinate while second column is the y coordinate.
It indicates that if I had to construct a Matrix
M = zeros(N, N);
M(1, 2) = 1;
M(1, 3) = 1;
.
.
M(2, 247) = 1;
This text file is huge and can't be brought to main memory at once. I must read it line by line. And save it in a sparse matrix.
So I need the following function:
function mat = generate( path )
fid = fopen(path);
tline = fgetl(fid);
% initialize an empty sparse matrix. (I know I assigned Mat(1, 1) = 1)
mat = sparse(1);
while ischar(tline)
tline = fgetl(fid);
if ischar(tline)
C = strsplit(tline);
end
mat(C{1}, C{2}) = 1;
end
fclose(fid);
end
But unfortunately besides the first row it just puts trash in my sparse mat.
Demo:
1 7
1 9
2 4
2 9
If I print the sparse mat I get:
(1,1) 1
(50,52) 1
(49,57) 1
(50,57) 1
Any suggestions ?
Fixing what you have...
Your problem is that C is a cell array of characters, not numbers. You need to convert the strings you read from the file into integer values. Instead of strsplit you can use functions like str2num and str2double. Since tline is a space-delimited character array of integers in this case, str2num is the easiest to use to compute C:
C = str2num(tline);
Then you just index C like an array instead of a cell array:
mat(C(1), C(2)) = 1;
Extra tidbit: If you were wondering how your demo code still worked even though C contained characters, it's because MATLAB has a tendency to automatically convert variables to the correct type for certain operations. In this case, the characters were converted to their double ASCII code equivalents: '1' became 49, '2' became 50, etc. Then it used these as indices into mat.
A simpler alternative...
You don't even have to bother with all that mess above, since you can replace your entire function with a much simpler approach using dlmread and sparse like so:
data = dlmread(filePath);
mat = sparse(data(:, 1), data(:, 2), 1);
clear data; % Save yourself some memory if you don't need it any more

MATLAB - Create repeated sequences of ones and zeros with loops

I am trying to create a single column vector (out), which is comprised of a sequence of ones and zeros. These should occur in sets of length B and C respectively, which are repeated A number of times. For example:
out=[1
0
0
1
0
0
1
0
0]
It is currently set up as:
out=[0]; %not ideal, but used to initially define 'out'
A=3;
B=1;
C=2;
for i = 1:length(A)
for ii = 1:length(B)
out(end+1,1) = ones(ii,1);
end
for iii = 1:length(C)
out(end+1,1) = zeros(iii,1);
end
end
This is not working - current output:
out=[0
1
0]
How can I correct these loops to get the desired output? Also, is there a better way of achieving this with the given the inputs?
Many thanks.
1) You do not need to use length as this returns the length of an array type, so A,B,C will all be length of 1.
2) Just directly use the values as shown below. Also you can initialize an empty array with empty brackets []
3) If you're using the zeros and ones commands, these generate whole arrays/matrices and do not need to be in a loop. If you want to keep your loop version, just use =1 or =0
out=[]; %--> you can use this instead
A=3;
B=1;
C=2;
for i = 1:A
out(end+1:end+B,1) = ones(B,1);
out(end+1:end+C,1) = zeros(C,1);
end
... or of course to be more "Matlaby" just do what David said in the comments repmat([ones(B,1);zeros(C,1)],A,1), but the above is there to help you on your way.
How about some modulo arithmetic?
result = double(mod(0:(B+C)*A-1, B+C)<B).';
Example:
>> B = 2; %// number of ones in each period
>> C = 4; %// number of zeros in each period
>> A = 3; %// number of periods
>> result = double(mod(0:(B+C)*A-1, B+C)<B).'
result =
1
1
0
0
0
0
1
1
0
0
0
0
1
1
0
0
0
0
I can suggest 2 ways:
a)Using for loop-
A=3;
B=2;
C=3;
OneVector=ones(1,B); % B is the length of ones.
zeroVector=zeros(1,C); % C is the length of zeros.
combinedVector=cat(2,OneVector,zeroVector);
Warehouse=[]; % to save data
for(i=1:A)
Warehouse=cat(2,Warehouse,combinedVector);
end
b)using repmat:
OneVector=ones(1,B); % B is the length of ones.
zeroVector=zeros(1,C); % C is the length of zeros.
combinedVector=cat(2,OneVector,zeroVector);
Warehouse=repmat(combinedVector, [A,1]);
I hope, this will solve your problem.

Using Matlab to make modification to a text file

Essentially I am writing a Matlab file to change the 2nd, 3rd and 4th numbers in the line below "STR" and above "CON" in the text file (which is given below and is called '0.dat'). Currently, my Matlab code makes no changes to the text file.
Text File
pri
3
len 0.03
vic 5 5
MAT
1 147E9 0.3 0 4.9E9 8.5E9
LAY
1 0.000125 1 45
2 0.000125 1 0
3 0.000125 1 -45
4 0.000125 1 90
5 0.000125 1 45
WAL
1 1 2 3 4 5
PLATE
1 0.005 1 1
STR
1 32217.442335442 3010.34241024889 2689.48842888812
CON
1 2 1 2 3 1 3 4 1 4 5 1 5 6 1 6 7 1
ATT
1 901 7 901
LON
34
POI
123456
1 7
X 0.015
123456
2 6
X 0.00381966011250105 0.026180339887499
123456
3 5
X 0.000857864376269049 0.0291421356237309
123456
4
X 0
PLO
2 3
CRO
0
RES
INMOD=1
END
Matlab code:
impafp = importdata('0.dat','\t');
afp = impafp.textdata;
fileID = fopen('0.dat','r+');
for i = 1:length(afp)
if (strncmpi(afp{i},'con',3))
newNx = 100;
newNxy = 50;
newNy = 500;
myformat = '%0.6f %0.9f %0.9f %0.9f\n';
newData = [1 newNx newNxy newNy];
afp{i-1} = fprintf(fileID, myformat, newData);
fclose(fileID);
end
end
From the help for importdata:
For ASCII files and spreadsheets, importdata expects to find numeric
data in a rectangular form (that is, like a matrix). Text headers can
appear above or to the left of numeric data. To import ASCII files
with numeric characters anywhere else, including columns of character
data or formatted dates or times, use TEXTSCAN instead of import data.
Indeed, if you print out the value of afp, you'll see that it just contains the first line. You were also not performing any operation that was writing to a file. And you were not closing the file ID if the if state wasn't triggered.
Here is one way to do this with textscan (which is probably faster too):
% Read in data as strings using textscan
fid = fopen('0.dat','r');
afp = textscan(fid,'%s','Delimiter','');
fclose(fid);
isSTR = strncmpi(afp{:},'str',3); % True for all lines starting with STR
isCON = strncmpi(afp{:},'con',3); % True for all lines starting with CON
% Find indices to replace - create logical indices
% True if line before is STR and line after is CON
% Offset isSTR and isCON by 2 elements in opposite directions to align
% Use & to perform vectorized AND
% Pad with FALSE on either side to make output the same length as afp{1}{:}
datIDX = [false;(isSTR(1:end-2)&isCON(3:end));false];
% Overwrite data using sprintf
myformat = '%0.6f %0.9f %0.9f %0.9f';
newNx = 100;
newNxy = 50;
newNy = 500;
newData = [1 newNx newNxy newNy];
afp{1}{datIDX} = sprintf(myformat, newData); % Set only elements that pass test
% Overwrite old file using fprintf (or change filename to new one)
fid = fopen('0.dat','w');
fprintf(fid,'%s\r\n',afp{1}{1:end-1});
fprintf(fid,'%s',afp{1}{end}); % Avoid blank line at end
fclose(fid);
If you're unfamiliar with logical indexing, you might read this blog post and this.
I would recommend just reading the entire file in, finding which lines contain your "keywords", modifying specific lines, and then writing it back out to a file, which can have the same name or a different one.
file = fileread('file.dat');
parts = regexp(file,'\n','split');
startIndex = find(~cellfun('isempty',regexp(parts,'STR')));
endIndex = find(~cellfun('isempty',regexp(parts,'CON')));
ind2Change = startIndex+1:endIndex-1;
tempCell{1} = sprintf('%0.6f %0.9f %0.9f %0.9f',[1,100,50,500]);
parts(ind2Change) = deal(tempCell);
out = sprintf('%s\n',parts{:});
out = out(1:end-1);
fh = fopen('file2.dat','w');
fwrite(fh,out);
fclose(fh);

Overwrite only specific fields of a csv file in matlab

I'd like to write cell arrays of strings to csv files and overwrite parts of them with numerical data. I guess, for illustrative purposes we could use two matrices:
a = ones(5,5);
b = zeros(3,3);
I'd like to write a to a csv file and then overwrite specific fields of this file with b, resulting in:
1 1 1 1 1
1 1 1 1 1
1 1 0 0 0
1 1 0 0 0
1 1 0 0 0
Is there a way to do this in matlab? I tried
csvwrite('foo.csv', a);
dlmwrite('foo.csv', b, 'roffset', 2, 'coffset', 2)
but this would overwrite the entire file. I would be thankful for any suggestions.
Here's a solution based on Marcin's suggestion:
datsize = size(a);
precision = 6;
output_cell = reshape(cellstr(num2str(a(:),precision)), size(a));
for i = 3:datsize(1,1),
for j = 3:datsize(1,2),
output_textdata(i,j) = output_cell(i-2,j-2);
end
end
cell2csv('foo.csv', output_textdata);
While this produces the desired outcome three issues remain. First, the 'precision' varies from cell to cell. Second, which is not a problem for the intended limited application of this script, this code would produce an error if matrix b partially overlapped with matrix a and partially exceeded its dimensions, e.g., b had a size of 4x4 and were superimposed on a starting from a(3,3). Third, this workaround doesn't answer the more general question of whether only specific fields of a csv can be overwritten in matlab.

How can I merge this data in MATLAB?

In the sample text file below, if column 3 contains a 1 then the corresponding data of column 2 should be merged with the data of the previous row in column 2. For example, the 40 in row 2 should be added to the 10 in row 1, then row 2 should be set to 0 (as shown in the modified sample text file). The problem with my code below is that it only records changes in the current data time(i,1) but not the changes made for the previous data.
original.txt
a time c
1 10 0
2 40 1
3 20 0
4 11 0
5 40 1
modified.txt
a time c
1 50 0
2 0 0
3 20 0
4 51 0
5 0 0
fid=fopen('data.txt');
A=textscan(fid,'%f%f%f');
a =A{1};
time=A{2};
c =A{3};
fclose(fid);
fid=fopen('newData.txt','wt');
for i=1:size(a)
if c(i,1)==1
time(i-1,1)=time(i,1)+time(i-1,1); % merge the time of the current and the previous
time(i,1) =0; %set the time to 0
array = []; %empty the array
array = [a(i,1) time c(i,1)]; add new data
format short g;
fprintf(fid,'%g\t %g\t %g\n',array);
end
fclose(fid)
The reason the current time value is written properly but the previous one isn't is because you have already written the previous one to the file on the previous loop iteration, so there is no way for you to change it. You need to remove the printing from within the loop and add it after you adjust all of the time values.
You can also take advantage of vectorization by using the FIND function instead of a for loop. You also only need one call to FPRINTF to output all the data. Try this:
a = [1; 2; 3; 4; 5]; %# Sample data
time = [10; 40; 20; 11; 40]; %# Sample data
c = [0; 1; 0; 0; 1]; %# Sample data
index = find(c == 1); %# Find indices where c equals 1
temp = time(index); %# Temporarily store the time values
time(index) = 0; %# Zero-out the time points
time(index-1) = time(index-1)+temp; %# Add to the previous time points
c(index) = 0; %# Zero-out the entries of c
fid = fopen('newData.txt','wt'); %# Open the file
fprintf(fid,'%g\t %g\t %g\n',[a time c].'); %'# Write the data to the file
fclose(fid); %# Close the file