LISTSERV at the University of Georgia
Menubar Imagemap
Home Browse Manage Request Manuals Register
Previous messageNext messagePrevious in topicNext in topicPrevious by same authorNext by same authorPrevious page (October 2005)Back to main SPSSX-L pageJoin or leave SPSSX-L (or change settings)ReplyPost a new messageSearchProportional fontNon-proportional font
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?
Comments: To: "Penfold, Robert" <PenfoldR@pediatrics.ohio-state.edu>
Comments: cc: Jon Peck <peck@spss.com>
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.


Back to: Top of message | Previous page | Main SPSSX-L page