1 package baseCode.math.metaanalysis;
2
3 import baseCode.math.CorrelationStats;
4 import cern.colt.list.DoubleArrayList;
5 import cern.jet.stat.Descriptive;
6 import cern.jet.stat.Probability;
7
8 /***
9 * Implementation of meta-analysis of correlations along the lines of chapter 18 of Cooper and Hedges, "Handbook of
10 * Research Synthesis". Both fixed and random effects models are supported, with z-transformed or untransformed
11 * correlations.
12 * <hr>
13 * <p>
14 * Copyright (c) 2004 Columbia University
15 *
16 * @author pavlidis
17 * @version $Id: CorrelationEffectMetaAnalysis.java,v 1.8 2005/03/21 18:01:03 pavlidis Exp $
18 */
19 public class CorrelationEffectMetaAnalysis extends MetaAnalysis {
20
21 private boolean transform = false;
22 private boolean fixed = true;
23
24 private double z;
25 private double p;
26 private double q;
27 private double e;
28 private double v;
29 private double n;
30 private double bsv;
31
32 public CorrelationEffectMetaAnalysis( boolean fixed, boolean transform ) {
33 this.fixed = fixed;
34 this.transform = transform;
35 }
36
37 public CorrelationEffectMetaAnalysis() {
38 }
39
40 /***
41 * Following CH section 2.2.
42 * <p>
43 * There are four possible cases (for now):
44 * <ol>
45 * <li>Fixed effects, Z-transformed. Weights are computed using CH eqns 18-8 and 18-3
46 * <li>Fixed effects, untransformed. Weights are computed using CH eqns 18-10 and 18-3
47 * <li>Random effects, Z-transformed. Weights are computed using CH eqns 18-20, 18-8 with 18-3
48 * <li>Random effects, untransformed. Weights are computed using CH eqns 18-10, 18-20, 18-24.
49 * </ol>
50 * The default is untransformed, fixed effects.
51 *
52 * @param correlations - NOT fisher transformed. This routine takes care of that.
53 * @param sampleSizes
54 * @return p-value. The p-value is also stored in the field p.
55 */
56 public double run( DoubleArrayList effects, DoubleArrayList sampleSizes ) {
57
58 DoubleArrayList weights;
59 DoubleArrayList conditionalVariances;
60 this.n = Descriptive.sum( sampleSizes );
61
62 if ( transform ) {
63 DoubleArrayList fzte = CorrelationStats.fisherTransform( effects );
64
65
66 conditionalVariances = fisherTransformedSamplingVariances( sampleSizes );
67 weights = metaFEWeights( conditionalVariances );
68 this.q = super.qStatistic( fzte, conditionalVariances, super.weightedMean( fzte, weights ) );
69
70 if ( !fixed ) {
71 this.bsv = metaREVariance( fzte, conditionalVariances, weights );
72
73 for ( int i = 0; i < conditionalVariances.size(); i++ ) {
74 conditionalVariances.setQuick( i, conditionalVariances.getQuick( i ) + bsv );
75 }
76 weights = metaFEWeights( conditionalVariances );
77 }
78
79 this.e = super.weightedMean( fzte, weights );
80 } else {
81
82 conditionalVariances = samplingVariances( effects, sampleSizes );
83 weights = metaFEWeights( conditionalVariances );
84 this.q = super.qStatistic( effects, conditionalVariances, super.weightedMean( effects, weights ) );
85
86 if ( !fixed ) {
87 this.bsv = metaREVariance( effects, conditionalVariances, weights );
88 for ( int i = 0; i < conditionalVariances.size(); i++ ) {
89 conditionalVariances.setQuick( i, conditionalVariances.getQuick( i ) + bsv );
90 }
91
92 weights = metaFEWeights( conditionalVariances );
93 }
94
95 this.e = super.weightedMean( effects, weights );
96 }
97 this.v = super.metaVariance( conditionalVariances );
98 this.z = Math.abs( e ) / Math.sqrt( v );
99 this.p = Probability.errorFunctionComplemented( z );
100
101
102
103
104
105
106
107 return p;
108 }
109
110 /***
111 * Equation 18-10 from CH. For untransformed correlations.
112 * <p>
113 *
114 * <pre>
115 * v_i = ( 1 - r_i ˆ 2 ) ˆ 2 / ( n_i - 1 )
116 * </pre>
117 *
118 * <p>
119 * I added a regularization to this, so that we don't get ridiculous variances when correlations are close to 1 (this
120 * happens). If the correlation is very close to 1 (or -1), we fudge it to be a value less close to 1 (e.g., 0.999)
121 * </p>
122 *
123 * @param r
124 * @param n
125 * @return
126 */
127 protected double samplingVariance( double r, double numsamples ) {
128
129 if ( numsamples <= 0 ) throw new IllegalArgumentException( "N must be greater than 0" );
130
131 if ( !CorrelationStats.isValidPearsonCorrelation( r ) )
132 throw new IllegalArgumentException( "r=" + r + " is not a valid Pearson correlation" );
133
134 double FUDGE = 0.001;
135 if ( Math.abs( r ) - 1.0 < FUDGE ) {
136 r = Math.abs( r ) - FUDGE;
137 }
138
139 if ( numsamples < 2 ) {
140 return Double.NaN;
141 }
142 double k = 1.0 - r * r;
143 double var = k * k / ( numsamples - 1 );
144
145 return var;
146 }
147
148 /***
149 * Run equation CH 18-10 on a list of sample sizes and effects.
150 *
151 * @param effectSizes
152 * @param sampleSizes
153 * @see samplingVariance
154 * @return
155 */
156 protected DoubleArrayList samplingVariances( DoubleArrayList effectSizes, DoubleArrayList sampleSizes ) {
157
158 if ( effectSizes.size() != sampleSizes.size() ) throw new IllegalArgumentException( "Unequal sample sizes." );
159
160 DoubleArrayList answer = new DoubleArrayList( sampleSizes.size() );
161 for ( int i = 0; i < sampleSizes.size(); i++ ) {
162
163 double ef = effectSizes.getQuick( i );
164
165 if ( Double.isNaN( ef ) ) {
166 answer.add( Double.NaN );
167 } else {
168 answer.add( samplingVariance( ef, sampleSizes.getQuick( i ) ) );
169 }
170 }
171 return answer;
172 }
173
174 /***
175 * Equation 18-8 from CH. For z-transformed correlations.
176 *
177 * <pre>
178 * v_i = 1 / ( n_i - 3 )
179 * </pre>
180 *
181 * @param n
182 * @return
183 */
184 protected double fisherTransformedSamplingVariance( double sampleSize ) {
185
186 if ( sampleSize <= 3.0 ) throw new IllegalStateException( "N is too small" );
187
188 return 1.0 / ( sampleSize - 3.0 );
189 }
190
191 /***
192 * Run equation CH 18-8 on a list of sample sizes.
193 *
194 * @param sampleSizes
195 * @return
196 */
197 protected DoubleArrayList fisherTransformedSamplingVariances( DoubleArrayList sampleSizes ) {
198
199 DoubleArrayList answer = new DoubleArrayList( sampleSizes.size() );
200 for ( int i = 0; i < sampleSizes.size(); i++ ) {
201 answer.add( fisherTransformedSamplingVariance( sampleSizes.getQuick( i ) ) );
202 }
203 return answer;
204 }
205
206 public void setFixed( boolean fixed ) {
207 this.fixed = fixed;
208 }
209
210 public void setTransform( boolean transform ) {
211 this.transform = transform;
212 }
213
214 public double getP() {
215 return p;
216 }
217
218 public double getQ() {
219 return q;
220 }
221
222 public double getZ() {
223 return z;
224 }
225
226 public double getE() {
227 return e;
228 }
229
230 public double getV() {
231 return v;
232 }
233
234 public double getN() {
235 return n;
236 }
237
238 public double getBsv() {
239 return bsv;
240 }
241 }