1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package ubic.basecode.math.linearmodels;
21
22 import java.io.Serializable;
23 import java.util.Collection;
24 import java.util.HashMap;
25 import java.util.LinkedHashMap;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.TreeSet;
29
30 import org.apache.commons.lang3.StringUtils;
31 import org.rosuda.REngine.REXP;
32 import org.rosuda.REngine.REXPMismatchException;
33
34 import ubic.basecode.util.r.type.AnovaEffect;
35 import ubic.basecode.util.r.type.AnovaResult;
36
37
38
39
40
41
42 public class GenericAnovaResult extends AnovaResult implements Serializable {
43
44
45
46
47 private static class InteractionFactor {
48
49
50 private static final String SEPARATOR = "_x_x_";
51
52
53 private Set<String> factorNames = new TreeSet<>();
54
55 public InteractionFactor( String... factorNames ) {
56 for ( String f : factorNames ) {
57 this.factorNames.add( f );
58 }
59 }
60
61
62
63
64
65
66 @Override
67 public boolean equals( Object obj ) {
68
69 if ( !( obj instanceof InteractionFactor ) ) return false;
70
71 return ( ( InteractionFactor ) obj ).factorNames.size() == this.factorNames.size()
72 && ( ( InteractionFactor ) obj ).factorNames.containsAll( this.factorNames );
73
74 }
75
76
77
78
79
80
81 @Override
82 public int hashCode() {
83 return StringUtils.join( factorNames, SEPARATOR ).hashCode();
84 }
85 }
86
87 private static final long serialVersionUID = 1L;
88
89 private Map<InteractionFactor, AnovaEffect> interactionEffects = new HashMap<>();
90
91 private Map<String, AnovaEffect> mainEffects = new LinkedHashMap<>();
92
93 private AnovaEffect residual;
94
95
96
97
98 public GenericAnovaResult( Collection<AnovaEffect> effects ) {
99 for ( AnovaEffect ae : effects ) {
100 String termLabel = ae.getEffectName();
101 boolean isInteraction = ae.isInteraction();
102
103 if ( isInteraction ) {
104 interactionEffects.put( new InteractionFactor( StringUtils.split( termLabel, ":" ) ), ae );
105 } else if ( termLabel.equals( "Residual" ) ) {
106 this.residualDf = ae.getDegreesOfFreedom();
107 this.residual = ae;
108 } else {
109 mainEffects.put( termLabel, ae );
110 }
111 }
112 }
113
114
115
116
117 public GenericAnovaResult( REXP rAnovaTable ) {
118
119 try {
120
121 String[] names = rAnovaTable.getAttribute( "row.names" ).asStrings();
122 double[] pvs = rAnovaTable.asList().at( "Pr(>F)" ).asDoubles();
123 double[] dfs = rAnovaTable.asList().at( "Df" ).asDoubles();
124 double[] fs = rAnovaTable.asList().at( "F value" ).asDoubles();
125
126 double[] ssq = rAnovaTable.asList().at( "Sum Sq" ).asDoubles();
127
128 for ( int i = 0; i < pvs.length; i++ ) {
129 String termLabel = names[i];
130 boolean isInteraction = termLabel.contains( ":" );
131
132 AnovaEffectvaEffect.html#AnovaEffect">AnovaEffect ae = new AnovaEffect( termLabel, pvs[i], fs[i], dfs[i], ssq[i], isInteraction );
133
134 if ( isInteraction ) {
135 interactionEffects.put( new InteractionFactor( StringUtils.split( termLabel, ":" ) ), ae );
136 } else {
137 mainEffects.put( termLabel, ae );
138 }
139 }
140
141 } catch ( REXPMismatchException e ) {
142 throw new RuntimeException( e );
143 }
144
145 }
146
147 public Double getInteractionEffectF() {
148 if ( interactionEffects.size() > 1 ) {
149 throw new IllegalArgumentException( "Must specify which interaction" );
150 }
151 if ( interactionEffects.isEmpty() ) {
152 return null;
153 }
154 return interactionEffects.values().iterator().next().getFStatistic();
155 }
156
157 public Double getInteractionEffectP() {
158 if ( interactionEffects.size() > 1 ) {
159 throw new IllegalArgumentException( "Must specify which interaction" );
160 }
161 if ( interactionEffects.isEmpty() ) {
162 return null;
163 }
164 return interactionEffects.values().iterator().next().getPValue();
165 }
166
167
168
169
170
171 public Double getInteractionEffectP( String... factorNames ) {
172 InteractionFactor interactionFactor = new InteractionFactor( factorNames );
173 if ( interactionEffects.isEmpty() ) {
174 return null;
175 }
176 if ( !interactionEffects.containsKey( interactionFactor ) ) {
177 return Double.NaN;
178 }
179 return interactionEffects.get( interactionFactor ).getPValue();
180 }
181
182 public Double getMainEffectDof( String factorName ) {
183 if ( mainEffects.get( factorName ) == null ) {
184 return null;
185 }
186 return mainEffects.get( factorName ).getDegreesOfFreedom();
187 }
188
189 public Double getMainEffectF( String factorName ) {
190 if ( mainEffects.get( factorName ) == null ) {
191 return Double.NaN;
192 }
193 return mainEffects.get( factorName ).getFStatistic();
194 }
195
196
197
198
199 public Collection<String> getMainEffectFactorNames() {
200 return mainEffects.keySet();
201 }
202
203 public Double getMainEffectP( String factorName ) {
204 if ( mainEffects.get( factorName ) == null ) {
205 return Double.NaN;
206 }
207 return mainEffects.get( factorName ).getPValue();
208 }
209
210 public boolean hasInteractions() {
211 return !interactionEffects.isEmpty();
212 }
213
214 @Override
215 public String toString() {
216 StringBuilder buf = new StringBuilder();
217
218 buf.append( "ANOVA table " + this.getKey() + " \n" );
219
220 buf.append( StringUtils.leftPad( "\t", 10 ) + "Df\tSSq\tMSq\tF\tP\n" );
221
222 for ( String me : this.getMainEffectFactorNames() ) {
223 if ( me.equals( LinearModelSummary.INTERCEPT_COEFFICIENT_NAME ) ) {
224 continue;
225 }
226 AnovaEffect a = mainEffects.get( me );
227 buf.append( a + "\n" );
228 }
229
230 if ( hasInteractions() ) {
231 for ( InteractionFactor ifa : interactionEffects.keySet() ) {
232 AnovaEffect a = this.interactionEffects.get( ifa );
233 buf.append( a + "\n" );
234 }
235 }
236
237 buf.append( residual + "\n" );
238
239 return buf.toString();
240 }
241 }