performing chi squared test in SAS using PROC FREQ - sas

Our university is forcing us to perform the old school chi square test using PROC FREQ (I am aware of the options with proc univariate).
I have generated one theoretical exponential distribution with Beta=15 (and written down the values laboriously), and I've generated 10000 random variables which have an exponential distribution, with beta=15.
I try to first enter the frequencies of my random variables (in each interval) via the datalines command:
data expofaktiska;
input number count;
datalines;
1 2910
2 2040
3 1400
4 1020
5 732
6 531
7 377
8 305
9 210
10 144
11 106
12 66
13 40
14 45
15 29
16 16
17 12
18 8
19 8
20 3
21 2
22 0
23 1
24 2
25 0
26 2
;
run;
This seems to work.
I then try to compare these values to the theoretical values, using the chi square test in proc freq (the one we are supposed to use)
As follows:
proc freq data=expofaktiska;
weight count;
tables number / testp=(0.28347 0.20311 0.14554 0.10428 0.07472 0.05354 0.03837 0.02749 0.01969 0.01412 0.01011 0.00724 0.0052 0.00372 0.00266 0.00191 0.00137 0.00098 0.00070 0.00051 0.00036 0.00026 0.00018 0.00013 0.00010 0.00007) chisq;
run;
I get the following error:
ERROR: The number of TESTP values does not equal the number of levels. For the table of number,
there are 24 levels and 26 TESTP values.
This may be because two intervals contain 0 obervations. I don't really see a way around this.
Also, I don't get the chi square test in the results viewer, nor the "tes probability", I only the frequency/cumulative frequency of the random variables.
What am I doing wrong? Do both theoretical/actual distributions need to have the same form (probability/frequencies?)
We are using SAS 9.4
Thanks in advance!
/Magnus

You need ZEROS options on the WEIGHT statement.
data expofaktiska;
input number count;
datalines;
1 2910
2 2040
3 1400
4 1020
5 732
6 531
7 377
8 305
9 210
10 144
11 106
12 66
13 40
14 45
15 29
16 16
17 12
18 8
19 8
20 3
21 2
22 0
23 1
24 2
25 0
26 2
;
run;
proc freq data=expofaktiska;
weight count / zeros;
tables number / testp=(0.28347 0.20311 0.14554 0.10428 0.07472 0.05354 0.03837 0.02749 0.01969 0.01412 0.01011 0.00724 0.0052 0.00372 0.00266 0.00191 0.00137 0.00098 0.00070 0.00051 0.00036 0.00026 0.00018 0.00013 0.00010 0.00007) chisq;
run;

Related

SAS Change the first record

Let's imagine the following table ...
obs
State
Imp
i
i2
1
me
100
100
2
me
90
100
100
3
me
80
100
100
4
me
70
100
100
5
me
1000
1000
100
6
me
900
1000
1000
7
me
800
1000
1000
8
me
0
1000
1000
9
me
2000
2000
1000
10
me
1900
2000
2000
11
gu
20
2000
2000
12
ca
40
2000
2000
13
ca
50
2000
2000
14
ca
30
2000
2000
15
ca
10
2000
2000
as you can see column "i2" is lag (i). What I want to do is:
1.- column "i" finds the maximum value as it progresses, so i want to reset that column
"i" every first "state", in order to get that maximum value of each state.
2.- modify the column "i2" so that it is as follows:
that each first value of "State" (obs 1-me, 11-gu and 12-ca) column "i" has the value
of column "imp"
obs
State
Imp
i
i2
1
me
100
100
100
2
me
90
100
100
3
me
80
100
100
4
me
70
100
100
5
me
1000
1000
100
6
me
900
1000
1000
7
me
800
1000
1000
8
me
0
1000
1000
9
me
2000
2000
1000
10
me
1900
2000
2000
11
gu
20
20
20
12
ca
40
40
40
13
ca
50
50
40
14
ca
30
50
50
15
ca
10
50
50
i have tried with this code, but it doesn't work
data metodo;
set sa80;
retain i;
if first.state then i=max(imp);
else i = max(imp,i);
i2 = lag(i);
run;
data final;
set metodo;
retain i2_aux;
if first.state then i2_aux = total;
else i2_aux = i2;
run;
Hope you could help, and thank you in advance
The main thing it not use an existing variable as the new RETAINed variable because then each time the SET statement executes the value retained is replaced with the value read from the input.
It also helps if the data is sorted by the key variable, although you can use the NOTSORTED keyword on the BY statement to process grouped, but not sorted, data.
data have;
input state $ imp ;
cards;
ca 40
ca 50
ca 30
ca 10
gu 20
me 100
me 90
me 80
me 70
me 1000
me 900
me 800
me 0
me 2000
me 1900
;
data want;
set have ;
by state notsorted;
retain i;
i=max(i,imp);
if first.state then i=imp;
i2=lag(i);
if first.state then i2=imp;
run;
Results:
Obs state imp i i2
1 ca 40 40 40
2 ca 50 50 40
3 ca 30 50 50
4 ca 10 50 50
5 gu 20 20 20
6 me 100 100 100
7 me 90 100 100
8 me 80 100 100
9 me 70 100 100
10 me 1000 1000 100
11 me 900 1000 1000
12 me 800 1000 1000
13 me 0 1000 1000
14 me 2000 2000 1000
15 me 1900 2000 2000
Fixed order of resetting I and LAG(I) call.

SAS_Add value for specific rows

I want to give the value for some specific rows. I think showing it by example would be better. I have following datasheet;
Date Value
01/01/2001 10
02/01/2001 20
03/01/2001 35
04/01/2001 15
05/01/2001 25
06/01/2001 35
07/01/2001 20
08/01/2001 45
09/01/2001 35
My result should be:
Date Value Spec.Value
01/01/2001 10 1
02/01/2001 20 1
03/01/2001 35 1
04/01/2001 15 2
05/01/2001 25 2
06/01/2001 35 2
07/01/2001 20 3
08/01/2001 45 3
09/01/2001 35 3
As you can see, my condition value is 35. I have three 35. I need to group my date by using this condition value.
data want;
set have;
retain specvalue 1;
if lag(value) = 35 then do;
specvalue +1;
end;
run;

SAS: retain the largest value of several possible values

This is a SAS question. The following lines for two people are ordered by ascending AdmitNum. Ascending AdmitNum is based on ascending dates, which are omitted. Ages are provided for each AdmitNum. Age decreases between some of the observations. I don't want this to occur. Age must be equal or increase.
If the next age is less than the current age, then I want the current age to be written into the new variable NeedAge. In other words, retain the greater age while it is the greater age.
Person 2 has the wrong age, 43, in three rows. These should be 53. Person 2's age changes to 54 when AdmitNum=5 and this value, 54, should be retained.
After several attempts I have had only had partial success. Can someone suggest a way to make NeedAge as shown below? Thanks.
ID AdmitNum HaveAge NeedAge
1 1 51 51
1 2 48 51
1 3 51 51
1 4 49 51
2 1 53 53
2 2 43 53
2 3 43 53
2 4 43 53
2 5 54 54
data have;
input ID AdmitNum HaveAge;
datalines;
1 1 51
1 2 48
1 3 51
1 4 49
2 1 53
2 2 43
2 3 43
2 4 43
2 5 54
;
run;
data want;
set have;
by ID;
if _n_ = 1 NeedAge = HaveAge;
if HaveAge > NeedAge then NeedAge = HaveAge;
retain NeedAge;
run;
Check if HaveAge exceeds NeedAge, and if so, replace NeedAge with HaveAge. Then retain.
data have;
input ID AdmitNum HaveAge;
datalines;
1 1 51
1 2 48
1 3 51
1 4 49
2 1 53
2 2 43
2 3 43
2 4 43
2 5 54
;
run;
data want;
set have;
by ID;
if HaveAge > NeedAge then NeedAge = HaveAge;
retain NeedAge;
run;

Cumulative sum in multiple columns in SAS

I have been searching the solution a while, but I couldn't find any similar question in SAS in communities. So here is my question: I have a big SAS table: let's say with 2 classes and 26 variables:
A B Var1 Var2 ... Var25 Var26
-----------------------------
1 1 10 20 ... 35 30
1 2 12 24 ... 32 45
1 3 20 23 ... 24 68
2 1 13 29 ... 22 57
2 2 32 43 ... 33 65
2 3 11 76 ... 32 45
...................
...................
I need to calculate the cumulative sum of the all 26 variables through the Class=B, which means that for A=1, it will accumulate through B=1,2,3; and for A=2 it will accumulate through B=1,2,3. The resulting table will be like:
A B Cum1 Cum2 ... Cum25 Cum26
-----------------------------
1 1 10 20 ... 35 30
1 2 22 44 ... 67 75
1 3 40 67 ... 91 143
2 1 13 29 ... 22 57
2 2 45 72 ... 55 121
2 3 56 148 .. 87 166
...................
...................
I can choose the hard way, like describing each of 26 variables in a loop, and then I can find the cumulative sums through B. But I want to find a more practical solution for this without describing all the variables.
On one of the websites was suggested a solution like this:
proc sort data= (drop=percent cum_pct rename=(count=demand cum_freq=cal));
weight var1;
run;
I am not sure if there is any option like "Weight" in Proc Sort, but if it works then I thought that maybe I can modify it by putting numeric instead of Var1, then the Proc Sort process can do the process for all the numerical values :
proc sort data= (drop=percent cum_pct rename=(count=demand cum_freq=cal));
weight _numerical_;
run;
Any ideas?
One way to accomplish this is to use 2 'parallel' arrays, one for your input values and another for the cumulative values.
%LET N = 26 ;
data cum ;
set have ;
by A B ;
array v{*} var1-var&N ;
array c{*] cum1-cum&N ;
retain c . ;
if first.A then call missing(of c{*}) ; /* reset on new values of A */
do i = 1 to &N ;
c{i} + v{i} ;
end ;
drop i ;
run ;

Use collapse like summarize

I want to use Stata's collapse like summarize. Say I have data (the 1's correspond to the same person, so do the 2's and the 3's) that, when summarized, looks like this:
Obs Mean Std. Dev. Min Max
Score1 54 17 3 11 22
Score2 32 13 2 5 28
Score3 43 22 4 17 33
Value1 54 9 3 2 12
Value2 32 31 7 22 44
Value3 43 38 4 31 45
Speed1 54 3 1 1 11
Speed2 32 6 3 2 12
Speed3 43 8 2 2 15
How would I create a new dataset (using collapse or something else) that looks somewhat like what summarize gives, but looks like the following? Note that the numbers after the variables correspond to observations in my data. So Score1, Value1, and Speed1 all correspond to _n==1.
_n ScoreMean ValueMean SpeedMean ScoreMax ValueMax SpeedMax
1 17 9 3 22 12 11
2 13 31 6 28 44 12
3 22 38 8 33 45 15
(I have omitted Std. Dev. and Min for brevity.)
When I run collapse (mean) Score1 Score2 Score3 Value1 Value2 Value3 Speed1 Speed2 Speed3, I get the following, which is not very helpful:
Score1 Score2 Score3 Value1 Value2 Value3 Speed1 Speed2 Speed3
1 17 13 22 9 31 38 3 6 8
This is on the right track. It only gives me the mean, though. I am not sure how to have it give me more than one statistic at once. I think I need to somehow use reshape at some point.
One way, following your lead:
*clear all
set more off
input ///
score1 score2 value1 value2 speed1 speed2
5 8 346 235 80 89
2 10 642 973 65 78
end
list
summarize
*-----
collapse (mean) score1m=score1 score2m=score2 ///
value1m=value1 value2m=value2 ///
speed1m=speed1 speed2m=speed2 ///
(max) score1max=score1 score2max=score2 ///
value1max=value1 value2max=value2 ///
speed1max=speed1 speed2max=speed2
gen obs = _n
reshape long score#m score#max value#m value#max speed#m speed#max, i(obs) j(n)
drop obs
list
Asking for several statistics is easy. Use the [(stat)] target_var=varname syntax so you don't get conflicting names when asking for several statistics. Then, reshape.
If there are many variables/subjects, it will turn very tedious. There are other ways. I will revise the answer later if no one posts an alternative by then.
This starts with Roberto's example toy dataset. I think it generalises more easily to 800 objects. (By the way, in Stata _n always and only means observation number in current dataset or group defined by by:, so your usage is mild abuse of syntax.)
clear
input score1 score2 value1 value2 speed1 speed2
5 8 346 235 80 89
2 10 642 973 65 78
end
gen j = _n
reshape long score value speed, i(j) j(i)
rename score yscore
rename value yvalue
rename speed yspeed
reshape long y, i(i j) j(what) string
collapse (mean) mean=y (min) min=y (max) max=y, by(what i)
reshape wide mean min max, j(what) i(i) string