Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1"""Testing helper functions 

2 

3Warning: current status experimental, mostly copy paste 

4 

5Warning: these functions will be changed without warning as the need 

6during refactoring arises. 

7 

8The first group of functions provide consistency checks 

9 

10""" 

11from statsmodels.compat.pandas import assert_equal 

12 

13import os 

14import sys 

15from distutils.version import LooseVersion 

16 

17import numpy as np 

18from numpy.testing import assert_allclose, assert_ 

19 

20import pandas as pd 

21 

22 

23class PytestTester(object): 

24 def __init__(self, package_path=None): 

25 f = sys._getframe(1) 

26 if package_path is None: 

27 package_path = f.f_locals.get('__file__', None) 

28 if package_path is None: 

29 raise ValueError('Unable to determine path') 

30 self.package_path = os.path.dirname(package_path) 

31 self.package_name = f.f_locals.get('__name__', None) 

32 

33 def __call__(self, extra_args=None, exit=False): 

34 try: 

35 import pytest 

36 if not LooseVersion(pytest.__version__) >= LooseVersion('3.0'): 

37 raise ImportError 

38 if extra_args is None: 

39 extra_args = ['--tb=short', '--disable-pytest-warnings'] 

40 cmd = [self.package_path] + extra_args 

41 print('Running pytest ' + ' '.join(cmd)) 

42 status = pytest.main(cmd) 

43 if exit: 

44 sys.exit(status) 

45 except ImportError: 

46 raise ImportError('pytest>=3 required to run the test') 

47 

48 

49def check_ttest_tvalues(results): 

50 # test that t_test has same results a params, bse, tvalues, ... 

51 res = results 

52 mat = np.eye(len(res.params)) 

53 tt = res.t_test(mat) 

54 

55 assert_allclose(tt.effect, res.params, rtol=1e-12) 

56 # TODO: tt.sd and tt.tvalue are 2d also for single regressor, squeeze 

57 assert_allclose(np.squeeze(tt.sd), res.bse, rtol=1e-10) 

58 assert_allclose(np.squeeze(tt.tvalue), res.tvalues, rtol=1e-12) 

59 assert_allclose(tt.pvalue, res.pvalues, rtol=5e-10) 

60 assert_allclose(tt.conf_int(), res.conf_int(), rtol=1e-10) 

61 

62 # test params table frame returned by t_test 

63 table_res = np.column_stack((res.params, res.bse, res.tvalues, 

64 res.pvalues, res.conf_int())) 

65 table2 = tt.summary_frame().values 

66 assert_allclose(table2, table_res, rtol=1e-12) 

67 

68 # TODO: move this to test_attributes ? 

69 assert_(hasattr(res, 'use_t')) 

70 

71 tt = res.t_test(mat[0]) 

72 tt.summary() # smoke test for #1323 

73 assert_allclose(tt.pvalue, res.pvalues[0], rtol=5e-10) 

74 # TODO: Adapt more of test_generic_methods.test_ttest_values here? 

75 

76 

77def check_ftest_pvalues(results): 

78 """ 

79 Check that the outputs of `res.wald_test` produces pvalues that 

80 match res.pvalues. 

81 

82 Check that the string representations of `res.summary()` and (possibly) 

83 `res.summary2()` correctly label either the t or z-statistic. 

84 

85 Parameters 

86 ---------- 

87 results : Results 

88 

89 Raises 

90 ------ 

91 AssertionError 

92 """ 

93 res = results 

94 use_t = res.use_t 

95 k_vars = len(res.params) 

96 # check default use_t 

97 pvals = [res.wald_test(np.eye(k_vars)[k], use_f=use_t).pvalue 

98 for k in range(k_vars)] 

99 assert_allclose(pvals, res.pvalues, rtol=5e-10, atol=1e-25) 

100 

101 # automatic use_f based on results class use_t 

102 pvals = [res.wald_test(np.eye(k_vars)[k]).pvalue 

103 for k in range(k_vars)] 

104 assert_allclose(pvals, res.pvalues, rtol=5e-10, atol=1e-25) 

105 

106 # TODO: Separate these out into summary/summary2 tests? 

107 # label for pvalues in summary 

108 string_use_t = 'P>|z|' if use_t is False else 'P>|t|' 

109 summ = str(res.summary()) 

110 assert_(string_use_t in summ) 

111 

112 # try except for models that do not have summary2 

113 try: 

114 summ2 = str(res.summary2()) 

115 except AttributeError: 

116 pass 

117 else: 

118 assert_(string_use_t in summ2) 

119 

120 

121def check_fitted(results): 

122 import pytest 

123 

124 # ignore wrapper for isinstance check 

125 from statsmodels.genmod.generalized_linear_model import GLMResults 

126 from statsmodels.discrete.discrete_model import DiscreteResults 

127 

128 # possibly unwrap -- GEE has no wrapper 

129 results = getattr(results, '_results', results) 

130 

131 if isinstance(results, (GLMResults, DiscreteResults)): 

132 pytest.skip('Not supported for {0}'.format(type(results))) 

133 

134 res = results 

135 fitted = res.fittedvalues 

136 assert_allclose(res.model.endog - fitted, res.resid, rtol=1e-12) 

137 assert_allclose(fitted, res.predict(), rtol=1e-12) 

138 

139 

140def check_predict_types(results): 

141 """ 

142 Check that the `predict` method of the given results object produces the 

143 correct output type. 

144 

145 Parameters 

146 ---------- 

147 results : Results 

148 

149 Raises 

150 ------ 

151 AssertionError 

152 """ 

153 res = results 

154 # squeeze to make 1d for single regressor test case 

155 p_exog = np.squeeze(np.asarray(res.model.exog[:2])) 

156 

157 # ignore wrapper for isinstance check 

158 from statsmodels.genmod.generalized_linear_model import GLMResults 

159 from statsmodels.discrete.discrete_model import DiscreteResults 

160 

161 # possibly unwrap -- GEE has no wrapper 

162 results = getattr(results, '_results', results) 

163 

164 if isinstance(results, (GLMResults, DiscreteResults)): 

165 # SMOKE test only TODO: mark this somehow 

166 res.predict(p_exog) 

167 res.predict(p_exog.tolist()) 

168 res.predict(p_exog[0].tolist()) 

169 else: 

170 fitted = res.fittedvalues[:2] 

171 assert_allclose(fitted, res.predict(p_exog), rtol=1e-12) 

172 # this needs reshape to column-vector: 

173 assert_allclose(fitted, res.predict(np.squeeze(p_exog).tolist()), 

174 rtol=1e-12) 

175 # only one prediction: 

176 assert_allclose(fitted[:1], res.predict(p_exog[0].tolist()), 

177 rtol=1e-12) 

178 assert_allclose(fitted[:1], res.predict(p_exog[0]), 

179 rtol=1e-12) 

180 

181 # Check that pandas wrapping works as expected 

182 exog_index = range(len(p_exog)) 

183 predicted = res.predict(p_exog) 

184 

185 cls = pd.Series if p_exog.ndim == 1 else pd.DataFrame 

186 predicted_pandas = res.predict(cls(p_exog, index=exog_index)) 

187 

188 # predicted.ndim may not match p_exog.ndim because it may be squeezed 

189 # if p_exog has only one column 

190 cls = pd.Series if predicted.ndim == 1 else pd.DataFrame 

191 predicted_expected = cls(predicted, index=exog_index) 

192 assert_equal(predicted_expected, predicted_pandas)