MATLAB create constant spacing between numbers on same line - matlab

Good morning,
I'm sure there's a built in function but I can't find it. I want to create static positioning for information being sent to a text document in MATLAB. For example:
height weight age favorite number
------------------------------------------------------------
60 140 24 9
30 45 3 10000000
48 100 9 19
9 7 1 1
currently, i'm just doing an fprint call with padded spaces to get it lined up, but the issue arises where having different length numbers causes the alignment to be off, like so:
height weight age favorite number
------------------------------------------------------------
60 140 24 9
30 45 3 10000000
48 100 9 19
1 7 1 1
Thanks in advance.
here's an example script that'll show what I mean:
fid1 = fopen('stackoverflowtest', 'w');
if fid1 < 3,
error('ERROR');
end;
fprintf(fid1, 'height weight age favorite number \n');
fprintf(fid1, '------------------------------------------------------------ \n');
height = 0;
weight = 10;
age = 100;
number = 3;
for i = 1:100
fprintf(fid1, "%d ', height);
fprintf(fid1, "%d ', weight);
fprintf(fid1, "%d ', age);
fprintf(fid1, "%d \n", number);
height = height + 3;
weight = weight + 6;
age = age - 1;
number = number + 23;
end

You can do this with the fprintf format specification, for example %-15d.
Here, the - is a flag which specifies left justification, and the 15 specifies how much space to leave around the representation.
We can reproduce your example with
A = [60 140 24 9
30 45 3 10000000
48 100 9 19
9 7 1 1];
fprintf('height weight age favorite number \n'),...
fprintf('------------------------------------------------------------ \n'),...
fprintf('%-15d %-15d %-12d %-15d \n',A')
which displays
height weight age favorite number
------------------------------------------------------------
60 140 24 9
30 45 3 10000000
48 100 9 19
9 7 1 1
EDIT: You can store this data as a table:
height = A(:,1)
weight = A(:,2);
age = A(:,3);
favourite_number = A(:,4);
tab1 = table(height, weight, age, favourite_number);
disp(tab1);
This prints to screen
height weight age favourite_number
______ ______ ___ ________________
60 140 24 9
30 45 3 1e+07
48 100 9 19
9 7 1 1
but I'm not sure how to save this representation to a file.

Related

How to shift non circularly in Matlab

I am trying to shift non circularly in MATLAB so even if I shift outside of the index it will add 0s to correct it. I tried following the answer in How do I shift columns (left or right) in a matrix? but had no success.
data = [1 2 3 4 5; 11 12 13 14 15; 21 22 23 24 25; 31 32 33 34 35]
d = 3; % shift; positive/negative for right/left
result = zeros(size(data), 'like', data); % preallocate with zeros
result(:,max(1,1+d):min(end,end+d)) = data(:,max(1,1-d):min(end,end-d)); % write values
In my output results is nothing but the same size but all zeroes
Desired output:
0 0 0 1 2 3 4 5
0 0 0 11 12 13 14 15
0 0 0 21 22 23 24 25
0 0 0 31 32 33 34 35
You can do it by creating a matrix result, the final size, filled with zeros, then copying the original data into the final result, making sure you place the data at the right indices.
What you have in your example code is not right for what you ask. If I run it,the final result is padded fine but truncated at the size of the original data matrix. This is how some matrix are shifted (with the shifted columns dropped altogether), but that's not what you asked.
A simple way to do it, is to create a padding matrix of the proper size, then simply concatenate it with your original data matrix. This can be done as below:
%% Initial data
data = [1 2 3 4 5; 11 12 13 14 15; 21 22 23 24 25; 31 32 33 34 35] ;
d = 3 ;
%% shift and pad with zeros
nrows = size(data,1) ; % Number of rows in [data]
pad = zeros( nrows , abs(d) ) ; % create padding matrix
if d>0
result = [pad data] ; % Concatenate the filler matrix on the left
else
result = [data pad] ; % Concatenate the filler matrix on the right
end
And just to be sure:
>> result
result =
0 0 0 1 2 3 4 5
0 0 0 11 12 13 14 15
0 0 0 21 22 23 24 25
0 0 0 31 32 33 34 35
If you want to reuse the same way than in your example code, you have to adjust it a bit to allow for the new columns:
%% create result and copy data
result = zeros( size(data,1) , size(data,2)+abs(d) ) ;
colStart = max(1,1+d) ;
result(:,colStart:colStart+size(data,2)-1) = data ;
This will create the same result matrix as above.

Counting number of items in a matrix according a period of time

I have a little issue.
For example, I have a matrix
m=[11 1 9 ;
22 2 10;
33 3 11;
44 4 14;
55 1 15;
66 4 20;
77 1 20;
88 1 24;
99 2 24 ]
where the first column is the id of a product, the second column is the id of the buyer, and the third is the day of purchase.
I would like to count the number of articles bought by a buyer for a period delta=5 days.
I tried this code but I have an issue: I would like to obtain a final matrix where in the rows i have the ids of the users and in columns the number of articles bought for each period.
m=[11 1 9 ;22 2 11; 33 3 10; 44 4 15; 55 1 15;66 4 20; 77 1 20; 88 1 24; 99 2 24 ]
D=m(:,3)
p=0;
delta=5
res=zeros(length(unique(m(:,2))),(div(max(D),delta)))
NbA=zeros(1,length(unique(m(:,2))))
while p<max(D)+1
p
pos=find((m(:,3)>=p)& (m(:,3)<p+delta))
Mtemp=u(pos,:);
[r c]=size(Mtemp);
Ustemp=Mtemp(:,2);
UnUstemp=unique(Ustemp);
for i=1:length(UnUstemp)clc
us=UnUstemp(i);
[n l]=size(find(Ustemp==us));
NbA(i)=n;
end
res=[res ;NbA];
p=p+delta;
end

Matlab: how I can transform this algorithm associated with matrices manipulation?

(For my problem, I use a matrix A 4x500000. And the values of A(4,k) varies between 1 and 200).
I give here an example for a case A 4x16 and A(4,k) varies between 1 and 10.
I want first to match a name to the value from 1 to 5 (=10/2):
1 = XXY;
2 = ABC;
3 = EFG;
4 = TXG;
5 = ZPF;
My goal is to find,for a vector X, a matrix M from the matrix A:
A = [20 52 70 20 52 20 52 20 20 10 52 20 11 1 52 20
32 24 91 44 60 32 24 32 32 12 11 32 2 5 24 32
40 37 24 30 11 40 37 40 40 5 10 40 40 3 37 40
2 4 1 3 4 5 2 1 3 3 8 6 7 9 6 10]
A(4,k) takes all values between 1 and 10. These values can be repeated and they all appear on the 4th line.
20
X= 32 =A(1:3,1)=A(1:3,6)=A(1:3,8)=A(1:3,9)=A(1:3,12)=A(1:3,16)
40
A(4,1) = 2;
A(4,6) = 5;
A(4,8) = 1;
A(4,9) = 3;
A(4,12) = 6;
A(4,16) = 10;
for A(4,k) corresponding to X, I associate 2 if A(4,k)<= 5, and 1 if A(4,k)> 5. For the rest of the value of A(4,k) which do not correspond to X, I associate 0:
[ 1 2 3 4 5 %% value of the fourth line of A between 1 and 5
2 2 2 0 2
ZX = 6 7 8 9 10 %% value of the fourth line of A between 6 and 10
1 0 0 0 1
2 2 2 0 2 ] %% = max(ZX(2,k),ZX(4,k))
the ultimate goal is to find the matrix M:
M = [ 1 2 3 4 5
XXY ABC EFG TXG ZPF
2 2 2 0 2 ] %% M(3,:)=ZX(5,:)
Code -
%// Assuming A, X and names to be given to the solution
A = [20 52 70 20 52 20 52 20 20 10 52 20 11 1 52 20
32 24 91 44 60 32 24 32 32 12 11 32 2 5 24 32
40 37 24 30 11 40 37 40 40 5 10 40 40 3 37 40
2 4 1 3 4 5 2 1 3 3 8 6 7 9 6 10];
X = [20 ; 32 ; 40];
names = {'XXY','ABC','EFG','TXG','ZPF'};
limit = 10; %// The maximum limit of A(4,:). Edit this to 200 for your actual case
%// Find matching 4th row elements
matches = A(4,ismember(A(1:3,:)',X','rows'));
%// Matches are compared against all possible numbers between 1 and limit
matches_pos = ismember(1:limit,matches);
%// Finally get the line 3 results of M
vals = max(2*matches_pos(1:limit/2),matches_pos( (limit/2)+1:end ));
Output -
vals =
2 2 2 0 2
For a better way to present the results, you can use a struct -
M_struct = cell2struct(num2cell(vals),names,2)
Output -
M_struct =
XXY: 2
ABC: 2
EFG: 2
TXG: 0
ZPF: 2
For writing the results to a text file -
output_file = 'results.txt'; %// Edit if needed to be saved to a different path
fid = fopen(output_file, 'w+');
for ii=1:numel(names)
fprintf(fid, '%d %s %d\n',ii, names{ii},vals(ii));
end
fclose(fid);
Text contents of the text file would be -
1 XXY 2
2 ABC 2
3 EFG 2
4 TXG 0
5 ZPF 2
A bsxfun() based approach.
Suppose your inputs are (where N can be set to 200):
A = [20 52 70 20 52 20 52 20 20 10 52 20 11 1 52 20
32 24 91 44 60 32 24 32 32 12 11 32 2 5 24 32
40 37 24 30 11 40 37 40 40 5 10 40 40 3 37 40
2 4 1 3 4 5 2 1 3 3 8 6 7 9 6 10]
X = [20; 32; 40]
N = 10;
% Match first 3 rows and return 4th
idxA = all(bsxfun(#eq, X, A(1:3,:)));
Amatch = A(4,idxA);
% Match [1:5; 5:10] to 4th row
idxZX = ismember([1:N/2; N/2+1:N], Amatch)
idxZX =
1 1 1 0 1
1 0 0 0 1
% Return M3
M3 = max(bsxfun(#times, idxZX, [2;1]))
M3 =
2 2 2 0 2

Matlab isn't incrementing my variable

I have the following matrix declared in Matlab:
EmployeeData =
1 20 100000 42 14
2 15 95000 35 14
3 18 70000 28 14
4 10 85000 35 14
5 10 40000 21 12
6 4 45000 14 8
7 3 50000 21 10
8 5 55000 21 14
9 1 25000 14 7
10 2 50000 21 9
42 4 100000 42 10
Where column 1 represents ID numbers, 2 represents years, 3 is salary, 4 is vacation days, and 5 is sick days. I am trying to find the maximum value of a column (in this case the salary column), and print out the ID associated with that value. If more than one employee has the maximum value, all the IDs with that maximum are supposed to be shown. So here is how I naively implemented a way to do it:
>> maxVal = [];
>> j = 1;
>> for i = EmployeeData(:, 3)
if i == max(EmployeeData(:, 3))
maxVal = [maxVal EmployeeData(j, 1)];
end
j = j + 1;
end
But it shows maxVal to be [] in my workspace variables, instead of [1 42] as I expected. Upon inserting a disp(i) in the for loop above the if to debug, I get the following output:
100000
95000
70000
85000
40000
45000
50000
55000
25000
50000
Just like I expected. But when I switch out that disp(i) with a disp(j), I get this for my output:
1
What am I doing wrong? Should this not work?
MATLAB for loops operate on rows, not columns. You should try replacing your for loop with:
for i = EmployeeData(:, 3)' % NOTE THE TRANSPOSE
...
end
EDIT: Note that you can do what you're trying to do without a forloop:
maxVal = EmployeeData(EmployeeData(:,3) == max(EmployeeData(:,3)),1);
Is this what you want?
>> EmployeeData(EmployeeData(:,3)==max(EmployeeData(:,3)),1)
ans =
1
42

"Find and replace" from a matrix MATLAB

I have a matrix that is like the following:
a = [10 0; 12 5; 10 0; 12 0; 15 0; 15 2];
a =
10 0
12 5
10 0
12 0
15 0
15 2
I am looking to create a new matrix which find and replaces the zeros with a value that is dependent on the first column's value. The key is this matrix:
Key =
10 100
12 200
15 300
If the value is already greater than zero in the first column I would like to leave it. The output would look like this:
Output =
10 100
12 5
10 100
12 200
15 300
15 2
You can do it in one line using logical indexing smartly:
a(~a(:,2),2)=arrayfun(#(x)Key(Key(:,1)==x,2),a(~a(:,2),1))
%a =
% 10 100
% 12 5
% 10 100
% 12 200
% 15 300
% 15 2