Help with macros

classic Classic list List threaded Threaded
23 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Help with macros

Eleonora Sidorova
Define !test ( List=!Noexp !Enclose('{', '}')
               /Char=!Default('µ') !Noexp !Enclose('{', '}')
               /Mis=!Default('$Sysmis') !Noexp !Enclose('{', '}')).

count ####NumCols=!List (MISSING,SYSMIS,LO THRU HI).

!Let !@Nvars=####NumCols.
do repeat x=!List /y=!Concat(!Char, 1) To !Concat(!Char, !@Nvars).
compute y=x.
end repeat.

!enddefine.

Hello everyone!

I am new on this forum and in SPSS Macro writing.
Please, can you indicate me the way to assign calculated variable ####NumCols to !@Nvars, to use it later in the syntax.

I've tried a lot of different ways but without success.

Thank you very much for any help.
Eleonora
Reply | Threaded
Open this post in threaded view
|

Re: Help with macros

Art Kendall
If you are new to SPSS it is possible but unlikely that you meed to use macros.

Please tell the list in words what you are trying to do.
Art Kendall
Social Research Consultants
Reply | Threaded
Open this post in threaded view
|

Re: Help with macros

Eleonora Sidorova
Thank you for your attantion to my problem.

I am trying to create macro, that delete duplicates codes in open ended questions.

The data looks like this:

DATA LIST LIST /a1_1@1o1  a1_1@2o1  a1_1@3o1  a1_1@4o1  a1_1@5o1  a1_1@6o1  a1_1@7o1  a1_1@8o1  a1_1@9o1
BEGIN DATA
10  49  30  4  44  1.5  999999  999999  49

This macro complete.

/*Kill double coded.
Define !dp_killrep ( List=!Noexp !Enclose('{', '}')
               /Char=!Default('µ') !Noexp !Enclose('{', '}')
               /Mis=!Default('$Sysmis') !Noexp !Enclose('{', '}')).

count ####NumCols=!List (MISSING,SYSMIS,LO THRU HI).

!Let !@Nvars=####NumCols.
do repeat x=!List /y=!Concat(!Char, 1) To !Concat(!Char, !@Nvars).
compute y=x.
end repeat.

!Let !Vec=!Concat('vec',!Char).

Vector !Vec=!Concat(!Char, 1) To !Concat(!Char, !@Nvars).
Loop #X=2 To !@Nvars.
Loop #Y=1 To #X-1.
If !Vec(#X)=!Vec(#Y) !Vec(#X)=!Mis.
End loop.
End loop.

recode !List (else=sysmis).

do repeat x=!List /y=!Concat(!Char, 1) To !Concat(!Char, !@Nvars).
compute x=y.
end repeat.
delete variables !Concat(!Char, 1) To !Concat(!Char, !@Nvars).
!enddefine.

Eleonora
Reply | Threaded
Open this post in threaded view
|

Re: Help with macros

Art Kendall
Your variable names do not appear to be very Mnemonic.
CTABLES has a built in option to ignore duplicates.

Unless you have many multiple response sets and or expect to do this task you do not need to use macros.  For many such tasks, Python may be more useful than macros.

Try this exercise in un-duplicating multiple response sets.
where Snack(i) is a multiple response set and Want(i) is the intended result.
does Result(i) match Want(i)?

Multiple response sets can have particular kinds of missing data. Here all negative values are meant to be user missing.

new file.
data list list/HH (f2)Snack1 to Snack3 (3f2) Want1 to Want3 (3f2).
begin data
    01 1 2 3 1 2 3
    02 3 2 1 3 2 1
    03 1 3 2 1 3 2
    04 1 3 -1 1 3 -1
    05 1 -1 -1 1 -1 -1
    06 1 1 1 1 -2 -2
    07 1 2 2 1 2 -2
    08 1 2 1 1 2 -2
    09 -3 -3 -3 -3 -3 -3
end data.
*MISSING VALUES Snack1 to Want3 (LO THRU -1).
VALUE LABELS Snack1 to Want3
    1 'Apple'
    2 'Cherry'
    3 'Lemon'
    -3 'No response for any snack'
    -2 'duplicate of earlier response'
    -1 'fewer responses in Multiple Response'.
list.
VECTOR S=Snack1 to Snack3.
VECTOR Result(3).
VECTOR R= Result1 to Result3.
LOOP #I =1 to 3.
    COMPUTE R(#I) = S(#I).
    DO IF #I GT 1.
        LOOP #J = 1 to #I-1.
            IF R(#I) EQ R(#J) R(#I) = -2.
        END LOOP.
    END IF.
END LOOP.
LIST.


Is this the kind of thing you are trying to do?
Art Kendall
Social Research Consultants
Reply | Threaded
Open this post in threaded view
|

Re: Help with macros

Eleonora Sidorova
In reply to this post by Eleonora Sidorova
Thank you,
I need this macros not for CTABLES but for checking the data if we do not prepare the tables.  Your script is similar to what I need but with some changes.  It should be universal macro, where I insert every time different numbers of variables that should be checked for duplicates. And I need to clean duplicates in original variables, not in the new ones.  For the last row with data in the  cleaned results we need only one -3.
Eleonora
Reply | Threaded
Open this post in threaded view
|

Re: Help with macros

Art Kendall
It sounds like you are preparing the data for somebody else who will be using software other than SPSS.

"And I need to clean duplicates in original variables, not in the new ones."

Transforming input variables into themselves is a dangerous practice.  It may be that you want to send the set of transformed variables to somebody else.  But retaining the original variables makes it possible to go back and do things the way you eventually mean.

it sounds like you want to take the variables in a multiple response set and produce a new set.
something like a function such as
"unduplicate MRSet1 into MRSet2"

I am not sure I follow
"For the last row with data in the  cleaned results we need only one -3. "
Why wouldn't all respondents (cases) have the same number of values in a multiple response set? Even if some of those values are user-missing?

Can you cobble up an example set of variables that looks like the kind of input you are suggesting?
then for each case fill in a set of variables representing what you want.  Possibly, you could just take my example set and edit it so the Want variables look like what you want.
Art Kendall
Social Research Consultants
Reply | Threaded
Open this post in threaded view
|

Re: Help with macros

Eleonora Sidorova
In the first piece of data below, there are double codes that can turn out in the data.

In the second part, this is what I need after cleaning the double codes. Of course, for security, it is better when cleaning the codes inside the macro,

to transfer the codes to new variables, but then return them to the original ones. I will not overwrite the original data file, since it is in our

rules to work with a copy and I, in case of incorrect macro operation, can always restore the original data.



The number and name of variables for cleaning in each project is different.

Therefore, my idea was that we need to create a universal macro in which I would substitute variables that need to be cleaned,

and the macro would count everything else by itself. My snag now is that I do not know how to assign to !NVars the counted number of variables

in the range in order to first transfer them to new variables, without double ones, clean the original variables, and then return the data from the newly created variables to them.



data list list/HH (f2)Snack1 to Snack3 (3f2) Want1 to Want3 (3f2).

begin data

    01 97 96 3 1 2 3

    02 3 2 1 3 2 1

    03 98 99 2 1 3 2

    04 1 3 -1 1 3 -1

    05 1 -1 -1 1 -1 -1

    06 1 1 1 1 -2 -2

    07 1 2 2 1 2 -2

    08 1 2 1 1 2 -2

    09 98 99 99 98 96 97

end data.

*MISSING VALUES Snack1 to Want3 (LO THRU -1).

VALUE LABELS Snack1 to Want3

    1 'Apple'

    2 'Cherry'

    3 'Lemon'

    -3 'No response for any snack'

    -2 'duplicate of earlier response'

    -1 'fewer responses in Multiple Response'.





data list list/HH (f2)Snack1 to Snack3 (3f2) Want1 to Want3 (3f2).

begin data

    01 97 96 3 1 2

    02 3 2 1

    03 98 99 2 1 3

    04 1 3 -1

    05 1 -1

    06 1 -2

    07 1 2 -2

    08 1 2 -2

    09 98 99 96 97

end data.

*MISSING VALUES Snack1 to Want3 (LO THRU -1).

VALUE LABELS Snack1 to Want3

    1 'Apple'

    2 'Cherry'

    3 'Lemon'

    -3 'No response for any snack'

    -2 'duplicate of earlier response'

    -1 'fewer responses in Multiple Response'.



Thank you in advance for the answer.
Reply | Threaded
Open this post in threaded view
|

Re: Help with macros

Bruce Weaver
Administrator
Hello Eleonora.  I'm still not at all sure I understand everything you want to do.  However, I think the key thing you are asking is how to assign to macro variable !@Nvars the number of variables in a list of variables.  If so, perhaps the following code will help you.  

* Count the number of variables in a list.
!LET !junk=""
!DO !var !IN (!List)
!LET !junk=!CONCAT(!junk,"x")
!DOEND
!LET !@Nvars = !LENGTH(!junk)

Good luck!
Bruce


Eleonora Sidorova wrote
In the first piece of data below, there are double codes that can turn out in the data.

In the second part, this is what I need after cleaning the double codes. Of course, for security, it is better when cleaning the codes inside the macro,

to transfer the codes to new variables, but then return them to the original ones. I will not overwrite the original data file, since it is in our

rules to work with a copy and I, in case of incorrect macro operation, can always restore the original data.



The number and name of variables for cleaning in each project is different.

Therefore, my idea was that we need to create a universal macro in which I would substitute variables that need to be cleaned,

and the macro would count everything else by itself. My snag now is that I do not know how to assign to !NVars the counted number of variables

in the range in order to first transfer them to new variables, without double ones, clean the original variables, and then return the data from the newly created variables to them.



data list list/HH (f2)Snack1 to Snack3 (3f2) Want1 to Want3 (3f2).

begin data

    01 97 96 3 1 2 3

    02 3 2 1 3 2 1

    03 98 99 2 1 3 2

    04 1 3 -1 1 3 -1

    05 1 -1 -1 1 -1 -1

    06 1 1 1 1 -2 -2

    07 1 2 2 1 2 -2

    08 1 2 1 1 2 -2

    09 98 99 99 98 96 97

end data.

*MISSING VALUES Snack1 to Want3 (LO THRU -1).

VALUE LABELS Snack1 to Want3

    1 'Apple'

    2 'Cherry'

    3 'Lemon'

    -3 'No response for any snack'

    -2 'duplicate of earlier response'

    -1 'fewer responses in Multiple Response'.





data list list/HH (f2)Snack1 to Snack3 (3f2) Want1 to Want3 (3f2).

begin data

    01 97 96 3 1 2

    02 3 2 1

    03 98 99 2 1 3

    04 1 3 -1

    05 1 -1

    06 1 -2

    07 1 2 -2

    08 1 2 -2

    09 98 99 96 97

end data.

*MISSING VALUES Snack1 to Want3 (LO THRU -1).

VALUE LABELS Snack1 to Want3

    1 'Apple'

    2 'Cherry'

    3 'Lemon'

    -3 'No response for any snack'

    -2 'duplicate of earlier response'

    -1 'fewer responses in Multiple Response'.



Thank you in advance for the answer.
--
Bruce Weaver
bweaver@lakeheadu.ca
http://sites.google.com/a/lakeheadu.ca/bweaver/

"When all else fails, RTFM."

PLEASE NOTE THE FOLLOWING: 
1. My Hotmail account is not monitored regularly. To send me an e-mail, please use the address shown above.
2. The SPSSX Discussion forum on Nabble is no longer linked to the SPSSX-L listserv administered by UGA (https://listserv.uga.edu/).
Reply | Threaded
Open this post in threaded view
|

Re: Help with macros

Eleonora Sidorova
Hi Bruce,
Thank you very much, this syntax is very useful!!
I've tested this morning, it works perfectly when ,
for example !List = a0@1o1 a0@1o2 a0@1o3 a0@1o4 a0@1o5 a0@1o6 a0@1o7 a0@1o8 a0@2o1 a0@3o1.
But when i try to write !List=a0@1o1 to a0@3o1, !junk is equal 3 in this case. Is there a way to read variables through to in a0@1o1 to a0@3o1.

Thank you very in advance,
Eleonora.
Reply | Threaded
Open this post in threaded view
|

Re: Help with macros

Kirill Orlov
In reply to this post by Eleonora Sidorova
Eleonora
To let the macro "know" a value generated by a regular syntax (such as a value from a dataset) within the same macro you will have to use WRITE and then INSERT comnands. It is tricky and not very much convenient, but is possible.

(The reason why it is a problem is that macros and regular syntax are not on the same level to call-over between them. Macro is an "envelope" for syntax, it can pass a parameter to syntax, but not vice versa.)

It is more convenient, many users think, to do such things like your task through Python programmability than through a macro.

But I'll show in the next reply how to do it in macro.
Reply | Threaded
Open this post in threaded view
|

Re: Help with macros

Eleonora Sidorova
Hello Kirill,

Thank you very much for the explanation, unfortunately I am still taking the first steps in the macro, many things are not yet known to me. I haven't started using Python yet, but I plan to deal with it in the future.

Thanks a lot for your help.
Eleanora.
Reply | Threaded
Open this post in threaded view
|

Re: Help with macros

Art Kendall
open spss
paste the line below and run it.
SPSSINC SELECT VARIABLES/help.

If you are starting out with SPSS, this list and its archives will prove to valuable resources.

before creating new features in Python or Macro  it will be more efficient to check whether the feature already exists.
Art Kendall
Social Research Consultants
Reply | Threaded
Open this post in threaded view
|

Re: Help with macros

Art Kendall
In reply to this post by Eleonora Sidorova
In 50 years of using SPSS and other software, I have never seen an application where cases have different numbers of variables in a set. It is certainly possible to have cases to have different numbers of valid values and user-missing values in a set. The number of valid values + the number of missing values is a constant across cases.

Why would one want to have different numbers of variables in multiple response sets (MRSets) in different cases?

In de-duplicated MRSets it is possible the  number of variables is cut down to be the maximum number of valid responses in ANY case.  However, it is often simpler to have the same number of variables in the result MRset as in the raw input MRSET. In that instance some variables would just have missing values indicating the respondent made fewer responses.

Having different cases have different numbers of variables would require more complex code. In addition if you are sending the data to other packages there is a risk the software would fill in zeros or its version of system-missing.
Art Kendall
Social Research Consultants
Reply | Threaded
Open this post in threaded view
|

Re: Help with macros

Bruce Weaver
Administrator
In reply to this post by Kirill Orlov
The WRITE & INSERT approach Kirill described has been referred to by some as the "horrible hack".  You can see an example of it in my 25-Jun-2013 post in this thread:

http://spssx-discussion.165.s1.nabble.com/SELECT-IF-LOOP-td5720860.html

Sorry Jon, I should have issued a trigger warning first, I suppose.  Calm yourself.  ;-)  

Kirill Orlov wrote
Eleonora
To let the macro "know" a value generated by a regular syntax (such as a value from a dataset) within the same macro you will have to use WRITE and then INSERT comnands. It is tricky and not very much convenient, but is possible.

(The reason why it is a problem is that macros and regular syntax are not on the same level to call-over between them. Macro is an "envelope" for syntax, it can pass a parameter to syntax, but not vice versa.)

It is more convenient, many users think, to do such things like your task through Python programmability than through a macro.

But I'll show in the next reply how to do it in macro.
--
Bruce Weaver
bweaver@lakeheadu.ca
http://sites.google.com/a/lakeheadu.ca/bweaver/

"When all else fails, RTFM."

PLEASE NOTE THE FOLLOWING: 
1. My Hotmail account is not monitored regularly. To send me an e-mail, please use the address shown above.
2. The SPSSX Discussion forum on Nabble is no longer linked to the SPSSX-L listserv administered by UGA (https://listserv.uga.edu/).
Reply | Threaded
Open this post in threaded view
|

Re: Help with macros

jkpeck
In reply to this post by Art Kendall
As Art said, SPSSINC SELECT VARIABLES supports TO and ALL in variable lists.  However, it is an extension command, so you need to install it via the Extensions > Extension Hub menu first.
Reply | Threaded
Open this post in threaded view
|

Re: Help with macros

Kirill Orlov
This post was updated on .
In reply to this post by Kirill Orlov
Eleonora,
The suggestion made by Bruce (the suggestion to loop through the list of names via macro !DO ... !IN(...)) is probably what will suit you. But it implies that the list of the input variable names is a complete name-by-name list, such as var1 var2 var3 var4.

Below is a recipe which allows to input variable name list also in a short form, such as var1 TO var4.
The macro below does the counting of variables by COUNT command - exactly like you did it in your macro in the question. The solution uses then WRITE command to prepare the DO REPEAT of the main job.

define !macro(vars= !cmdend)
!let !prefix= 'NEW_'

/*Auxiliary actions.
*(please replace below the path D:\EXERCISE\ with some one where you can save files to on your PC).
string nvars##$ (a8).
do if $casenum=1. /*Just for one case, do the following
 count nvars###= !vars (MISSING LO THRU HI). /*Count the number of variables
 compute nvars##$= ltrim(string(nvars###,f8)). /*nvars### in string format
write outfile= 'D:\EXERCISE\my temporary file.sps'
      /'do repeat x= ' !quote(!vars)
      /' /y= ' !quote(!prefix) '1 to ' !quote(!prefix) nvars##$ '.'.
end if.
execute. /*Run the transformation action

*The main task of your macro.
insert file= 'D:\EXERCISE\my temporary file.sps'. /*Read the DO REPEAT command
compute y= rnd(uniform(x)). /*Some your computations
                   /*(in this example: generate a random integer between 0 and X)
end repeat. /*Close the END REPEAT
execute. /*Run the transformation action

/*You may want to remove traces of your auxiliary actions.
*delete variables nvars### nvars##$.
*erase file 'D:\EXERCISE\my temporary file.sps'.

!enddefine.


*EXAMPLE.
data list list /var1 var2 var3.
begin data
1 4 1
3 8 5
2 6 4
0 2 9
end data.
dataset name data.

*Run your macro.
!macro vars= var1 var2 var3.

*You can also run.
!macro vars= var1 to var3.

*-----------------------.

Your 'my temporary file.sps' syntax file contained this.
do repeat x= var1 var2 var3
 /y= NEW_1 to NEW_3       .


If the list of variables vars can be long, a more relible way to write out the DO REPEAT will be:
write outfile= 'D:\EXERCISE\my temporary file.sps'
      /'do repeat x= '
    !do !w !in (!vars)
      /' ' !quote(!w)
    !doend
      /' /y= ' !quote(!prefix) '1 to ' !quote(!prefix) nvars##$ '.'.

instead of the:    
write outfile= 'D:\EXERCISE\my temporary file.sps'
      /'do repeat x= ' !quote(!vars)
      /' /y= ' !quote(!prefix) '1 to ' !quote(!prefix) nvars##$ '.'.

so each of your vars variables will occupy a separate line in 'my temporary file.sps' syntax file.
Reply | Threaded
Open this post in threaded view
|

Re: Help with macros

Eleonora Sidorova
In reply to this post by jkpeck
I checked this command and it is already on my computer. How do I apply this command in my case?

Thanks in advance,
Eleanora
Reply | Threaded
Open this post in threaded view
|

Re: Help with macros

Eleonora Sidorova
In reply to this post by Kirill Orlov
Thank's a lot Kirill, I will test this script.
Eleonora.
 
 
Reply | Threaded
Open this post in threaded view
|

Re: Help with macros

Art Kendall
In reply to this post by Kirill Orlov
OP posted this for the "Want" variables.  But that has a different structure for each case.
data list list/HH (f2)Snack1 to Snack3 (3f2) Want1 to Want3 (3f2).
begin data
    01 97 96 3 1 2
    02 3 2 1
    03 98 99 2 1 3
    04 1 3 -1
    05 1 -1
    06 1 -2
    07 1 2 -2
    08 1 2 -2
    09 98 99 96 97
end data.
Art Kendall
Social Research Consultants
Reply | Threaded
Open this post in threaded view
|

Re: Help with macros

Eleonora Sidorova
In reply to this post by Art Kendall
My idea was to create a generic macro that works with SPSS data. I know that mrset removes double codes. but in the course of my work, we often deal with open-ended questions and then send data to other departments that do not work with MRSET. Therefore, the data must be cleaned of double codes. There are many coded open-ended questions included into the data and the number of variables are different each time. In one question they gave 3 answers, in another 10. Therefore, for a macro that I am trying to do, first, it is important to  count the number of variables in the range, and then work with it.
When all the variables are listed, then there are no problems with the macro, but when we write through to, it becomes a problem. Yes, you can list all the variables, but you want to be able to write in different ways.

Example of using future macros:

Using the syntax of Bruce , I can use it for
!test list={q6@1o1 q6@1o2 q6@1o3 q6@1o4 q6@1o5 q6@1o6}.
exe.
!test list={q6a@1o1 q6a@1o2 q6a@1o3}.
exe.
!test list={q2a@1o1 q2a@1o2 q2a@1o3 q2a@1o4 q2a@1o5}.
exe.

But it would be more convenient if I could work with both options.


!test list={q6@1o1 to q6@1o10}.
exe.
!test list={q6a@1o1 to q6a@1o3}.
exe.
!test list={q2a@1o1 to q2a@1o5}.
exe.

Eleonora.
12