Join Now

Beregning af median for flere variable samtidigt, hvor den ene variabel skal være styrende

by Occasional Contributor MartinJeppesen on ‎11-17-2015 10:19 AM (875 Views)

Hej SAS community DK

 

Jeg har lavet en proc means med beregning af median for to variable, som fx:

 

proc means data=stru2014.stru2014;

class hvdbr;

var lqnpup lqn;

output out= tjek median = ;

run;

 

Resultatet er 2 medianværdier, som er beregnet isoleret fra hinanden.

 

Det jeg i virkeligheden gerne vil, er at have medianværdien beregnet for den første variable "lqnpup" og så blot have værdien for "lqn" for samme observation med ud i outputtet.

 

Kender nogen til en smart metode at gøre dette på?

 

mvh

Martin

Comments
by SAS Employee GeorgMorsing
on ‎11-18-2015 08:16 AM

Hej Martin,

 

Er det dette du ønsker?

 

proc sql;

select weight, median(height) as height_median from sashelp.class;

run;

 

Jeg bruger lige en tabel vi alle har adgang til. Altså, vælg en kolonne og så tage median af en anden kolonne på hver observation.

by Occasional Contributor MartinJeppesen
on ‎11-18-2015 08:35 AM

Hej Georg

 

Tak for svaret. Så vidt jeg kan se, giver din løsning mig medianen for samtlige observationer, samt værdien for den tilknyttede variabel (weight). Så mit output har lige så mange rækker som mit input.

 

Det jeg gerne vil opnå, er at finde medianværdien for det samlede materiale - i eksemplet 62,8, samt den tilhørende vægt (102,5 som er Carols værdi)

 

Hvis jeg bruger proc means, får jeg i stedet værdien 99,5 for weight, fordi den beregner medianen for vægt uafhængigt af medianen for højde.

 

proc means data=sashelp.class median;

var height weight;

run;

by SAS Employee GeorgMorsing
on ‎11-18-2015 08:46 AM

Ja, jeg har lidt svært ved at forstå helt præcist hvad du vil have. Det er sikkert at det kan lade sig gøre. Det er svært for mig at forstå hvad du mener med "samlede materiale". Mener du alle værdier for en kolonne eller mener du alle værdier for begge kolonner?

 

Du vil altså have en median beregning (det kan så være for en eller to kolonner) og så blot have første observation i en tabel sammen med den median beregning?

 

Svar lige, så får du en løsning.

Georg

by Occasional Contributor MartinJeppesen
on ‎11-18-2015 08:57 AM

Jeg ved godt det er lidt kryptisk og sikker også uden for det normale.

 

Med det samlede materiale tænker jeg på de 19 observationer i eksemplet fra sashelp.class.

Her vil jeg gerne beregne medianen for height, og min proc means fortæller, at den er 62,8. Det er værdien for "Carol". Derudover vil jeg gerne have median-observationens værdi for weight - dvs. Carols værdi for weight, som er 102,5.

 

Hvis jeg beder proc means om median-værdien for weight, returnerer den 99,5, som er "Johns" værdi, og den er jeg ikke interesseret i.

 

Håber det giver nogenlunde mening.

by SAS Employee GeorgMorsing
on ‎11-18-2015 09:00 AM

Nu forstår jeg. Det giver da god mening. Jeg sender dig en løsning. Den er ikke helt simpel. Kommer imorgen.

 

by Occasional Contributor MartinJeppesen
on ‎11-18-2015 09:06 AM
Det glæder jeg mig til :-)
by SAS Employee GeorgMorsing
on ‎11-19-2015 03:21 AM

Hej,

 

Her er løsningen. Jeg ser i dit eksempel at du har et CLASS statement. Altså en gruppering. Så der skal findes en median for hver gruppe. Nedenstående kode kan udvides til dette.

 

Men er det dette du ville?  

 

Georg

 

* --- Find median og læg den i en makrovariabel ---;

proc sql noprint;

select median(height) into : median from sashelp.class;

run;

* --- Find rækken der er medianen og print den ---;

proc sql;

select name, weight, height from sashelp.class

where height=&median;

run;

* --- Find rækken der er medianen oog gem den i en tabel ---;

data hvem;

set sashelp.class;

where height=&median;

run;

by Occasional Contributor MartinJeppesen
on ‎11-19-2015 03:43 AM
Noget i den stil. Jeg håbede blot at man kunne gøre det ved en simpel option i proc means eller lignende.

Jeg undrer mig dog over, at jeg får en anden medianværdi for height ud af din kode, end når jeg anvender proc means. Jeg er ikke sikker på jeg helt forstår, hvordan median(height) i proc sql virker.

Den giver mig følgende warning:
WARNING: The MEDIAN function has been called with only one argument. However, it is not an SQL aggregate function, and this call
will not cause SQL aggregation.
by SAS Employee GeorgMorsing
on ‎11-19-2015 03:52 AM

Her er så en løsning hvor man ikke benytter SQL. Se nederst.

Der er ikke nogen PROC der kan gøre det du ønsker med en option. Derfor er man nødt til at lave til SAS Macro behandling. Har du ikke lært SAS MACRO vil jeg anbefale dig at gå på SAS Macro Language 1 kurset. Det kan man næsten ikke undvære hvis man arbejder med SAS.

 

Georg

 

 

* --- Find median og læg den i en makrovariabel ---;

proc sql noprint;

select median(height) into : median from sashelp.class;

run;

* --- Find rækken der er medianen og print den ---;

proc sql;

select name, weight, height from sashelp.class

where height=&median;

run;

* --- Find median og læg den i en makrovariabel ---;

* --- sammen løsning som øverste SQL, der skal blot to step til dette ---;

proc means data=sashelp.class noprint;

var height;

output out=tabel_median median=median_height;

run;

data _null_;

set tabel_median;

call symputx("median",median_height);

stop;

run;

* --- Find rækken der er medianen oog gem den i en tabel ---;

data hvem;

set sashelp.class;

where height=&median;

run;

by Occasional Contributor MartinJeppesen
on ‎11-19-2015 04:28 AM
Ok, tak for hjælpen :-)
mvh Martin
by New Contributor JakobBørstingSørensen
‎11-19-2015 12:28 PM - edited ‎11-19-2015 12:31 PM

Hej Martin og Georg

 

Vær opmærksom på at ovenstående løsning kun fungerer i tabeller med et ulige antal observationer(eller hvis de to midterste observationer har samme værdi).

 

Problemet opstår idet der ikke findes nogen entydigt "midterste" observation i et datasæt med et lige antal observationer. Medianen er derfor regnet som gennemsnittet af de to midterste observationer. Så med mindre disse er ens, vil median() outputte et tal som ikke findes i datasættet. Det sidste datastep, der danner datasættet "hvem", vil da være tomt.

 

Eksempelvis vil medianen af følgende tal 2, 5, 6, 14 være 5,5.

 

Nedstående kode tager højde for det, og finder de observationer frem, der matcher på de to tal, der er taget gennemsnit af (i ovenstående eksempel vil den tage observationer, der matcher 5 og 6). I tilfælde af et ulige antal rækker, vil outputtet være det samme:

 

/*Sorter datasættet efter højde*/
proc sort data=sashelp.class out=class_sort;
    by height;
run;

/*Find den/de midterste observation.*/
/*Bemærk: ceil(x) = floor(x) når x er heltal*/
data medVal;
    set class_sort nobs=antObs;

    if _n_ eq floor((antObs+1)/2) or _n_ eq ceil((antObs+1)/2);
run;

/*Der slåes op igen, for at sikre at alle matchende værdier kommer med ud*/
proc sql ;
    create table hvem as
    select * from sashelp.class
    where height in (select height from medVal);
quit;
by Occasional Contributor MartinJeppesen
on ‎11-20-2015 02:54 AM

Hej Jakob

 

Tak for inputtet, som bestemt er relevant, når koden skal være generisk. Jeg har dog en ekstra udfordring, idet jeg har brug for at vægte mine data, hvilket jo nemt gøres i en proc means, men jeg kan ikke lige se, hvordan man kan tilføje det i din ellers elegante løsning.

 

Har du et forslag til hvordan vægtning vil kunne tilføjes?

 

På forhånd tak

Martin

 

 

by New Contributor JakobBørstingSørensen
on ‎11-20-2015 01:14 PM

Hej

Ddu kan bruge nedstående kode. Jeg har defineret variabler man måtte ønske ændret i toppen. Det vil være oplagt at wrappe koden ind i en makro, hvis den skal genbruges. Det har jeg dog lige undladt her, af hensyn til farvelægningen af syntaxen.

 

Bemærk i øvrigt også at jeg ikke har testet hvordan den opfører sig med negative værdier af weight. Kan i hvert fald se det giver problemer hvis den summer til 0.

 

I eksemplet har jeg vægtet med alder, ved ikke hvor meget mening det giver, men det var lige den eneste numeriske variabel, der ikke har været brugt til andet.

 

/************Input************/
%let dsn  		= sashelp.class;	/*Datasæt til analyse*/
%let var  		= height;		  	/*Styrende variabel*/
%let weight 	= age;			  	/*Variabel der vægtes*/
%let ptile		= 50;				/*Percentil, 50 angiver medianen*/
/*****************************/


/*Sorter datasættet efter højde, derudover regnes summen af vægten*/
proc sql;
create table dsnSort as 
select *, sum(&weight) as sumW
from &dsn
order by &var
;quit;

/*Find den obsvation der har halvelen af vægtvariablen på hver sin side(For medianen)*/
data medVal;
	retain accSumW 0;
    set dsnSort;
    /*Der regnes en løbende akkumuleret sum*/
	accSumW + &weight;
		 
    if &ptile ge (accSumW-&weight)*100/sumW and &ptile le accSumW*100/sumW;
run;

/*Der slåes op igen, for at sikre at alle matchende værdier kommer med ud*/
proc sql ;
    create table hvem as
    select * from &dsn
    where &var in (select &var from medVal);
quit;

/*Kan udelades, men er fin til at validere med*/
proc means data=&dsn P&ptile;
VAR &var;
WEIGHT &weight;
RUN;

 

by Occasional Contributor MartinJeppesen
on ‎11-23-2015 09:01 AM
Hej Jakob
Det er perfekt. Jeg har ikke negative eller nul-vægte, så det giver mig ikke problemer.

Tusind tak for hjælpen.
Martin