I can see two ways to define a global variable from a function in q.
Using ::
q){gv::10}[]
q)gv /- 10
Using set
q){`gv set 20}[]
q)gv /- 20
There is a catch with set i.e. if a global variable already has a symbol assigned to it, then the value which is assigned to global variable within the function is assigned to the symbol which is assigned to global variable.
q)gv:`t
q){gv set 20}[]
`t
q)gv
`t
q)t
20
Can someone please explain me which is the better way (set or ::) to define a global variable within a function and why is it better?
There is no "better" really - but set has the advantage of assigning to a variable name which is itself a variable (as you showed in your example).
I'm confused about your confusion in the last example though......if you wanted 20 to be assigned to a global called gv then you should put a backtick in front of gv, aka `gv set 20; and conversely if you wanted 20 to be assigned to the symbol/name that gv contains then don't use the backtick, aka gv set 20;
Final point to note is that you can also create globals in non-root directories/namespaces using a single colon assignment
q){.this.that:1;}[]
q)
q).this
| ::
that| 1
Related
I would like to find the measure of a variable using syntax and then use this in an If-statement. Is this possible using syntax?
For example, if I have two variables a (nominal) and b (ordinal):
DO IF (a is nominal?)
...
END IF
You can create a list of all the nominal variables in your data. In the following example the list will be stored under the macro call !noms:
SPSSINC SELECT VARIABLES MACRONAME="!noms" /PROPERTIES LEVEL=NOMINAL.
* now, for example you can run frequencies on all nominal variables.
freq !noms.
If you want to transform all the nominal variables you can use do repeat. For example:
do repeat NomVrs=!noms.
recode NomVrs ("cat2"="persian").
end repeat.
If you want to test only one specific variable (in this example called AmInominal), you can use a macro this way:
define DoIfNom ()
!do !vr !in (!eval(!noms))
!if (!vr="AmInominal") !then
variable label AmInominal "this variable is indeed nominal".
recode AmInominal ("cat2"="persian").
frequencies AmInominal.
!ifend
!doend
!enddefine.
DoIfNom.
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
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.