Understand evaluation and loop [duplicate] - matlab

This question already has an answer here:
Suppressing Output MATLAB
(1 answer)
Closed 6 years ago.
Trying to understand this code :
A = [1 2 3]
T = A(:,1:end);
fprintf('\nvalues ', T);
A creates a Matrix of dimension 1 x 3
When I run this code, this is printed :
A =
1 2 3
Why is T not implicitly evaluated and printed to screen ?
I'm unfamiliar with this syntax : A(:,1:end); is this selecting the first column of Matrix and looping ?

The lines of code that are evaluated in screen "implicitly" are the ones that do not end with ;. The semicolon operator suppresses the printing of the result of that line.
In your code,
A = [1 2 3] % No semicolon -> print
T = A(:,1:end); % semicolon -> no print
The end keyword has nothing to do with the printing. Its a keyword very useful to do vetorized operations in Matlab.
Saying A(:,1:end) you are telling MATLAB " take all the values (:) from column indexes starting on 1 until the last column of the matrix end. Basically, in this case, all the values of A. You can try A(1:end,1:end) and check that returns the same thing.
For a more useful example, you might want all the matrix but the first row, then you would use A(2:end,:).

Related

SPSS/macro: split string into multiple variables

I am trying to split a string variable into multiple dummy coded variables. I used these sources to get an idea of how one would achieve this task in SPSS:
https://www.ibm.com/support/pages/making-multiple-string-variables-single-multiply-coded-field
https://www.spss-tutorials.com/spss-split-string-variable-into-separate-variables/
But when I try to adapt the first one to my needs or when I try to convert the second one to a macro, I fail.
In my dataset I have (multiple) variables that contain a comma seperated string that represents different combinations of selected items (as well as missing values). For each item of a specific variable I want to create a dummy variable. If the item was selected, it should be represented with a 1 in the new dummy variable. If it was not selected, that case should be represented with a 0.
Different input variables can contain different numbers of items.
For example:
ID
VAR1
VAR2
DMMY1_1
DMMY1_2
DMMY1_3
1
1, 2
8
1
1
0
2
1
1, 3
1
0
0
3
3, 1
2, 3, 1
1
0
1
4
2, 8
0
0
0
Here is what I came up with so far ...
* DEFINE DATA.
DATA LIST /ID 1 (F) VAR1 2-5 (A) VAR2 6-12 (A).
BEGIN DATA
11, 28
21 1, 3
33, 12, 3, 1
4 2, 8
END DATA.
* MACRO SYNTAX.
* DEFINE VARIABLES (in the long run these should/will be inside the macro function, but for now I will leave them outside).
NUMERIC v1 TO v3 (F1).
VECTOR v = v1 TO v3.
STRING #char (A1).
DEFINE split_var(vr = TOKENS(1)).
!DO !#pos=1 !TO char.length(!vr).
COMPUTE #char = char.substr(!vr, !#pos, 1).
!IF (!#char !NE "," !AND !#char !NE " ") !THEN
COMPUTE v(NUMBER(!#char, F1)) = 1.
!IFEND.
!DOEND.
!ENDDEFINE.
split_var vr=VAR1.
EXECUTE.
As I got more errors than I can count, it's hard to narrow down my problem. But I think the problem has something to do with the way I use the char.length() function (and I am a bit confused when to use the bang operator).
If anyone has some insights, I would really appreciate some help :)
There is a fundamental issue to understand about SPSS macro - the macro does not read or interact in any way with the data. All the macro does is manipulate text to write syntax. The syntax created will later work on the actual data when you run it.
So, for example, Your first error is using char.length(!vr) within the syntax. You are trying to get the macro to read the data, calculate the length and use, but that simply can't be done - the macro can only work with what you gave it.
Another example in your code: you calculate #char and then try to use it in the macro as !#char. So that obviously won't work. ! precedes only macro functions or arguments. #char, in your code, is neither, and it can't become one - can't read the data into the macro...
To give you a litte push forward: I understand you want the macro loop to run a different number of times for each variable, but you can't use char.length(!vr). I suggest instead have the macro loop as many times as necessary to be sure you can deal with the longest variable you'll need to work with.
And another general strategy hint - first, create syntax to deal with one specific variable and one specific delimiter. Once this works, start working on a macro, keeping in mind that the only purpose of the macro is to recreate the same working syntax, only changing the parameters of variable name and delimiter.
With my new understanding of the SPSS macro logic (thanks to #eli-k) the problem was quite easy to solve. Here is the working solution.
* DEFINE DATA.
DATA LIST /ID 1 (F) VAR1 2-5 (A) VAR2 6-12 (A).
BEGIN DATA
11, 28
21 1, 3
33, 12, 3, 1
4 2, 8
END DATA.
* DEFINE MACRO.
DEFINE #split_var(src_var = !TOKENS(1)
/dmmy_var_label = !DEFAULT(dmmy) !TOKENS(1)
/dmmy_var_lvls = !TOKENS(1))
NUMERIC !CONCAT(!dmmy_var_label,1) TO !CONCAT(!dmmy_var_label, !dmmy_var_lvls) (F1).
VECTOR #dmmy_vec = !CONCAT(!dmmy_var_label,1) TO !CONCAT(!dmmy_var_label, !dmmy_var_lvls).
STRING #char (A1).
LOOP #pos=1 TO char.length(!src_var).
COMPUTE #char = char.substr(!src_var, #pos, 1).
DO IF (#char NE "," AND #char NE " ").
COMPUTE #index = NUMBER(#char, F1).
COMPUTE #dmmy_vec(#index) = 1.
END IF.
END LOOP.
RECODE !CONCAT(!dmmy_var_label,1) TO !CONCAT(!dmmy_var_label, !dmmy_var_lvls) (SYSMIS=0) (ELSE=COPY).
EXECUTE.
!ENDDEFINE.
* CALL MACRO.
#split_var src_var=VAR2 dmmy_var_lvls=8.

How to fix 'Subscripted assignment dimension mismatch' error inside FOR loop [duplicate]

This question already has answers here:
Create variables with names from strings
(6 answers)
Closed 3 years ago.
I've been getting this Subscripted assignment dimension mismatch error in matlab when trying to transpose a vector inside a for loop. I've checked other questions and solutions to no avail and any input would be greatly appreciated.
id = spikes.labels(:,1);
cl = id(spikes.labels(:,2) == 2);
for i = 1:length(cl);
ii = cl(i);
indexSpike = find(spikes.assigns == ii);
Unit = spikes.unwrapped_times(indexSpike);
strcat('Unit', num2str(ii)) = Unit';
save (strcat('Unit', num2str(ii), '.mat'), strcat('Unit', num2str(ii)));
end
In the second to last line inside the loop I need to transpose the vector called Unit and name it according to ii.
This is where I get the error.
You can make a structure array for this problem. Structure will have two properties name and value. Assign strcat('Unit', num2str(ii)) to name and Unit' to value
units(ii).name = strcat('Unit', num2str(ii));
units(ii).value = Unit';
save (strcat('Unit', num2str(ii), '.mat'), Unit');

Error running matlab code after compiling

It looks like this has been asked many times, but none of the past posts seem to solve my question. All those had to do with matrix/vector while my code does not have any of these, just simple variables. It takes three variables as arguments. It works perfectly fine within the Matlab environment. I only got the error when I compiled it with mcc -m Normal.m and tried to run with the executable like this "./Normal 1 5 0.5". The complete error message is:
Error using /
Matrix dimensions must agree.
Error in Normal (line 4)
MATLAB:dimagree
It is complaining about line 4: N=2/dt, what is wrong with this?
Here is the code:
function val=Normal(l1,l2,dt)
const=(l2/l1-1);
N=2/dt;
S=1.0/sqrt(l2/l1);
Z(1)=S;
for i=2:N
t= -1+(i-1)*dt;
Z(i)=1.0/sqrt(const*t*t+1);
S=S+2*Z(i);
end
Z(21)=1.0/(l2/l1);
S=S+1.0/sqrt(l2/l1);
val=dt*S/2;
end
But dt is not a scalar when passed into the standalone through the command ./Normal 1 5 0.5. It is a character array with 3 elements ('0', '.','5')!
When passing numerical arguments to a standalone, they are passed as strings. Thus, inside the function, you need to convert '0.5' into a double, and similarly for l1 and l2:
dt = str2num(dt);
l1 = str2num(l1);
l2 = str2num(l2);
Note that you can use isdeployed to determine at runtime if the function is a standalone:
if isdeployed, dt = str2num(dt); end
And you might need to display the result:
if isdeployed, disp(val); end
Result:
>> system('Normal 1 5 0.5');
1.4307
>> Normal(1,5,0.5) % .m function for comparison
ans =
1.4307

Matlab says 'find' is not defined in a function [duplicate]

This question already has an answer here:
MATLAB error: "previously appeared to be used as a function or command"
(1 answer)
Closed 8 years ago.
In my command window, I can execute find([0 1 0]), but when I run find in a function, as in x = find([0 1 0]), the compiler tells me that find isn't defined. Why might that be?
The error is:
??? Error: File: frequentTuples.m Line: 12 Column: 21
"find" previously appeared to be used as a function or command, conflicting with its
use here as the name of a variable.
A possible cause of this error is that you forgot to initialize the
variable, or you have initialized it implicitly using load or eval.
and here's the code. The error occurs on the second line of the for loop.
function [ tuples ] = frequentTuples( k, candidates, transactions, min_support )
%FREQUENTTUPLES Get frequent itemsets of size k
% Detailed explanation goes here
candidate_tuple_is_frequent = zeros(size(candidates, 1));
for i = 1:size(candidates, 1)
columns_of_candidate_items = transactions(:, candidates(i, :));
indices_of_transactions_containing_all_items = find(sum(columns_of_candidate_items') == k);
candidate_tuple_is_frequent(i) = size(indices_of_transactions_containing_all_items) >= min_support;
end
tuples = candidates(find(candidate_tuple_is_frequent, :));
end
Ah, I see your problem now. You have a misplaced bracket on line 13. You have
tuples = candidates(find(candidate_tuple_is_frequent, :));
When you should have
tuples = candidates(find(candidate_tuple_is_frequent), :);
You're trying to call find(candidate_tuple_is_frequent, :), which is trying to treat find as a variable. This means that any other call to find in the function will treat it as a variable, hence your error.

Removing specific elements from matrix

I want to remove a (*) asterisk from my matrix and write out that matrix to a text file and the remaining elements will be concatenated to each other without a space or any kind of delimiters. I wrote this code
for b = 1 : length(out7num_r7_nt_back)
if ~(out7num_r7_nt_back(b) == '*')
out7num_r7_back(b) = '';
end
end
disp(out7num_r7_nt_back);
dlmwrite('my_data.txt',out7num_r7_nt_back, '');
I got this error message:
??? Index of element to remove exceeds matrix dimensions.
You can use a vectorized boolean index, replacing the loop as follows:
out7num_r7_nt_back = out7num_r7_nt_back(out7num_r7_nt_back(b) ~= '*');
That should be much faster as well.
Value of upper bound of for loop (length(out7num_r7_nt_back)) gets evaluated only once!
Say you have '*ab' in a variable. Loop will count to 3 (length of variable). Inside the loop when program erases '*', you'll get 'ab' which is of length 2. Since loop is iterating to 3, program will try to access out7num_r7_nt_back(3) which is out of bounds.
You could remove characters while going backwards:
...
for b = length(out7num_r7_nt_back) : -1 : 1
...
But you should prefer vectorized approach because it's faster and cleaner to write.