Clover coverage report - baseCode - 0.2.5
Coverage timestamp: Tue Apr 12 2005 11:31:58 EDT
file stats: LOC: 241   Methods: 16
NCLOC: 122   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
CorrelationEffectMetaAnalysis.java 75% 84.8% 68.8% 80%
coverage coverage
 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; // z score
 25   
    private double p; // probability
 26   
    private double q; // q-score;
 27   
    private double e; // unconditional effect;
 28   
    private double v; // unconditional variance;
 29   
    private double n; // total sample size
 30   
    private double bsv; // between-studies variance component;
 31   
 
 32  36
    public CorrelationEffectMetaAnalysis( boolean fixed, boolean transform ) {
 33  36
       this.fixed = fixed;
 34  36
       this.transform = transform;
 35   
    }
 36   
 
 37  0
    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  9
    public double run( DoubleArrayList effects, DoubleArrayList sampleSizes ) {
 57   
 
 58  9
       DoubleArrayList weights;
 59  9
       DoubleArrayList conditionalVariances;
 60  9
       this.n = Descriptive.sum( sampleSizes );
 61   
 
 62  9
       if ( transform ) {
 63  5
          DoubleArrayList fzte = CorrelationStats.fisherTransform( effects );
 64   
 
 65   
          // initial values.
 66  5
          conditionalVariances = fisherTransformedSamplingVariances( sampleSizes );
 67  5
          weights = metaFEWeights( conditionalVariances );
 68  5
          this.q = super.qStatistic( fzte, conditionalVariances, super.weightedMean( fzte, weights ) );
 69   
 
 70  5
          if ( !fixed ) { // adjust the conditional variances and weights.
 71  2
             this.bsv = metaREVariance( fzte, conditionalVariances, weights );
 72   
 
 73  2
             for ( int i = 0; i < conditionalVariances.size(); i++ ) {
 74  40
                conditionalVariances.setQuick( i, conditionalVariances.getQuick( i ) + bsv );
 75   
             }
 76  2
             weights = metaFEWeights( conditionalVariances );
 77   
          }
 78   
 
 79  5
          this.e = super.weightedMean( fzte, weights );
 80   
       } else {
 81   
 
 82  4
          conditionalVariances = samplingVariances( effects, sampleSizes );
 83  4
          weights = metaFEWeights( conditionalVariances );
 84  4
          this.q = super.qStatistic( effects, conditionalVariances, super.weightedMean( effects, weights ) );
 85   
 
 86  4
          if ( !fixed ) { // adjust the conditional variances and weights.
 87  1
             this.bsv = metaREVariance( effects, conditionalVariances, weights );
 88  1
             for ( int i = 0; i < conditionalVariances.size(); i++ ) {
 89  20
                conditionalVariances.setQuick( i, conditionalVariances.getQuick( i ) + bsv );
 90   
             }
 91   
 
 92  1
             weights = metaFEWeights( conditionalVariances );
 93   
          }
 94   
 
 95  4
          this.e = super.weightedMean( effects, weights );
 96   
       }
 97  9
       this.v = super.metaVariance( conditionalVariances );
 98  9
       this.z = Math.abs( e ) / Math.sqrt( v );
 99  9
       this.p = Probability.errorFunctionComplemented( z );
 100   
 
 101   
       // System.err.println(effects);
 102   
 
 103   
       //      if ( qTest( q, effects.size() ) < 0.05 ) {
 104   
       //         System.err.println("Q was significant: " + qTest( q, effects.size() ) );
 105   
       //      }
 106   
 
 107  9
       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 &circ; 2 ) &circ; 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  80
    protected double samplingVariance( double r, double numsamples ) {
 128   
 
 129  0
       if ( numsamples <= 0 ) throw new IllegalArgumentException( "N must be greater than 0" );
 130   
 
 131  80
       if ( !CorrelationStats.isValidPearsonCorrelation( r ) )
 132  0
             throw new IllegalArgumentException( "r=" + r + " is not a valid Pearson correlation" );
 133   
 
 134  80
       double FUDGE = 0.001;
 135  80
       if ( Math.abs( r ) - 1.0 < FUDGE ) {
 136  80
          r = Math.abs( r ) - FUDGE; // don't care about sign. any more.
 137   
       }
 138   
 
 139  80
       if ( numsamples < 2 ) {
 140  0
          return Double.NaN;
 141   
       }
 142  80
       double k = 1.0 - r * r;
 143  80
       double var = k * k / ( numsamples - 1 );
 144   
 
 145  80
       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  4
    protected DoubleArrayList samplingVariances( DoubleArrayList effectSizes, DoubleArrayList sampleSizes ) {
 157   
 
 158  0
       if ( effectSizes.size() != sampleSizes.size() ) throw new IllegalArgumentException( "Unequal sample sizes." );
 159   
 
 160  4
       DoubleArrayList answer = new DoubleArrayList( sampleSizes.size() );
 161  4
       for ( int i = 0; i < sampleSizes.size(); i++ ) {
 162   
 
 163  80
          double ef = effectSizes.getQuick( i );
 164   
 
 165  80
          if ( Double.isNaN( ef ) ) {
 166  0
             answer.add( Double.NaN );
 167   
          } else {
 168  80
             answer.add( samplingVariance( ef, sampleSizes.getQuick( i ) ) );
 169   
          }
 170   
       }
 171  4
       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  100
    protected double fisherTransformedSamplingVariance( double sampleSize ) {
 185   
 
 186  0
       if ( sampleSize <= 3.0 ) throw new IllegalStateException( "N is too small" );
 187   
 
 188  100
       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  5
    protected DoubleArrayList fisherTransformedSamplingVariances( DoubleArrayList sampleSizes ) {
 198   
 
 199  5
       DoubleArrayList answer = new DoubleArrayList( sampleSizes.size() );
 200  5
       for ( int i = 0; i < sampleSizes.size(); i++ ) {
 201  100
          answer.add( fisherTransformedSamplingVariance( sampleSizes.getQuick( i ) ) );
 202   
       }
 203  5
       return answer;
 204   
    }
 205   
 
 206  0
    public void setFixed( boolean fixed ) {
 207  0
       this.fixed = fixed;
 208   
    }
 209   
 
 210  0
    public void setTransform( boolean transform ) {
 211  0
       this.transform = transform;
 212   
    }
 213   
 
 214  0
    public double getP() {
 215  0
       return p;
 216   
    }
 217   
 
 218  1
    public double getQ() {
 219  1
       return q;
 220   
    }
 221   
 
 222  2
    public double getZ() {
 223  2
       return z;
 224   
    }
 225   
 
 226  2
    public double getE() {
 227  2
       return e;
 228   
    }
 229   
 
 230  2
    public double getV() {
 231  2
       return v;
 232   
    }
 233   
 
 234  0
    public double getN() {
 235  0
       return n;
 236   
    }
 237   
 
 238  2
    public double getBsv() {
 239  2
       return bsv;
 240   
    }
 241   
 }