<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: Help with 3:1 propensity score matching using macro in New SAS User</title>
    <link>https://communities.sas.com/t5/New-SAS-User/Help-with-3-1-propensity-score-matching-using-macro/m-p/523978#M4728</link>
    <description>&lt;P&gt;You stared with: N=427, so if you want a 1:3 match, that becomes 1281 records.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Each treatment is matched with 3 controls. If you have a unique variable that identifies your rows, check your data and you should find that you have duplicates of your case data, triplicates and each control should be unique.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;EDIT:&lt;/P&gt;
&lt;P&gt;Please include code in a code block in the future and if you're using SAS 9.4 TSM5+ there is a PROC PSMATCH now available to do these types of matching as well.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Source of macro: &lt;A href="http://www2.sas.com/proceedings/forum2007/185-2007.pdf" target="_blank"&gt;http://www2.sas.com/proceedings/forum2007/185-2007.pdf&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;HR /&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/247921"&gt;@Jarot741&lt;/a&gt;&amp;nbsp;wrote:&lt;BR /&gt;
&lt;P&gt;Hi all,&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I need help with the following:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;PRE-Matching&lt;/P&gt;
&lt;P&gt;My treatment cohort is 427 and the control 4079&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;POST-Matching&lt;/P&gt;
&lt;P&gt;My treatment cohort is 1281 and the control 1281&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I am wanting to do a 3:1 match, and not sure why I ended up with the last numbers.&lt;/P&gt;
&lt;P&gt;I am using this macro by Marcelo Coca Perraillon Paper 185-2007:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%macro PSMatching(datatreatment=, datacontrol=, method=, numberofcontrols=, 
        caliper=, replacement=, out=);
    /* Create copies of the treated units if N &amp;gt; 1 */;

    data _Treatment0(drop=i);
        set &amp;amp;datatreatment;

        do i=1 to &amp;amp;numberofcontrols;
            RandomNumber=ranuni(12345);
            output;
        end;
    run;

    /* Randomly sort both datasets */
    proc sort data=_Treatment0 out=_Treatment(drop=RandomNumber);
        by RandomNumber;
    run;

    data _Control0;
        set &amp;amp;datacontrol;
        RandomNumber=ranuni(45678);
    run;

    proc sort data=_Control0 out=_Control(drop=RandomNumber);
        by RandomNumber;
    run;

    data Matched(keep=IdSelectedControl PScoreControl MatchedToTreatID 
            PScoreTreat);
        length pscoreC 8;
        length idC 8;

        /* Load Control dataset into the hash object */
        if _N_=1 then
            do;
                declare hash h(dataset: "_Control", ordered: 'no');
                declare hiter iter('h');
                h.defineKey('idC');
                h.defineData('pscoreC', 'idC');
                h.defineDone();
                call missing(idC, pscoreC);
            end;

        /* Open the treatment */
        set _Treatment;

        %if %upcase(&amp;amp;method) ~=RADIUS %then
            %do;
                retain BestDistance 99;
            %end;

        /* Iterate over the hash */
        rc=iter.first();

        if (rc=0) then
            BestDistance=99;

        do while (rc=0);

            /* Caliper */

            %if %upcase(&amp;amp;method)=CALIPER %then
                %do;

                    if (pscoreT - &amp;amp;caliper) &amp;lt;=pscoreC &amp;lt;=(pscoreT + &amp;amp;caliper) then
                        do;
                            ScoreDistance=abs(pscoreT - pscoreC);

                            if ScoreDistance &amp;lt; BestDistance then
                                do;
                                    BestDistance=ScoreDistance;
                                    IdSelectedControl=idC;
                                    PScoreControl=pscoreC;
                                    MatchedToTreatID=idT;
                                    PScoreTreat=pscoreT;
                                end;
                        end;
                %end;

            /* NN */

            %if %upcase(&amp;amp;method)=NN %then
                %do;
                    ScoreDistance=abs(pscoreT - pscoreC);

                    if ScoreDistance &amp;lt; BestDistance then
                        do;
                            BestDistance=ScoreDistance;
                            IdSelectedControl=idC;
                            PScoreControl=pscoreC;
                            MatchedToTreatID=idT;
                            PScoreTreat=pscoreT;
                        end;
                %end;

            %if %upcase(&amp;amp;method)=NN or %upcase(&amp;amp;method)=CALIPER %then
                %do;
                    rc=iter.next();

                    /* Output the best control and remove it */
                    if (rc ~=0) and BestDistance ~=99 then
                        do;
                            output;

                            %if %upcase(&amp;amp;replacement)=NO %then
                                %do;
                                    rc1=h.remove(key: IdSelectedControl);
                                %end;
                        end;
                %end;

            /* Radius */

            %if %upcase(&amp;amp;method)=RADIUS %then
                %do;

                    if (pscoreT - &amp;amp;caliper) &amp;lt;=pscoreC &amp;lt;=(pscoreT + &amp;amp;caliper) then
                        do;
                            IdSelectedControl=idC;
                            PScoreControl=pscoreC;
                            MatchedToTreatID=idT;
                            PScoreTreat=pscoreT;
                            output;
                        end;
                    rc=iter.next();
                %end;
        end;
    run;

    /* Delete temporary tables. Quote for debugging */
    proc datasets;
        delete _ : gennum=all);
        run;

    data &amp;amp;out;
        set Matched;
    run;

%mend PSMatching;

*And I am invoking it;
&amp;nbsp;
%PSMatching(datatreatment=PNET._MIPD_YES, datacontrol=PNET._MIPD_NO, method=NN, 
    numberofcontrols=3, caliper=0.1, replacement=NO, out=MATCHES);
RUN;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Any ideas?&lt;/P&gt;
&lt;P&gt;Thanks,&lt;/P&gt;
&lt;P&gt;J&lt;/P&gt;
&lt;HR /&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
    <pubDate>Tue, 01 Jan 2019 00:27:02 GMT</pubDate>
    <dc:creator>Reeza</dc:creator>
    <dc:date>2019-01-01T00:27:02Z</dc:date>
    <item>
      <title>Help with 3:1 propensity score matching using macro</title>
      <link>https://communities.sas.com/t5/New-SAS-User/Help-with-3-1-propensity-score-matching-using-macro/m-p/523904#M4709</link>
      <description>&lt;P&gt;Hi all,&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;I need help with the following:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;PRE-Matching&lt;/P&gt;&lt;P&gt;My treatment cohort is 427 and the control 4079&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;POST-Matching&lt;/P&gt;&lt;P&gt;My treatment cohort is 1281 and the control 1281&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;I am wanting to do a 3:1 match, and not sure why I ended up with the last numbers.&lt;/P&gt;&lt;P&gt;I am using this macro by Marcelo Coca Perraillon Paper 185-2007:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;%macro PSMatching(datatreatment=, datacontrol=,&lt;BR /&gt;method=, numberofcontrols=, caliper=,&lt;BR /&gt;&amp;nbsp;replacement=, out=);&lt;BR /&gt;&lt;BR /&gt;/* Create copies of the treated units if N &amp;gt; 1 */;&lt;BR /&gt;&amp;nbsp;data _Treatment0(drop= i);&lt;BR /&gt;&amp;nbsp; set &amp;amp;datatreatment;&lt;BR /&gt;&amp;nbsp; do i= 1 to &amp;amp;numberofcontrols;&lt;BR /&gt;&amp;nbsp; RandomNumber= ranuni(12345);&lt;BR /&gt;output;&lt;BR /&gt;end;&lt;BR /&gt;run;&lt;BR /&gt;&lt;BR /&gt;/* Randomly sort both datasets */&lt;BR /&gt;proc sort data= _Treatment0 out= _Treatment(drop= RandomNumber);&lt;BR /&gt;by RandomNumber;&lt;BR /&gt;run;&lt;BR /&gt;data _Control0;&lt;BR /&gt;set &amp;amp;datacontrol;&lt;BR /&gt;RandomNumber= ranuni(45678);&lt;BR /&gt;run;&lt;BR /&gt;proc sort data= _Control0 out= _Control(drop= RandomNumber);&lt;BR /&gt;by RandomNumber;&lt;BR /&gt;run;&lt;BR /&gt;&lt;BR /&gt;&amp;nbsp;data Matched(keep = IdSelectedControl PScoreControl MatchedToTreatID PScoreTreat);&lt;BR /&gt;&amp;nbsp; length pscoreC 8;&lt;BR /&gt;&amp;nbsp; length idC 8;&lt;BR /&gt;/* Load Control dataset into the hash object */&lt;BR /&gt;&amp;nbsp; if _N_= 1 then do;&lt;BR /&gt;declare hash h(dataset: "_Control", ordered: 'no');&lt;BR /&gt;declare hiter iter('h');&lt;BR /&gt;h.defineKey('idC');&lt;BR /&gt;h.defineData('pscoreC', 'idC');&lt;BR /&gt;h.defineDone();&lt;BR /&gt;call missing(idC, pscoreC);&lt;BR /&gt;end;&lt;BR /&gt;/* Open the treatment */&lt;BR /&gt;set _Treatment;&lt;BR /&gt;%if %upcase(&amp;amp;method) ~= RADIUS %then %do;&lt;BR /&gt;retain BestDistance 99;&lt;BR /&gt;%end;&lt;BR /&gt;/* Iterate over the hash */&lt;BR /&gt;rc= iter.first();&lt;BR /&gt;if (rc=0) then BestDistance= 99;&lt;BR /&gt;do while (rc = 0);&lt;BR /&gt;&lt;BR /&gt;&lt;BR /&gt;/* Caliper */&lt;BR /&gt;%if %upcase(&amp;amp;method) = CALIPER %then %do;&lt;BR /&gt;if (pscoreT - &amp;amp;caliper) &amp;lt;= pscoreC &amp;lt;= (pscoreT + &amp;amp;caliper) then do;&lt;BR /&gt;ScoreDistance = abs(pscoreT - pscoreC);&lt;BR /&gt;if ScoreDistance &amp;lt; BestDistance then do;&lt;BR /&gt;BestDistance = ScoreDistance;&lt;BR /&gt;IdSelectedControl = idC;&lt;BR /&gt;PScoreControl =&amp;nbsp; pscoreC;&lt;BR /&gt;MatchedToTreatID = idT;&lt;BR /&gt;PScoreTreat = pscoreT;&lt;BR /&gt;end;&lt;BR /&gt;end;&lt;BR /&gt;%end;&lt;BR /&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;BR /&gt;/* NN */&lt;BR /&gt;%if %upcase(&amp;amp;method) = NN %then %do;&lt;BR /&gt;ScoreDistance = abs(pscoreT - pscoreC);&lt;BR /&gt;if ScoreDistance &amp;lt; BestDistance then do;&lt;BR /&gt;BestDistance = ScoreDistance;&lt;BR /&gt;IdSelectedControl = idC;&lt;BR /&gt;PScoreControl =&amp;nbsp; pscoreC;&lt;BR /&gt;MatchedToTreatID = idT;&lt;BR /&gt;PScoreTreat = pscoreT;&lt;BR /&gt;end;&lt;BR /&gt;%end;&lt;BR /&gt;&lt;BR /&gt;%if %upcase(&amp;amp;method) = NN or %upcase(&amp;amp;method) = CALIPER %then %do;&lt;BR /&gt;rc = iter.next();&lt;BR /&gt;/* Output the best control and remove it */&lt;BR /&gt;if (rc ~= 0) and BestDistance ~=99 then do;&lt;BR /&gt;output;&lt;BR /&gt;%if %upcase(&amp;amp;replacement) = NO %then %do;&lt;BR /&gt;rc1 = h.remove(key: IdSelectedControl);&lt;BR /&gt;%end;&lt;BR /&gt;end;&lt;BR /&gt;%end;&lt;BR /&gt;/* Radius */&lt;BR /&gt;%if %upcase(&amp;amp;method) = RADIUS %then %do;&lt;BR /&gt;if (pscoreT - &amp;amp;caliper) &amp;lt;= pscoreC &amp;lt;= (pscoreT + &amp;amp;caliper) then do;&lt;BR /&gt;IdSelectedControl = idC;&lt;BR /&gt;PScoreControl =&amp;nbsp; pscoreC;&lt;BR /&gt;MatchedToTreatID = idT;&lt;BR /&gt;PScoreTreat = pscoreT;&lt;BR /&gt;output;&lt;BR /&gt;end;&lt;BR /&gt;rc = iter.next();&lt;BR /&gt;%end;&lt;BR /&gt;end;&lt;BR /&gt;run;&lt;BR /&gt;/* Delete temporary tables. Quote for debugging */&lt;BR /&gt;proc datasets;&lt;BR /&gt;delete _ : gennum=all);&lt;BR /&gt;&lt;BR /&gt;run;&lt;BR /&gt;&amp;nbsp;data &amp;amp;out;&lt;BR /&gt;&amp;nbsp;&amp;nbsp; set Matched;&lt;BR /&gt;&amp;nbsp;run;&lt;BR /&gt;%mend PSMatching;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;And I am invoking it :&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;%PSMatching(datatreatment=PNET._MIPD_YES, datacontrol=PNET._MIPD_NO,&lt;BR /&gt;method=NN, numberofcontrols=3, caliper=0.1, replacement=NO, out=MATCHES); RUN;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Any ideas?&lt;/P&gt;&lt;P&gt;Thanks,&lt;/P&gt;&lt;P&gt;J&lt;/P&gt;</description>
      <pubDate>Mon, 31 Dec 2018 02:06:21 GMT</pubDate>
      <guid>https://communities.sas.com/t5/New-SAS-User/Help-with-3-1-propensity-score-matching-using-macro/m-p/523904#M4709</guid>
      <dc:creator>Jarot741</dc:creator>
      <dc:date>2018-12-31T02:06:21Z</dc:date>
    </item>
    <item>
      <title>Re: Help with 3:1 propensity score matching using macro</title>
      <link>https://communities.sas.com/t5/New-SAS-User/Help-with-3-1-propensity-score-matching-using-macro/m-p/523978#M4728</link>
      <description>&lt;P&gt;You stared with: N=427, so if you want a 1:3 match, that becomes 1281 records.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Each treatment is matched with 3 controls. If you have a unique variable that identifies your rows, check your data and you should find that you have duplicates of your case data, triplicates and each control should be unique.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;EDIT:&lt;/P&gt;
&lt;P&gt;Please include code in a code block in the future and if you're using SAS 9.4 TSM5+ there is a PROC PSMATCH now available to do these types of matching as well.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Source of macro: &lt;A href="http://www2.sas.com/proceedings/forum2007/185-2007.pdf" target="_blank"&gt;http://www2.sas.com/proceedings/forum2007/185-2007.pdf&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;HR /&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/247921"&gt;@Jarot741&lt;/a&gt;&amp;nbsp;wrote:&lt;BR /&gt;
&lt;P&gt;Hi all,&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I need help with the following:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;PRE-Matching&lt;/P&gt;
&lt;P&gt;My treatment cohort is 427 and the control 4079&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;POST-Matching&lt;/P&gt;
&lt;P&gt;My treatment cohort is 1281 and the control 1281&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I am wanting to do a 3:1 match, and not sure why I ended up with the last numbers.&lt;/P&gt;
&lt;P&gt;I am using this macro by Marcelo Coca Perraillon Paper 185-2007:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%macro PSMatching(datatreatment=, datacontrol=, method=, numberofcontrols=, 
        caliper=, replacement=, out=);
    /* Create copies of the treated units if N &amp;gt; 1 */;

    data _Treatment0(drop=i);
        set &amp;amp;datatreatment;

        do i=1 to &amp;amp;numberofcontrols;
            RandomNumber=ranuni(12345);
            output;
        end;
    run;

    /* Randomly sort both datasets */
    proc sort data=_Treatment0 out=_Treatment(drop=RandomNumber);
        by RandomNumber;
    run;

    data _Control0;
        set &amp;amp;datacontrol;
        RandomNumber=ranuni(45678);
    run;

    proc sort data=_Control0 out=_Control(drop=RandomNumber);
        by RandomNumber;
    run;

    data Matched(keep=IdSelectedControl PScoreControl MatchedToTreatID 
            PScoreTreat);
        length pscoreC 8;
        length idC 8;

        /* Load Control dataset into the hash object */
        if _N_=1 then
            do;
                declare hash h(dataset: "_Control", ordered: 'no');
                declare hiter iter('h');
                h.defineKey('idC');
                h.defineData('pscoreC', 'idC');
                h.defineDone();
                call missing(idC, pscoreC);
            end;

        /* Open the treatment */
        set _Treatment;

        %if %upcase(&amp;amp;method) ~=RADIUS %then
            %do;
                retain BestDistance 99;
            %end;

        /* Iterate over the hash */
        rc=iter.first();

        if (rc=0) then
            BestDistance=99;

        do while (rc=0);

            /* Caliper */

            %if %upcase(&amp;amp;method)=CALIPER %then
                %do;

                    if (pscoreT - &amp;amp;caliper) &amp;lt;=pscoreC &amp;lt;=(pscoreT + &amp;amp;caliper) then
                        do;
                            ScoreDistance=abs(pscoreT - pscoreC);

                            if ScoreDistance &amp;lt; BestDistance then
                                do;
                                    BestDistance=ScoreDistance;
                                    IdSelectedControl=idC;
                                    PScoreControl=pscoreC;
                                    MatchedToTreatID=idT;
                                    PScoreTreat=pscoreT;
                                end;
                        end;
                %end;

            /* NN */

            %if %upcase(&amp;amp;method)=NN %then
                %do;
                    ScoreDistance=abs(pscoreT - pscoreC);

                    if ScoreDistance &amp;lt; BestDistance then
                        do;
                            BestDistance=ScoreDistance;
                            IdSelectedControl=idC;
                            PScoreControl=pscoreC;
                            MatchedToTreatID=idT;
                            PScoreTreat=pscoreT;
                        end;
                %end;

            %if %upcase(&amp;amp;method)=NN or %upcase(&amp;amp;method)=CALIPER %then
                %do;
                    rc=iter.next();

                    /* Output the best control and remove it */
                    if (rc ~=0) and BestDistance ~=99 then
                        do;
                            output;

                            %if %upcase(&amp;amp;replacement)=NO %then
                                %do;
                                    rc1=h.remove(key: IdSelectedControl);
                                %end;
                        end;
                %end;

            /* Radius */

            %if %upcase(&amp;amp;method)=RADIUS %then
                %do;

                    if (pscoreT - &amp;amp;caliper) &amp;lt;=pscoreC &amp;lt;=(pscoreT + &amp;amp;caliper) then
                        do;
                            IdSelectedControl=idC;
                            PScoreControl=pscoreC;
                            MatchedToTreatID=idT;
                            PScoreTreat=pscoreT;
                            output;
                        end;
                    rc=iter.next();
                %end;
        end;
    run;

    /* Delete temporary tables. Quote for debugging */
    proc datasets;
        delete _ : gennum=all);
        run;

    data &amp;amp;out;
        set Matched;
    run;

%mend PSMatching;

*And I am invoking it;
&amp;nbsp;
%PSMatching(datatreatment=PNET._MIPD_YES, datacontrol=PNET._MIPD_NO, method=NN, 
    numberofcontrols=3, caliper=0.1, replacement=NO, out=MATCHES);
RUN;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Any ideas?&lt;/P&gt;
&lt;P&gt;Thanks,&lt;/P&gt;
&lt;P&gt;J&lt;/P&gt;
&lt;HR /&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Tue, 01 Jan 2019 00:27:02 GMT</pubDate>
      <guid>https://communities.sas.com/t5/New-SAS-User/Help-with-3-1-propensity-score-matching-using-macro/m-p/523978#M4728</guid>
      <dc:creator>Reeza</dc:creator>
      <dc:date>2019-01-01T00:27:02Z</dc:date>
    </item>
  </channel>
</rss>

