I don't think SPSS macros can return values, so instead of assigning a value like VIXL3 = !getLastAvail target=VIX level=3 I figured I need to do something like this:
/* computes last available entry of target at given level */
define !compLastAvail(name !Tokens(1) /target !Tokens(1) /level !Tokens(1))
compute tmpid= $casenum.
dataset copy tmpset1.
select if not miss(!target).
compute !name= lag(!target, !level).
match files /file= * /file= tmpset1 /by tmpid.
exec.
delete variables tmpid.
dataset close tmpset1.
!enddefine.
/* compute last values */
!compLastAvail name="VIXCL3" target=VIXC level=3.
The compute !name = ...is where the problem is.
How should this be done properly? The above returns:
>Error # 4285 in column 9. Text: VIXCL3
>Incorrect variable name: either the name is more than 64 characters, or it is
>not defined by a previous command.
>Execution of this command stops.
When you pass tokens to the macro, they get interpreted literally. So when you specify
!compLastAvail name="VIXCL3"
It gets passed to the corresponding compute statement as "VIXCL3", instead of just a variable name without quotation marks (e.g. VIXCL3).
Two other general pieces of advice;
If you do the command set mprint on before you execute your macro, you will see how your tokens are passed to the macro. In this instance, if you had taken that step, you would have seen that the offending compute statement and error message.
Sometimes you do what to use quotation marks in tokens, and when that is the case the string commands !QUOTE and !UNQUOTE come in handy.
Related
I'll start with my code:
macro example(args...)
local s = __source__
println(s) # This part works, showing macro is called on line 9
quote
println(s) # Julia tells me this variable "s" is not defined
println(__source__) # Likewise, "__source__" is not defined here either
end
end
#example 42 # Line 9 of my file
In my macro above I want to record the line number that is calling the macro and use it within my quote block. Both capturing it in a variable outside the quote block and using it within, or using it directly in the quote block don't work. My understanding is the code outside the quote block runs at parse-time, and the expression returned from the quote block is evaluated at run-time.
I feel like there must be a way to capture that variable and inject it right into the expression that will be evaluated later, but I haven't figured out how to do that. Any help here is appreciated. If there is a better way to do this let me know.
I ended up finding out an answer on my own. In the second line if I changed __source__ to __source__.line or __source__.file it worked fine as long as I then used $ to interpolate the result into the expression the macro returned. I'm still not sure why __source__ on its own didn't work, but using either .line or .file methods is working for me now.
I'm experiencing a similar problem trying to use __source__.
I think I can offer insight into why source.line, etc worked though.
The value of source.line is an integer. The value of source.fike is a string. Numbers and strings evaluate to themselves.
A symbol, on the other hand, evaluates to whatever value it has in the environment.
I need to run SPSS syntax in an IF statement, which tests if a variable exists in the document. I am having trouble getting the IF test right. I'm trying to do this:
do if (test if myVariable exists).
// execute code here
end if.
Execute.
I've looked here and tried this:
DO IF (myVariable) exist=1.
END IF.
Execute.
But I get the error 'There is extraneous text following the logical expression on a DO IF command. Have I misunderstood the code?
spssinc select variables command creates a list of variables according to a specified propertie. In this case the property will be the variable called "MyVar". If the variable doesn't exist, the list will stay empty:
spssinc select variables macroname="!findMyVar" /properties pattern="MyVar".
Now we define a macro that will run some commands only if the above list is not empty:
define doifMyVarexists ()
!if (!eval(!findMyVar)<>"") !then
* put your commands here, like following examples.
compute MyVar=MyVar*2.
freq MyVar.
!ifend
!enddefine.
* the macro is ready, now we call it:
doifMyVarexists.
If you run this multiple times, you will face a problem that if MyVar exists once and in a later run doesn't exist - the list doesn't get emptied (it is only overwritten if there were variables to put into it).
To solve that use the following line to empty the list before running select variables again:
define !findMyVar() !enddefine.
I would like to conditionally process blocks of syntax where the condition is based on the active data set.
Within an SPSS macro, you can conditionally process a block of syntax using the !IF/!IFEND macro command. However, as far as I can tell, the user is required to explicitly give a value to the flag by either using the !LET command (!LET !FLAG = 1), or by using a Macro input variable. This is wildly different from my experience with other languages, where I can write code that has branching logic based on the data I'm working with.
Say that there is a block of syntax that I only want to run if there are at least 2 records in the active data set. I can create a variable in the data set which is equal to the number of records using the AGGREGATE function, but I can't find a way to make a macro variable equal to that value in a way that is usable as a !IF condition. Below is a very simple version of what I'd like to do.
COMPUTE DUMMY=1.
AGGREGATE
/OUTFILE = * MODE = ADDVARIABLES
/BREAK DUMMY
/NUMBER_OF_CASES = N.
!LET !N_CASES = NUMBER_OF_CASES.
!IF (!N_CASES > 1) !THEN
MEANS TABLES = VAR1 VAR2 VAR3.
!IFEND
Is what I'm attempting possible? Thanks in advance for your time and consideration.
Following is a way to put a value from the dataset into a macro, which you can then use wherever you need - including in another macro.
First we'll make a little dataset to recreate your example:
data list free/var1 var2 var3.
begin data
1 1 1 2 2 2 3 3 3
end data.
* this will create the number of cases value:
AGGREGATE /OUTFILE = * MODE = ADDVARIABLES /BREAK /NUMBER_OF_CASES = N.
Now we can send the value into a macro - by writing a separate syntax file with the macro definition.
do if $casenum=1.
write out='SomePath\N_CASES.sps' /"define !N_CASES() ", NUMBER_OF_CASES, " !enddefine.".
end if.
exe.
insert file='SomePath\N_CASES.sps'.
The macro is now defined and you can use the value in calculations (e.g if you want to use it for analysis of a different dataset, or later in your syntax when the current data is not available).
for example:
compute just_checking= !N_CASES .
You can also use it in your macro as in your example - you'll see that the new macro can't read the !N_CASES macro as is, that's why you need the !eval() function:
define !cond_means ()
!IF (!eval(!N_CASES) > 1) !THEN
MEANS TABLES = VAR1 VAR2 VAR3.
!IFEND
!enddefine.
Now running the macro will produce nothing if there is just one line in your data, and will run means if there was more than one line:
!cond_means.
I am currently trying to create dynamic variable names based on the valuelabels of the passed Argument. Currently, I have something like this:
COMPUTE counter = 0.
APPLY DICTIONARY FROM *
/SOURCE VARIABLES = V601
/TARGET VARIABLES = counter.
DEFINE !macro1 (!POS !CMDEND).
STRING name (A20).
!DO !#i = 1 !TO 62
COMPUTE counter = #i
!IF (!POS !EQ !i)
!THEN
COMPUTE name = VALUELABEL(!POS)
COMPUTE !CONCAT('wasnot', name) = 1.
!ELSE
COMPUTE name = VALUELABEL(!counter).
COMPUTE !CONCAT('wasnot', name) = 0.
!IFEND
!DOEND
CROSSTABS v15 by !CONCAT('wasnot', name) /cells = column.
!ENDDEFINE.
The idea is, that for every unique value of V601 a flag variable will be created (e.g. "wasnotvaluelabel1"). This variable will either have value = 1 or 0 respectively. However, it seems that concat cannot be used the way I intended. I get these errors:
Error # 6843 in column 7. Text: !POS
The end of a macro expression occurred when an operand was expected.
Execution of this command stops.
Error # 6846 in column 7. Text: !POS
A macro expression includes an undefined macro variable or a macro operator
which is not valid within an expression.
Error # 6836 in column 12. Text: !EQ
In a macro expression, an operator was not preceded by an operand.
Error # 6846 in column 2. Text: !THEN
A macro expression includes an undefined macro variable or a macro operator
which is not valid within an expression.
Error # 6846 in column 28. Text: !POS
A macro expression includes an undefined macro variable or a macro operator
which is not valid within an expression.
Questions I have right now:
Is it even possible to generate dynamic names? I have tried
different attempts over the last hours but the SPSS macro "language"
seems very restricted.
Is there perhaps some other way to achieve this Task? It seems rather unconvenient.
Please note, working with the Python AddIn is sadly not an Option. I'm grateful for any received advice.
There is an extension command, SPSSINC CREATE DUMMIES, that will create all these dummy variables automatically. It's on the Transform menu. And it is implemented in Python.
Using Python you can easily read case data and do lots more.
Thanks for all the Help. In the end I did it with generating new syntax using Outfile.
I am using this function on matlab
[ProbData,HazData] = cdsbootstrap(ZeroData,MarketData,Settle,[],[],[],[],[],[],0.25)
and it is giving me an error because it dose not understand the [ ].
I want to keep the default inputs from 4-->9 and change the ninth input to 0.25. What should I put instead of the [ ]?
The function cdsbootstrap uses matlab's very common Name/Value pair syntax. Read the first few lines here:
Specify optional comma-separated pairs of Name,Value arguments. Name
is the argument name and Value is the corresponding value. Name must
appear inside single quotes (' '). You can specify several name and
value pair arguments in any order as Name1,Value1,...,NameN,ValueN.
So if you wanted ALL default values, you would use the call:
[ProbData,HazData] = cdsbootstrap(ZeroData,MarketData,Settle);
If you wanted to change one of these possiblities you would simply include the name and value, all names omitted are set to defaults. Based on your value of 0.25 I'm going to assume you are trying to set the RecoveryRate since 0.25 is close to the default.
[ProbData,HazData] = cdsbootstrap(ZeroData,MarketData,Settle,'RecoveryRate',0.25);
Ref:
http://www.mathworks.com/help/fininst/cdsbootstrap.html