1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package ubic.basecode.math.linearmodels;
20
21 import org.apache.commons.lang3.StringUtils;
22 import org.apache.commons.math3.distribution.FDistribution;
23 import ubic.basecode.dataStructure.matrix.DoubleMatrix;
24
25 import javax.annotation.Nullable;
26 import java.util.Collection;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30
31
32
33
34
35
36 class LinearModelSummaryImpl implements LinearModelSummary {
37
38 private static final long serialVersionUID = 1L;
39
40
41
42
43 private final String key;
44 private final double adjRSquared;
45 @Nullable
46 private GenericAnovaResult anovaResult;
47 private final double[] coefficients;
48 private final DoubleMatrix<String, String> contrastCoefficients;
49 private final double denominatorDof;
50
51
52
53 private final double[] effects;
54 private final List<String> factorNames;
55 private final double fStat;
56 private final double numeratorDof;
57
58
59
60 private final double priorDof;
61 private final double[] residuals;
62 private final double rSquared;
63
64
65
66 private final boolean shrunken;
67 private final double sigma;
68 private final double[] stdevUnscaled;
69 private final Map<String, Collection<String>> term2CoefficientNames;
70
71 @Nullable
72 private Double overallPValue = null;
73
74
75
76
77 public LinearModelSummaryImpl( String key ) {
78 this.key = key;
79 this.stdevUnscaled = null;
80 this.adjRSquared = Double.NaN;
81 this.coefficients = null;
82 this.effects = null;
83 this.sigma = Double.NaN;
84 this.priorDof = Double.NaN;
85 this.numeratorDof = Double.NaN;
86 this.fStat = Double.NaN;
87 this.shrunken = false;
88 this.rSquared = Double.NaN;
89 this.residuals = null;
90 this.factorNames = null;
91 this.denominatorDof = Double.NaN;
92 this.contrastCoefficients = null;
93 this.term2CoefficientNames = null;
94 }
95
96 public LinearModelSummaryImpl( String k, double[] coefficients, double[] residuals, List<String> terms,
97 DoubleMatrix<String, String> contrastCoefficients, double[] effects, double[] stdevUnscaled, double rsquared,
98 double adjRsquared, double fstat, double ndof, double ddof, @Nullable GenericAnovaResult anovaResult,
99 double sigma, boolean isShrunken, double priorDof ) {
100 if ( anovaResult != null && !anovaResult.getKey().equals( k ) ) {
101 throw new IllegalArgumentException( "Keys of ANOVA and holding LM must match" );
102 }
103 this.residuals = residuals;
104 this.coefficients = coefficients;
105 this.contrastCoefficients = contrastCoefficients;
106 this.rSquared = rsquared;
107 this.adjRSquared = adjRsquared;
108 this.fStat = fstat;
109 this.numeratorDof = ndof;
110 this.denominatorDof = ddof;
111 this.key = k;
112 this.anovaResult = anovaResult;
113 this.effects = effects;
114 this.stdevUnscaled = stdevUnscaled;
115 this.factorNames = terms;
116 this.sigma = sigma;
117 this.shrunken = isShrunken;
118 this.priorDof = priorDof;
119 this.term2CoefficientNames = LinearModelSummaryUtils.createTerm2CoefficientNames( factorNames, contrastCoefficients );
120 }
121
122 @Override
123 public double getAdjRSquared() {
124 return adjRSquared;
125 }
126
127 @Override
128 public GenericAnovaResult getAnova() {
129 return this.anovaResult;
130 }
131
132 @Override
133 public double[] getCoefficients() {
134 return coefficients;
135 }
136
137 @Override
138 public DoubleMatrix<String, String> getContrastCoefficients() {
139 return contrastCoefficients;
140 }
141
142 @Override
143 public Map<String, Double> getContrastCoefficients( String factorName ) {
144 return getContrastAttribute( factorName, "Estimate" );
145 }
146
147 @Override
148 public Map<String, Double> getContrastCoefficientStderr( String factorName ) {
149 return getContrastAttribute( factorName, "Std. Error" );
150 }
151
152 @Override
153 public Map<String, Double> getContrastPValues( String factorName ) {
154 return getContrastAttribute( factorName, "Pr(>|t|)" );
155 }
156
157 @Override
158 public Map<String, Double> getContrastTStats( String factorName ) {
159 return getContrastAttribute( factorName, "t value" );
160 }
161
162 private Map<String, Double> getContrastAttribute( String factorName, String attributeName ) {
163 Collection<String> terms = term2CoefficientNames.get( factorName );
164 if ( terms == null ) return null;
165 Map<String, Double> results = new HashMap<>();
166 for ( String term : terms ) {
167 results.put( term, contrastCoefficients.getByKeys( term, attributeName ) );
168 }
169 return results;
170 }
171
172 @Override
173 public double[] getEffects() {
174 return this.effects;
175 }
176
177 @Override
178 public double getFStat() {
179 return this.fStat;
180 }
181
182 @Override
183 public List<String> getFactorNames() {
184 return factorNames;
185 }
186
187 @Override
188 public double getInterceptCoefficient() {
189 if ( contrastCoefficients != null ) {
190 if ( contrastCoefficients.hasRow( LinearModelSummary.INTERCEPT_COEFFICIENT_NAME ) ) {
191 return contrastCoefficients.getByKeys( LinearModelSummary.INTERCEPT_COEFFICIENT_NAME, "Estimate" );
192 } else if ( contrastCoefficients.rows() == 1 ) {
193
194
195
196
197
198 assert "x1".equals( contrastCoefficients.getRowName( 0 ) );
199 return contrastCoefficients.getByKeys( contrastCoefficients.getRowName( 0 ), "Estimate" );
200 }
201 }
202
203 return Double.NaN;
204 }
205
206 @Override
207 public double getInterceptPValue() {
208 if ( contrastCoefficients != null ) {
209 if ( contrastCoefficients.hasRow( LinearModelSummary.INTERCEPT_COEFFICIENT_NAME ) ) {
210 return contrastCoefficients.getByKeys( LinearModelSummary.INTERCEPT_COEFFICIENT_NAME, "Pr(>|t|)" );
211 } else if ( contrastCoefficients.rows() == 1 ) {
212
213
214
215
216
217 assert "x1".equals( contrastCoefficients.getRowName( 0 ) );
218 return contrastCoefficients.getByKeys( contrastCoefficients.getRowName( 0 ), "Pr(>|t|)" );
219 }
220 }
221 return Double.NaN;
222 }
223
224 @Override
225 public double getInterceptTStat() {
226 if ( contrastCoefficients != null ) {
227 if ( contrastCoefficients.hasRow( LinearModelSummary.INTERCEPT_COEFFICIENT_NAME ) ) {
228 return contrastCoefficients.getByKeys( LinearModelSummary.INTERCEPT_COEFFICIENT_NAME, "t value" );
229 } else if ( contrastCoefficients.rows() == 1 ) {
230
231
232
233
234
235 assert "x1".equals( contrastCoefficients.getRowName( 0 ) );
236 return contrastCoefficients.getByKeys( contrastCoefficients.getRowName( 0 ), "t value" );
237 }
238 }
239
240 return Double.NaN;
241 }
242
243 public String getKey() {
244 return key;
245 }
246
247 public double getMainEffectPValue( String factorName ) {
248 if ( anovaResult == null ) return Double.NaN;
249 return anovaResult.getMainEffectPValue( factorName );
250 }
251
252 @Override
253 public double getNumeratorDof() {
254 return this.numeratorDof;
255 }
256
257 @Override
258 public double getOverallPValue() {
259 if ( overallPValue == null ) {
260 if ( Double.isNaN( numeratorDof ) || Double.isNaN( denominatorDof ) || numeratorDof == 0 || denominatorDof == 0 ) {
261 overallPValue = Double.NaN;
262 } else {
263 FDistribution f = new FDistribution( numeratorDof, denominatorDof );
264 overallPValue = 1.0 - f.cumulativeProbability( this.getFStat() );
265 }
266 }
267 return overallPValue;
268 }
269
270 @Override
271 public double getPriorDof() {
272 return priorDof;
273 }
274
275 @Override
276 public double getResidualsDof() {
277 return this.denominatorDof;
278 }
279
280 @Override
281 public double[] getResiduals() {
282 return residuals;
283 }
284
285 @Override
286 public double getRSquared() {
287 return rSquared;
288 }
289
290 @Override
291 public double getSigma() {
292 return sigma;
293 }
294
295 @Override
296 public double[] getStdevUnscaled() {
297 return stdevUnscaled;
298 }
299
300 @Override
301 public boolean isBaseline( String factorValueName ) {
302 return !contrastCoefficients.hasRow( factorValueName );
303 }
304
305 @Override
306 public boolean isShrunken() {
307 return shrunken;
308 }
309
310 public void setAnova( GenericAnovaResult genericAnovaResult ) {
311 this.anovaResult = genericAnovaResult;
312 }
313
314 @Override
315 public String toString() {
316 StringBuilder buf = new StringBuilder();
317 if ( StringUtils.isNotBlank( this.key ) ) {
318 buf.append( this.key ).append( "\n" );
319 }
320 buf.append( "F=" ).append( String.format( "%.2f", this.fStat ) ).append( " Rsquare=" ).append( String.format( "%.2f", this.rSquared ) ).append( "\n" );
321
322 buf.append( "Residuals:\n" );
323 if ( residuals != null ) {
324 for ( double d : residuals ) {
325 buf.append( String.format( "%.2f ", d ) );
326 }
327 } else {
328 buf.append( "Residuals are null" );
329 }
330
331 buf.append( "\n\nCoefficients:\n" ).append( contrastCoefficients ).append( "\n" );
332 if ( this.anovaResult != null ) {
333 buf.append( this.anovaResult ).append( "\n" );
334 }
335
336 return buf.toString();
337 }
338
339 }