4192 |
11 Aug 22 |
peter |
// $Id$ |
4192 |
11 Aug 22 |
peter |
2 |
|
4192 |
11 Aug 22 |
peter |
3 |
/* |
4192 |
11 Aug 22 |
peter |
Copyright (C) 2022 Peter Johansson |
4192 |
11 Aug 22 |
peter |
5 |
|
4192 |
11 Aug 22 |
peter |
This file is part of the yat library, https://dev.thep.lu.se/yat |
4192 |
11 Aug 22 |
peter |
7 |
|
4192 |
11 Aug 22 |
peter |
The yat library is free software; you can redistribute it and/or |
4192 |
11 Aug 22 |
peter |
modify it under the terms of the GNU General Public License as |
4192 |
11 Aug 22 |
peter |
published by the Free Software Foundation; either version 3 of the |
4192 |
11 Aug 22 |
peter |
License, or (at your option) any later version. |
4192 |
11 Aug 22 |
peter |
12 |
|
4192 |
11 Aug 22 |
peter |
The yat library is distributed in the hope that it will be useful, |
4192 |
11 Aug 22 |
peter |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
4192 |
11 Aug 22 |
peter |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
4192 |
11 Aug 22 |
peter |
General Public License for more details. |
4192 |
11 Aug 22 |
peter |
17 |
|
4192 |
11 Aug 22 |
peter |
You should have received a copy of the GNU General Public License |
4192 |
11 Aug 22 |
peter |
along with yat. If not, see <https://www.gnu.org/licenses/>. |
4192 |
11 Aug 22 |
peter |
20 |
*/ |
4192 |
11 Aug 22 |
peter |
21 |
|
4192 |
11 Aug 22 |
peter |
22 |
#include <config.h> |
4192 |
11 Aug 22 |
peter |
23 |
|
4192 |
11 Aug 22 |
peter |
24 |
#include "NegativeBinomialExtendedMixture.h" |
4192 |
11 Aug 22 |
peter |
25 |
|
4192 |
11 Aug 22 |
peter |
26 |
#include <yat/statistics/GaussianMixture.h> |
4192 |
11 Aug 22 |
peter |
27 |
#include <yat/utility/BFGS2.h> |
4252 |
18 Nov 22 |
peter |
28 |
#include <yat/utility/Exception.h> |
4192 |
11 Aug 22 |
peter |
29 |
#include <yat/utility/Matrix.h> |
4192 |
11 Aug 22 |
peter |
30 |
|
4192 |
11 Aug 22 |
peter |
31 |
#include <gsl/gsl_randist.h> |
4192 |
11 Aug 22 |
peter |
32 |
#include <gsl/gsl_sf_gamma.h> |
4192 |
11 Aug 22 |
peter |
33 |
#include <gsl/gsl_sf_psi.h> |
4192 |
11 Aug 22 |
peter |
34 |
|
4192 |
11 Aug 22 |
peter |
35 |
#include <cassert> |
4192 |
11 Aug 22 |
peter |
36 |
#include <cmath> |
4252 |
18 Nov 22 |
peter |
37 |
#include <sstream> |
4192 |
11 Aug 22 |
peter |
38 |
#include <utility> |
4192 |
11 Aug 22 |
peter |
39 |
#include <vector> |
4192 |
11 Aug 22 |
peter |
40 |
|
4192 |
11 Aug 22 |
peter |
41 |
namespace theplu { |
4192 |
11 Aug 22 |
peter |
42 |
namespace yat { |
4192 |
11 Aug 22 |
peter |
43 |
namespace statistics { |
4192 |
11 Aug 22 |
peter |
44 |
|
4192 |
11 Aug 22 |
peter |
45 |
void NegativeBinomialExtendedMixture::add(unsigned long int k, double y) |
4192 |
11 Aug 22 |
peter |
46 |
{ |
4192 |
11 Aug 22 |
peter |
47 |
data_.push_back(std::make_pair(k, y)); |
4192 |
11 Aug 22 |
peter |
48 |
} |
4192 |
11 Aug 22 |
peter |
49 |
|
4192 |
11 Aug 22 |
peter |
50 |
|
4192 |
11 Aug 22 |
peter |
51 |
const utility::Vector& NegativeBinomialExtendedMixture::alpha(void) const |
4192 |
11 Aug 22 |
peter |
52 |
{ |
4192 |
11 Aug 22 |
peter |
53 |
return alpha_; |
4192 |
11 Aug 22 |
peter |
54 |
} |
4192 |
11 Aug 22 |
peter |
55 |
|
4192 |
11 Aug 22 |
peter |
56 |
|
4192 |
11 Aug 22 |
peter |
57 |
void NegativeBinomialExtendedMixture::clear(void) |
4192 |
11 Aug 22 |
peter |
58 |
{ |
4192 |
11 Aug 22 |
peter |
59 |
data_.clear(); |
4192 |
11 Aug 22 |
peter |
60 |
} |
4192 |
11 Aug 22 |
peter |
61 |
|
4192 |
11 Aug 22 |
peter |
62 |
|
4192 |
11 Aug 22 |
peter |
// Calculate P(Z_i=j) given current param_ |
4192 |
11 Aug 22 |
peter |
64 |
bool NegativeBinomialExtendedMixture::expectation_step(utility::Matrix& H) |
4192 |
11 Aug 22 |
peter |
65 |
{ |
4192 |
11 Aug 22 |
peter |
// loop over values |
4192 |
11 Aug 22 |
peter |
67 |
for (size_t j=0; j<data_.size(); ++j) { |
4192 |
11 Aug 22 |
peter |
68 |
unsigned long int k = data_[j].first; |
4192 |
11 Aug 22 |
peter |
69 |
double y = data_[j].second; |
4192 |
11 Aug 22 |
peter |
70 |
utility::VectorView column = H.column_view(j); |
4192 |
11 Aug 22 |
peter |
// loop over models |
4192 |
11 Aug 22 |
peter |
72 |
for (size_t i=0; i<column.size(); ++i) |
4192 |
11 Aug 22 |
peter |
73 |
column(i) = tau_(i) * pdf(k, y*m_(i), alpha_(i)); |
4192 |
11 Aug 22 |
peter |
74 |
column *= 1.0 / sum(column); |
4192 |
11 Aug 22 |
peter |
75 |
} |
4192 |
11 Aug 22 |
peter |
76 |
return false; |
4192 |
11 Aug 22 |
peter |
77 |
} |
4192 |
11 Aug 22 |
peter |
78 |
|
4192 |
11 Aug 22 |
peter |
79 |
|
4192 |
11 Aug 22 |
peter |
80 |
void NegativeBinomialExtendedMixture::fit(const utility::VectorBase& m, |
4192 |
11 Aug 22 |
peter |
81 |
const utility::VectorBase& alpha, |
4192 |
11 Aug 22 |
peter |
82 |
const utility::VectorBase& tau) |
4192 |
11 Aug 22 |
peter |
83 |
{ |
4192 |
11 Aug 22 |
peter |
84 |
m_ = m; |
4192 |
11 Aug 22 |
peter |
85 |
alpha_ = alpha; |
4192 |
11 Aug 22 |
peter |
86 |
tau_ = tau; |
4192 |
11 Aug 22 |
peter |
87 |
optimize(); |
4192 |
11 Aug 22 |
peter |
88 |
} |
4192 |
11 Aug 22 |
peter |
89 |
|
4192 |
11 Aug 22 |
peter |
90 |
|
4192 |
11 Aug 22 |
peter |
91 |
void NegativeBinomialExtendedMixture::fit(size_t n) |
4192 |
11 Aug 22 |
peter |
92 |
{ |
4192 |
11 Aug 22 |
peter |
93 |
if (data_.empty()) |
4192 |
11 Aug 22 |
peter |
94 |
return; |
4192 |
11 Aug 22 |
peter |
95 |
init_fit(n); |
4192 |
11 Aug 22 |
peter |
96 |
optimize(); |
4192 |
11 Aug 22 |
peter |
97 |
} |
4192 |
11 Aug 22 |
peter |
98 |
|
4192 |
11 Aug 22 |
peter |
99 |
|
4192 |
11 Aug 22 |
peter |
100 |
void NegativeBinomialExtendedMixture::init_fit(size_t n) |
4192 |
11 Aug 22 |
peter |
101 |
{ |
4192 |
11 Aug 22 |
peter |
102 |
m_.resize(n); |
4192 |
11 Aug 22 |
peter |
103 |
alpha_.resize(n, 1.1); |
4192 |
11 Aug 22 |
peter |
104 |
tau_.resize(n, 1.0/n); |
4192 |
11 Aug 22 |
peter |
105 |
|
4192 |
11 Aug 22 |
peter |
106 |
statistics::GaussianMixture gm; |
4192 |
11 Aug 22 |
peter |
107 |
for (const auto& x : data_) |
4192 |
11 Aug 22 |
peter |
108 |
gm.add(x.first / x.second); |
4192 |
11 Aug 22 |
peter |
109 |
gm.fit(n); |
4192 |
11 Aug 22 |
peter |
110 |
|
4192 |
11 Aug 22 |
peter |
111 |
for (size_t i=0; i<n; ++i) |
4192 |
11 Aug 22 |
peter |
112 |
m_(i) = gm.mean(i); |
4192 |
11 Aug 22 |
peter |
113 |
} |
4192 |
11 Aug 22 |
peter |
114 |
|
4192 |
11 Aug 22 |
peter |
115 |
|
4192 |
11 Aug 22 |
peter |
116 |
double NegativeBinomialExtendedMixture::logL(void) const |
4192 |
11 Aug 22 |
peter |
117 |
{ |
4192 |
11 Aug 22 |
peter |
118 |
double sum = 0; |
4192 |
11 Aug 22 |
peter |
119 |
for (size_t i=0; i<data_.size(); ++i) { |
4192 |
11 Aug 22 |
peter |
120 |
double L = 0; |
4192 |
11 Aug 22 |
peter |
121 |
for (size_t j=0; j<tau_.size(); ++j) |
4192 |
11 Aug 22 |
peter |
122 |
L += tau_(j) * pdf(data_[i].first, data_[i].second * m_(j), alpha_(j)); |
4192 |
11 Aug 22 |
peter |
123 |
if (L) |
4192 |
11 Aug 22 |
peter |
124 |
sum += std::log(L); |
4192 |
11 Aug 22 |
peter |
125 |
} |
4192 |
11 Aug 22 |
peter |
126 |
return sum; |
4192 |
11 Aug 22 |
peter |
127 |
} |
4192 |
11 Aug 22 |
peter |
128 |
|
4192 |
11 Aug 22 |
peter |
129 |
|
4192 |
11 Aug 22 |
peter |
130 |
const yat::utility::Vector& NegativeBinomialExtendedMixture::m(void) const |
4192 |
11 Aug 22 |
peter |
131 |
{ |
4192 |
11 Aug 22 |
peter |
132 |
return m_; |
4192 |
11 Aug 22 |
peter |
133 |
} |
4192 |
11 Aug 22 |
peter |
134 |
|
4192 |
11 Aug 22 |
peter |
135 |
|
4192 |
11 Aug 22 |
peter |
136 |
void NegativeBinomialExtendedMixture::optimize(void) |
4192 |
11 Aug 22 |
peter |
137 |
{ |
4192 |
11 Aug 22 |
peter |
138 |
assert(data_.size()); |
4192 |
11 Aug 22 |
peter |
139 |
utility::BFGS2 solver(tau_.size()); |
4192 |
11 Aug 22 |
peter |
140 |
yat::utility::Matrix H(tau_.size(), data_.size()); |
4192 |
11 Aug 22 |
peter |
141 |
bool changed = true; |
4192 |
11 Aug 22 |
peter |
142 |
for (size_t i=0; i<100 && changed; ++i) { |
4192 |
11 Aug 22 |
peter |
143 |
changed = expectation_step(H); |
4192 |
11 Aug 22 |
peter |
144 |
if (optimize_tau(H)) |
4192 |
11 Aug 22 |
peter |
145 |
changed = true; |
4192 |
11 Aug 22 |
peter |
146 |
if (optimize_param(H, solver)) |
4192 |
11 Aug 22 |
peter |
147 |
changed=true; |
4192 |
11 Aug 22 |
peter |
148 |
} |
4192 |
11 Aug 22 |
peter |
149 |
} |
4192 |
11 Aug 22 |
peter |
150 |
|
4192 |
11 Aug 22 |
peter |
151 |
|
4192 |
11 Aug 22 |
peter |
152 |
bool NegativeBinomialExtendedMixture::optimize_tau(const utility::Matrix& H) |
4192 |
11 Aug 22 |
peter |
153 |
{ |
4192 |
11 Aug 22 |
peter |
154 |
yat::utility::Vector prev_tau(tau_); |
4192 |
11 Aug 22 |
peter |
// tau is updated as the average |
4192 |
11 Aug 22 |
peter |
156 |
for (size_t i=0; i<tau_.size(); ++i) { |
4192 |
11 Aug 22 |
peter |
157 |
tau_(i) = sum(H.row_const_view(i)); |
4192 |
11 Aug 22 |
peter |
158 |
} |
4192 |
11 Aug 22 |
peter |
159 |
tau_ *= 1.0 / sum(tau_); |
4192 |
11 Aug 22 |
peter |
160 |
double norm2 = norm2_squared(yat::utility::Vector(tau_-prev_tau)); |
4192 |
11 Aug 22 |
peter |
161 |
return norm2 > 1e-9; |
4192 |
11 Aug 22 |
peter |
162 |
} |
4192 |
11 Aug 22 |
peter |
163 |
|
4192 |
11 Aug 22 |
peter |
164 |
|
4192 |
11 Aug 22 |
peter |
165 |
bool NegativeBinomialExtendedMixture:: |
4192 |
11 Aug 22 |
peter |
166 |
optimize_param(const utility::Matrix& H, |
4192 |
11 Aug 22 |
peter |
167 |
utility::MultiMinimizerDerivative& solver) |
4192 |
11 Aug 22 |
peter |
168 |
{ |
4192 |
11 Aug 22 |
peter |
169 |
/* |
4192 |
11 Aug 22 |
peter |
Maximize Q given current H matrix |
4192 |
11 Aug 22 |
peter |
Q = sum_i sum_j P(Z_j=i | K_j=k_j; params) ln(L(param_i; k_j, i) |
4192 |
11 Aug 22 |
peter |
= sum_i sum_j H_ij ln(L(param_i; k_j, i) |
4192 |
11 Aug 22 |
peter |
where i runs over models and j over samples |
4192 |
11 Aug 22 |
peter |
174 |
|
4192 |
11 Aug 22 |
peter |
L = tau*Gamma(r+k)/(Gamma(k+1)*Gamma(r)) * (1-p)^r * p^k |
4192 |
11 Aug 22 |
peter |
ln L = ln(tau) + ln(Gamma(r+k)) - ln(Gamma(k+1)) - ln(Gamma(r)) + |
4192 |
11 Aug 22 |
peter |
r*ln(1-p) + k*ln(p) |
4192 |
11 Aug 22 |
peter |
178 |
*/ |
4192 |
11 Aug 22 |
peter |
179 |
|
4192 |
11 Aug 22 |
peter |
180 |
yat::utility::Vector old_m = m_; |
4192 |
11 Aug 22 |
peter |
181 |
yat::utility::Vector old_alpha = alpha_; |
4192 |
11 Aug 22 |
peter |
182 |
yat::utility::Vector param(2); |
4192 |
11 Aug 22 |
peter |
183 |
for (size_t i=0; i<tau_.size(); ++i) { |
4192 |
11 Aug 22 |
peter |
184 |
yat::utility::VectorConstView h = H.row_const_view(i); |
4192 |
11 Aug 22 |
peter |
185 |
param(0) = m_(i); |
4192 |
11 Aug 22 |
peter |
186 |
param(1) = alpha_(i); |
4192 |
11 Aug 22 |
peter |
187 |
Q func(data_, h); |
4252 |
18 Nov 22 |
peter |
188 |
size_t m_epochs = 1000; |
4252 |
18 Nov 22 |
peter |
189 |
solver(param, func, utility::MultiMinimizerDerivative::Gradient(1e-3), |
4252 |
18 Nov 22 |
peter |
190 |
m_epochs); |
4252 |
18 Nov 22 |
peter |
191 |
if (solver.epochs() == m_epochs) { |
4252 |
18 Nov 22 |
peter |
192 |
std::ostringstream msg; |
4252 |
18 Nov 22 |
peter |
193 |
msg << "NegativeBinomialExtendedMixture: maximal epochs reached"; |
4252 |
18 Nov 22 |
peter |
194 |
throw utility::runtime_error(msg.str()); |
4252 |
18 Nov 22 |
peter |
195 |
} |
4192 |
11 Aug 22 |
peter |
196 |
m_(i) = param(0); |
4192 |
11 Aug 22 |
peter |
197 |
alpha_(i) = param(1); |
4192 |
11 Aug 22 |
peter |
198 |
} |
4192 |
11 Aug 22 |
peter |
199 |
|
4192 |
11 Aug 22 |
peter |
200 |
double norm2 = norm2_squared(yat::utility::Vector(m_ - old_m)) + |
4192 |
11 Aug 22 |
peter |
201 |
norm2_squared(yat::utility::Vector(alpha_ - old_alpha)); |
4192 |
11 Aug 22 |
peter |
202 |
return norm2 > 1e-9; |
4192 |
11 Aug 22 |
peter |
203 |
} |
4192 |
11 Aug 22 |
peter |
204 |
|
4192 |
11 Aug 22 |
peter |
205 |
|
4192 |
11 Aug 22 |
peter |
206 |
double NegativeBinomialExtendedMixture::p(size_t i) const |
4192 |
11 Aug 22 |
peter |
207 |
{ |
4192 |
11 Aug 22 |
peter |
208 |
return 1.0 - 1.0/alpha_(i); |
4192 |
11 Aug 22 |
peter |
209 |
} |
4192 |
11 Aug 22 |
peter |
210 |
|
4192 |
11 Aug 22 |
peter |
211 |
|
4192 |
11 Aug 22 |
peter |
212 |
double NegativeBinomialExtendedMixture::pdf(unsigned long int k, double m, |
4192 |
11 Aug 22 |
peter |
213 |
double alpha) const |
4192 |
11 Aug 22 |
peter |
214 |
{ |
4192 |
11 Aug 22 |
peter |
215 |
if (m <= 0) { |
4192 |
11 Aug 22 |
peter |
216 |
if (m == 0 && k==0) |
4192 |
11 Aug 22 |
peter |
217 |
return 1.0; |
4192 |
11 Aug 22 |
peter |
218 |
return 0.0; |
4192 |
11 Aug 22 |
peter |
219 |
} |
4192 |
11 Aug 22 |
peter |
220 |
|
4192 |
11 Aug 22 |
peter |
221 |
if (alpha <= 1.0) |
4192 |
11 Aug 22 |
peter |
222 |
return gsl_ran_poisson_pdf(k, m); |
4192 |
11 Aug 22 |
peter |
223 |
double p = 1 - 1.0 / alpha; |
4192 |
11 Aug 22 |
peter |
224 |
double r = m / (alpha - 1); |
4192 |
11 Aug 22 |
peter |
225 |
return gsl_ran_negative_binomial_pdf(k, 1.0-p, r); |
4192 |
11 Aug 22 |
peter |
226 |
} |
4192 |
11 Aug 22 |
peter |
227 |
|
4192 |
11 Aug 22 |
peter |
228 |
|
4192 |
11 Aug 22 |
peter |
229 |
double NegativeBinomialExtendedMixture::r(size_t i) const |
4192 |
11 Aug 22 |
peter |
230 |
{ |
4192 |
11 Aug 22 |
peter |
231 |
return m_(i) / (alpha_(i)-1.0); |
4192 |
11 Aug 22 |
peter |
232 |
} |
4192 |
11 Aug 22 |
peter |
233 |
|
4192 |
11 Aug 22 |
peter |
234 |
|
4192 |
11 Aug 22 |
peter |
235 |
const yat::utility::Vector& NegativeBinomialExtendedMixture::tau(void) const |
4192 |
11 Aug 22 |
peter |
236 |
{ |
4192 |
11 Aug 22 |
peter |
237 |
return tau_; |
4192 |
11 Aug 22 |
peter |
238 |
} |
4192 |
11 Aug 22 |
peter |
239 |
|
4192 |
11 Aug 22 |
peter |
240 |
|
4192 |
11 Aug 22 |
peter |
241 |
NegativeBinomialExtendedMixture:: |
4192 |
11 Aug 22 |
peter |
242 |
Q::Q(const std::vector<std::pair<unsigned long int, double>>& data, |
4192 |
11 Aug 22 |
peter |
243 |
const yat::utility::VectorBase& h) |
4192 |
11 Aug 22 |
peter |
244 |
: data_(data), h_(h) |
4192 |
11 Aug 22 |
peter |
245 |
{ |
4192 |
11 Aug 22 |
peter |
246 |
} |
4192 |
11 Aug 22 |
peter |
247 |
|
4192 |
11 Aug 22 |
peter |
248 |
|
4192 |
11 Aug 22 |
peter |
249 |
double NegativeBinomialExtendedMixture::Q::operator() |
4192 |
11 Aug 22 |
peter |
250 |
(const yat::utility::VectorBase& x) |
4192 |
11 Aug 22 |
peter |
251 |
{ |
4192 |
11 Aug 22 |
peter |
252 |
assert(x.size()==2); |
4192 |
11 Aug 22 |
peter |
253 |
double m = x(0); |
4192 |
11 Aug 22 |
peter |
254 |
double alpha = x(1); |
4192 |
11 Aug 22 |
peter |
255 |
double sum = 0; |
4192 |
11 Aug 22 |
peter |
256 |
|
4192 |
11 Aug 22 |
peter |
257 |
for (size_t i=0; i<data_.size(); ++i) { |
4192 |
11 Aug 22 |
peter |
258 |
unsigned long int k = data_[i].first; |
4192 |
11 Aug 22 |
peter |
259 |
double y = data_[i].second; |
4192 |
11 Aug 22 |
peter |
260 |
sum -= h_(i) * log_L(m, alpha, k, y); |
4192 |
11 Aug 22 |
peter |
261 |
} |
4192 |
11 Aug 22 |
peter |
262 |
return sum; |
4192 |
11 Aug 22 |
peter |
263 |
} |
4192 |
11 Aug 22 |
peter |
264 |
|
4192 |
11 Aug 22 |
peter |
265 |
|
4192 |
11 Aug 22 |
peter |
266 |
void NegativeBinomialExtendedMixture::Q::operator() |
4192 |
11 Aug 22 |
peter |
267 |
(const utility::VectorBase& x, utility::VectorMutable& gradient) |
4192 |
11 Aug 22 |
peter |
268 |
{ |
4192 |
11 Aug 22 |
peter |
269 |
assert(gradient.size() == 2); |
4192 |
11 Aug 22 |
peter |
270 |
assert(data_.size() == h_.size()); |
4192 |
11 Aug 22 |
peter |
271 |
gradient.all(0.0); |
4192 |
11 Aug 22 |
peter |
272 |
|
4192 |
11 Aug 22 |
peter |
273 |
assert(x.size()==2); |
4192 |
11 Aug 22 |
peter |
274 |
double m = x(0); |
4192 |
11 Aug 22 |
peter |
275 |
double alpha = x(1); |
4192 |
11 Aug 22 |
peter |
276 |
|
4192 |
11 Aug 22 |
peter |
277 |
for (size_t i=0; i<data_.size(); ++i) { |
4192 |
11 Aug 22 |
peter |
278 |
unsigned long int k = data_[i].first; |
4192 |
11 Aug 22 |
peter |
279 |
double y = data_[i].second; |
4192 |
11 Aug 22 |
peter |
280 |
gradient -= h_(i) * calc_gradient(m, alpha, k, y); |
4192 |
11 Aug 22 |
peter |
281 |
} |
4192 |
11 Aug 22 |
peter |
282 |
} |
4192 |
11 Aug 22 |
peter |
283 |
|
4192 |
11 Aug 22 |
peter |
284 |
|
4192 |
11 Aug 22 |
peter |
// return dlnL/dp |
4192 |
11 Aug 22 |
peter |
286 |
double |
4192 |
11 Aug 22 |
peter |
287 |
NegativeBinomialExtendedMixture::Q::calculate_dp(double p, double r, |
4192 |
11 Aug 22 |
peter |
288 |
unsigned long int k) const |
4192 |
11 Aug 22 |
peter |
289 |
{ |
4192 |
11 Aug 22 |
peter |
290 |
/* |
4192 |
11 Aug 22 |
peter |
logL = log(Gamma(yr+k)) - log(Gamma(k+1) - log(Gamma(yr)) - |
4192 |
11 Aug 22 |
peter |
yrlog(1-p) + klog(p) |
4192 |
11 Aug 22 |
peter |
293 |
|
4192 |
11 Aug 22 |
peter |
dlnL/dp = d yr*ln(1-p)/dp + d k*ln(p)/dp = |
4192 |
11 Aug 22 |
peter |
= -yr/(1-p) + k/p |
4192 |
11 Aug 22 |
peter |
296 |
*/ |
4192 |
11 Aug 22 |
peter |
297 |
return k/p - r/(1-p); |
4192 |
11 Aug 22 |
peter |
298 |
} |
4192 |
11 Aug 22 |
peter |
299 |
|
4192 |
11 Aug 22 |
peter |
300 |
|
4192 |
11 Aug 22 |
peter |
301 |
double |
4192 |
11 Aug 22 |
peter |
302 |
NegativeBinomialExtendedMixture::Q::calculate_dr(double p, double r, |
4192 |
11 Aug 22 |
peter |
303 |
unsigned long int k) const |
4192 |
11 Aug 22 |
peter |
304 |
{ |
4192 |
11 Aug 22 |
peter |
305 |
/* |
4192 |
11 Aug 22 |
peter |
logL = log(Gamma(yr+k)) - log(Gamma(k+1) - log(Gamma(yr)) - |
4192 |
11 Aug 22 |
peter |
yrlog(1-p) + klog(p) |
4192 |
11 Aug 22 |
peter |
308 |
|
4192 |
11 Aug 22 |
peter |
dlnL/dr = y*d ln(Gamma(y*r+k))/dr - y*d ln(Gamma(y*r))/dr + ln(1-p) |
4192 |
11 Aug 22 |
peter |
310 |
*/ |
4192 |
11 Aug 22 |
peter |
311 |
return gsl_sf_psi(r+k) - gsl_sf_psi(r) + std::log(1.0-p); |
4192 |
11 Aug 22 |
peter |
312 |
} |
4192 |
11 Aug 22 |
peter |
313 |
|
4192 |
11 Aug 22 |
peter |
314 |
|
4192 |
11 Aug 22 |
peter |
315 |
/* |
4192 |
11 Aug 22 |
peter |
return log L = |
4192 |
11 Aug 22 |
peter |
log(Gamma(yr+k)) - log(Gamma(k+1) - log(Gamma(yr)) - yrlog(1-p) + klog(p) |
4192 |
11 Aug 22 |
peter |
318 |
*/ |
4192 |
11 Aug 22 |
peter |
319 |
double |
4192 |
11 Aug 22 |
peter |
320 |
NegativeBinomialExtendedMixture::Q::log_L(double m, double alpha, |
4192 |
11 Aug 22 |
peter |
321 |
unsigned long int k, |
4192 |
11 Aug 22 |
peter |
322 |
double y) const |
4192 |
11 Aug 22 |
peter |
323 |
{ |
4192 |
11 Aug 22 |
peter |
324 |
if (alpha > 1.001) { |
4192 |
11 Aug 22 |
peter |
325 |
double r = y * m / (alpha-1.0); |
4192 |
11 Aug 22 |
peter |
326 |
double p = 1.0 - 1.0/alpha; |
4192 |
11 Aug 22 |
peter |
327 |
return gsl_sf_lngamma(r+k) - gsl_sf_lngamma(k+1) - gsl_sf_lngamma(r) + |
4192 |
11 Aug 22 |
peter |
328 |
r*log(1.0-p) + k*log(p); |
4192 |
11 Aug 22 |
peter |
329 |
} |
4192 |
11 Aug 22 |
peter |
330 |
|
4192 |
11 Aug 22 |
peter |
// alpha = 1+epsilon |
4192 |
11 Aug 22 |
peter |
// r = m / (alpha-1) = m / epsilon |
4192 |
11 Aug 22 |
peter |
// p = (alpha-1) / alpha = epsilon / (1+epsilon) |
4192 |
11 Aug 22 |
peter |
// 1-p = (1+epsilon-epsilon)/(1+epsilon) = 1/(1+epsilon) |
4192 |
11 Aug 22 |
peter |
335 |
|
4192 |
11 Aug 22 |
peter |
// Taylor expand around alpha=1, f(1) + f'(1) * (alpha-1) |
4192 |
11 Aug 22 |
peter |
// where f(1) is the Poisson logL |
4192 |
11 Aug 22 |
peter |
// logL = k*log(m) - m - log(Gamma(k+1)) + |
4192 |
11 Aug 22 |
peter |
// + [(k-1)*k/(2*m) + m/2 - k] (alpha-1) |
4192 |
11 Aug 22 |
peter |
340 |
|
4192 |
11 Aug 22 |
peter |
341 |
double res = k*std::log(y*m) - y*m - gsl_sf_lngamma(k+1); |
4192 |
11 Aug 22 |
peter |
342 |
if (alpha > 1.0) |
4192 |
11 Aug 22 |
peter |
343 |
res += (alpha-1.0) * 0.5*((k-1)*k/(y*m) + y*m - 2*k); |
4192 |
11 Aug 22 |
peter |
344 |
else // penalizing alpha < 1 |
4192 |
11 Aug 22 |
peter |
345 |
res -= 1000*std::pow(alpha-1.0, 2); |
4192 |
11 Aug 22 |
peter |
346 |
|
4192 |
11 Aug 22 |
peter |
347 |
return res; |
4192 |
11 Aug 22 |
peter |
348 |
} |
4192 |
11 Aug 22 |
peter |
349 |
|
4192 |
11 Aug 22 |
peter |
350 |
|
4192 |
11 Aug 22 |
peter |
351 |
utility::Vector |
4192 |
11 Aug 22 |
peter |
352 |
NegativeBinomialExtendedMixture::Q::calc_gradient(double m, double alpha, |
4192 |
11 Aug 22 |
peter |
353 |
unsigned long int k, |
4192 |
11 Aug 22 |
peter |
354 |
double y) const |
4192 |
11 Aug 22 |
peter |
355 |
{ |
4192 |
11 Aug 22 |
peter |
356 |
utility::Vector res(2); |
4192 |
11 Aug 22 |
peter |
357 |
if (alpha > 1.001) { |
4192 |
11 Aug 22 |
peter |
358 |
double r = m / (alpha-1.0); |
4192 |
11 Aug 22 |
peter |
359 |
double p = 1.0 - 1.0/alpha; |
4192 |
11 Aug 22 |
peter |
360 |
double dp = calculate_dp(p, y*r, k); |
4192 |
11 Aug 22 |
peter |
361 |
double dr = y*calculate_dr(p, y*r, k); |
4192 |
11 Aug 22 |
peter |
// df/dm = df/dr * dr/dm + df/dp * dp/dm |
4192 |
11 Aug 22 |
peter |
// = df/dr * 1/(alpha-1) |
4192 |
11 Aug 22 |
peter |
364 |
res(0) = dr / (alpha-1.0); |
4192 |
11 Aug 22 |
peter |
365 |
|
4192 |
11 Aug 22 |
peter |
// df/dalpha = df/dp dp/dalpha + df/dr dr/dalpha = |
4192 |
11 Aug 22 |
peter |
// = df/dp 1/alpha^2 - df/dr m/(alpha-1)^2 |
4192 |
11 Aug 22 |
peter |
368 |
res(1) = dp / std::pow(alpha,2) - dr*m/std::pow(alpha-1, 2); |
4192 |
11 Aug 22 |
peter |
369 |
} |
4192 |
11 Aug 22 |
peter |
370 |
else { |
4192 |
11 Aug 22 |
peter |
// Taylor expansion at alpha=1: |
4192 |
11 Aug 22 |
peter |
// logL = k*log(m*y) - m*y - log(Gamma(k+1)) + |
4192 |
11 Aug 22 |
peter |
// + [(k-1)*k/(2*m*y) + m*y/2 - k] (alpha-1) |
4192 |
11 Aug 22 |
peter |
374 |
|
4192 |
11 Aug 22 |
peter |
// df/dm |
4192 |
11 Aug 22 |
peter |
376 |
res(0) = k/(m*y) - 1; |
4192 |
11 Aug 22 |
peter |
377 |
if (alpha > 1.0) |
4192 |
11 Aug 22 |
peter |
378 |
res(0) += (alpha-1.0) * 0.5 * (1.0 - (k-1)*k/(m*m*y)); |
4192 |
11 Aug 22 |
peter |
379 |
|
4192 |
11 Aug 22 |
peter |
//df/dalpha |
4192 |
11 Aug 22 |
peter |
381 |
res(1) = (k-1)*k/(2*m*y) + (m*y)/2 - k; |
4192 |
11 Aug 22 |
peter |
382 |
if (alpha < 1) // penalizing alpha < 1 |
4192 |
11 Aug 22 |
peter |
383 |
res(1) -= 2*1000*(alpha-1); |
4192 |
11 Aug 22 |
peter |
384 |
} |
4192 |
11 Aug 22 |
peter |
385 |
return res; |
4192 |
11 Aug 22 |
peter |
386 |
} |
4192 |
11 Aug 22 |
peter |
387 |
}}} |