@@ -149,3 +149,79 @@ def setup_class(cls):
149
149
150
150
# Note: loc is fixed, no problems with parameters close to min data
151
151
cls .skip_bsejac = False
152
+
153
+
154
+ class TwoPeakLLHNoExog (GenericLikelihoodModel ):
155
+ """Fit height of signal peak over background."""
156
+ start_params = [10 , 1000 ]
157
+ cloneattr = ['start_params' , 'signal' , 'background' ]
158
+ exog_names = ['n_signal' , 'n_background' ]
159
+ endog_names = ['alpha' ]
160
+
161
+ def __init__ (self , endog , exog = None , signal = None , background = None ,
162
+ * args , ** kwargs ):
163
+ # assume we know the shape + location of the two components,
164
+ # so we re-use their PDFs here
165
+ self .signal = signal
166
+ self .background = background
167
+ super (TwoPeakLLHNoExog , self ).__init__ (endog = endog , exog = exog ,
168
+ * args , ** kwargs )
169
+
170
+ def loglike (self , params ): # pylint: disable=E0202
171
+ return - self .nloglike (params )
172
+
173
+ def nloglike (self , params ):
174
+ endog = self .endog
175
+ return self .nlnlike (params , endog )
176
+
177
+ def nlnlike (self , params , endog ):
178
+ n_sig = params [0 ]
179
+ n_bkg = params [1 ]
180
+ if (n_sig < 0 ) or n_bkg < 0 :
181
+ return np .inf
182
+ n_tot = n_bkg + n_sig
183
+ alpha = endog
184
+ sig = self .signal .pdf (alpha )
185
+ bkg = self .background .pdf (alpha )
186
+ sumlogl = np .sum (
187
+ np .ma .log (
188
+ (n_sig * sig ) + (n_bkg * bkg )
189
+ )
190
+ )
191
+ sumlogl -= n_tot
192
+ return - sumlogl
193
+
194
+
195
+ class TestTwoPeakLLHNoExog (object ):
196
+
197
+ @classmethod
198
+ def setup_class (cls ):
199
+ np .random .seed (42 )
200
+ pdf_a = stats .halfcauchy (loc = 0 , scale = 1 )
201
+ pdf_b = stats .uniform (loc = 0 , scale = 100 )
202
+
203
+ n_a = 30
204
+ n_b = 1000
205
+ params = [n_a , n_b ]
206
+
207
+ X = np .concatenate ([
208
+ pdf_a .rvs (size = n_a ),
209
+ pdf_b .rvs (size = n_b ),
210
+ ])[:, np .newaxis ]
211
+ cls .X = X
212
+ cls .params = params
213
+ cls .pdf_a = pdf_a
214
+ cls .pdf_b = pdf_b
215
+
216
+ def test_fit (self ):
217
+ llh_noexog = TwoPeakLLHNoExog (self .X ,
218
+ signal = self .pdf_a ,
219
+ background = self .pdf_b )
220
+
221
+ res = llh_noexog .fit ()
222
+ assert np .allclose (res .params , self .params , rtol = 1e-1 )
223
+ assert np .isnan (res .df_resid )
224
+ res_bs = res .bootstrap (nrep = 50 )
225
+ assert res_bs is not None
226
+ smry = res .summary ()
227
+ assert smry is not None
0 commit comments