Date: Mon, 31 Oct 2005 21:04:10 -0500
Reply-To: Richard Ristow <wrristow@mindspring.com>
Sender: "SPSSX(r) Discussion" <SPSSX-L@LISTSERV.UGA.EDU>
From: Richard Ristow <wrristow@mindspring.com>
Subject: Re: macro to select nearest neighbour given neighbor occurred on
previous date?
In-Reply-To: <714B9F12B4E18C4C843B66E8E190F2AD45F949@res2k3ms01.CRII.ORG >
Content-Type: text/plain; charset="us-ascii"; format=flowed
At 04:34 PM 10/31/2005, Penfold, Robert wrote:
>I have 510 distance variables for each case and they are sorted (A).
>That is, NND1 < NND2 < NND3 . . . <NND510. The prescription dates for
>every neighbor of a case are contained in RxDATENN2 - RxDATENN510.
>
>RxDATENN(i) = the prescribing date of the nearest physician (in
>miles). There are 510 physicians.
>RxDATENN1 = the prescribing date of the case
>NNdistance = distance between two cases
>NND(i) = distance between case and all other cases.
>
>I want to create a variable called "NNdistance" which would be the
>distance to the nearest case GIVEN that the closest case occurred on
>an earlier date. I've written [a macro - definition below]:
>
>My problem is that I want the macro to "stop" for a case when it
>satisfies the first date condition. As it is, this macro always gives
>the *furthest* distance for which the date is earlier.
>
>Maybe I'm taking the wrong approach altogether?
To put, I hope gently, some points that have been made a great many
times:
First, a macro is almost always the hard way to solve a problem. It's
one more layer of code to debug, at the very least.
Second, if you have a macro and want to see what it's doing, run with
MPRINT set on; did you try that?
Third, if you're having trouble with any kind of loop, run it, if at
all possible, for a few iterations rather than a great many (like 510).
Fourth, both DO REPEAT, and LOOP over a VECTOR, are usually easier, and
certainly cleaner, ways to loop through a list of variables, than is a
macro loop. If your variables are in the order
RXDATENN1 RXDATENN1 ... RXDATENN510 NND1 NND2 ... NND510
those two ways of looping are easier than if the order is
RXDATENN1 NND1 RXDATENN2 NND2 ... RXDATENN510 NND510
In the former case, variable lists
RXDATENN1 TO RXDATENN510
and
NND1 TO NND510
give the results you'd want them to.
Now: if I understand you right, you want NNDISTANCE to be the value of
NNDn corresponding to the first RXDATENNn that is less than RXDATENN1.
Here's some of the expansion of your macro. (I've indented the COMPUTE
statements). And, of course, this will give you the NNDn corresponding
to the last RXDATENNn that is less than RXDATENN1.
PRESERVE.
SET MPRINT ON.
macdef arg1 = 1 arg2 = 510.
18 M>
19 M> .
20 M> DO IF RXDATENN1 < RXDATENN1.
21 M> . COMPUTE NNDISTANCE= NND1.
22 M> END IF.
23 M>
24 M> DO IF RXDATENN2 < RXDATENN1.
25 M> . COMPUTE NNDISTANCE= NND2.
26 M> END IF.
27 M>
28 M> DO IF RXDATENN3 < RXDATENN1.
29 M> . COMPUTE NNDISTANCE= NND3.
30 M> END IF.
[...]
2052 M> DO IF RXDATENN509 < RXDATENN1.
2053 M> . COMPUTE NNDISTANCE= NND509.
2054 M> END IF.
2055 M>
2056 M> DO IF RXDATENN510 < RXDATENN1.
2057 M> . COMPUTE NNDISTANCE= NND510.
2058 M> END IF.
2059 M> .
Here's a solution; I'm staying with the code, rather than tweaking the
macro:
. COMPUTE NNDISTANCE = $SYSMIS.
24 M> DO IF RXDATENN2 < RXDATENN1.
. IF MISSING(NNDISTANCE)
NNDISTANCE= NND2.
26 M> END IF.
27 M>
28 M> DO IF RXDATENN3 < RXDATENN1.
. IF MISSING(NNDISTANCE)
NNDISTANCE= NND3.
30 M> END IF.
If you still want to use the macro, build this change into it. It's
'wasteful' of computer time, since it goes on checking the rest of the
510 after it's found the one it wants, but that's rarely crucial. You
wrote,
>I want the macro to "stop" for a case when it satisfies the first date
>condition
That is probably shorthand for what you really mean, but to be clear: a
macro CANNOT 'stop' when a condition in the data is satisfied. The
macro runs to completion, and generates all its code, before SPSS even
looks at the data. The macro-generated code, plus any code you've
written directly, become the program that processes the data; at that
point, whether the code has been written directly or generated by a
macro, matters not at all.
Finally, this may not have been the only tough part of your problem. It
sounds like you started with 510 records, each with a date and a
location, and generated the records you describe in this posting. You
are, that is, comparing every one of your 510 with every other; and
SPSS plain isn't good at many-to-many logic. I don't know what we'd
have said about what I'm guessing was the initial problem, but building
those 510 records sounds like it was a bear.
Good luck, then,
Richard Ristow
....... Appendix: Macro definition and invocation ........
(Un-quoted, for clarity)
DEFINE macdef (arg1 = !TOKENS(1)
/arg2 = !TOKENS(1))
!DO !i = !arg1 !TO !arg2.
DO IF !CONCAT(RxDATENN,!i) < RxDATENN1.
COMPUTE NNdistance=!CONCAT(NND,!i).
END IF.
!DOEND
!ENDDEFINE.
macdef arg1 = 1 arg2 = 510.