-
-
Notifications
You must be signed in to change notification settings - Fork 197
feature/neg_binomial_2_log_glm #658
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
seantalts
merged 22 commits into
stan-dev:develop
from
VMatthijs:feature/neg_binomial_2_log_glm
Nov 14, 2017
Merged
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
1374757
Normal Linear GLM working
VMatthijs fd65182
Added Test, which passes
VMatthijs de35b3b
Removed poissonglm from mat.hpp, to help merging
VMatthijs 19b0b41
Removed poisson regression files to help merging
VMatthijs d9acb80
Satisfied cpplint + did performance tests - 4.5 performance gain over…
VMatthijs 5d155f2
commented out performance test
VMatthijs 7e4e5fd
initial stab at neg_binomial_2_log_glm
VMatthijs 95f1a74
neg_binomial_2_log_glm finished and working
VMatthijs 6f71ca9
minor speedup
VMatthijs 6aba311
Merge branch 'develop' of https://github.com/stan-dev/math into featu…
VMatthijs 3906562
done for review
VMatthijs 1d0c285
Merge branch 'develop' of https://github.com/stan-dev/math into featu…
VMatthijs 625ace1
satisfied cpplint for test
VMatthijs dde66fd
minor
VMatthijs d276308
Merge branch 'develop' into feature/neg_binomial_2_log_glm
seantalts 178adb8
fixed passing by reference in lambdas
VMatthijs 4385fec
Merge branch 'feature/neg_binomial_2_log_glm' of https://github.com/V…
VMatthijs 94ce8f1
Merge branch 'develop' into feature/neg_binomial_2_log_glm
VMatthijs 0866b23
Merge branch 'develop' into feature/neg_binomial_2_log_glm
VMatthijs f168bfd
minor
VMatthijs d6135c8
Merge branch 'develop' of https://github.com/stan-dev/math into featu…
VMatthijs e3147a7
Merge branch 'feature/neg_binomial_2_log_glm' of https://github.com/V…
VMatthijs File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
196 changes: 196 additions & 0 deletions
196
stan/math/prim/mat/prob/neg_binomial_2_log_glm_lpmf.hpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
#ifndef STAN_MATH_PRIM_MAT_PROB_NEG_BINOMIAL_2_LOG_GLM_LPMF_HPP | ||
#define STAN_MATH_PRIM_MAT_PROB_NEG_BINOMIAL_2_LOG_GLM_LPMF_HPP | ||
|
||
#include <stan/math/prim/scal/meta/is_constant_struct.hpp> | ||
#include <stan/math/prim/scal/meta/partials_return_type.hpp> | ||
#include <stan/math/prim/scal/meta/operands_and_partials.hpp> | ||
#include <stan/math/prim/scal/err/check_consistent_sizes.hpp> | ||
#include <stan/math/prim/scal/err/check_positive_finite.hpp> | ||
#include <stan/math/prim/scal/err/check_nonnegative.hpp> | ||
#include <stan/math/prim/scal/err/check_finite.hpp> | ||
#include <stan/math/prim/scal/fun/constants.hpp> | ||
#include <stan/math/prim/scal/fun/multiply_log.hpp> | ||
#include <stan/math/prim/scal/fun/digamma.hpp> | ||
#include <stan/math/prim/scal/fun/lgamma.hpp> | ||
#include <stan/math/prim/scal/fun/log_sum_exp.hpp> | ||
#include <stan/math/prim/scal/fun/value_of.hpp> | ||
#include <stan/math/prim/mat/fun/value_of.hpp> | ||
#include <stan/math/prim/scal/meta/include_summand.hpp> | ||
#include <stan/math/prim/scal/meta/scalar_seq_view.hpp> | ||
#include <cmath> | ||
|
||
namespace stan { | ||
namespace math { | ||
|
||
/** | ||
* Returns the log PMF of the Generalized Linear Model (GLM) | ||
* with Negative-Binomial-2 distribution and log link function. | ||
* If containers are supplied, returns the log sum of the probabilities. | ||
* @tparam T_n type of positive int vector of variates (labels); | ||
* this can also be a single positive integer value; | ||
* @tparam T_x type of the matrix of covariates (features); this | ||
* should be an Eigen::Matrix type whose number of rows should match the | ||
* length of n and whose number of columns should match the length of beta | ||
* @tparam T_beta type of the weight vector; | ||
* this can also be a scalar; | ||
* @tparam T_alpha type of the intercept; | ||
* this should be a scalar; | ||
* @tparam T_precision type of the (positive) precision vector phi; | ||
* this can also be a scalar; | ||
* @param n failures count vector parameter | ||
* @param x design matrix | ||
* @param beta weight vector | ||
* @param alpha intercept (in log odds) | ||
* @param phi (vector of) precision parameters | ||
* @return log probability or log sum of probabilities | ||
* @throw std::invalid_argument if container sizes mismatch. | ||
* @throw std::domain_error if x, beta or alpha is infinite. | ||
* @throw std::domain_error if phi is infinite or non-positive. | ||
* @throw std::domain_error if n is negative. | ||
*/ | ||
template <bool propto, typename T_n, typename T_x, typename T_beta, | ||
typename T_alpha, typename T_precision> | ||
typename return_type<T_x, T_beta, T_alpha, T_precision>::type | ||
neg_binomial_2_log_glm_lpmf(const T_n &n, const T_x &x, const T_beta &beta, | ||
const T_alpha &alpha, const T_precision &phi) { | ||
static const char* function = "neg_binomial_2_log_glm_lpmf"; | ||
typedef typename stan::partials_return_type<T_n, T_x, T_beta, | ||
T_alpha, T_precision>::type | ||
T_partials_return; | ||
|
||
using std::exp; | ||
using Eigen::Dynamic; | ||
using Eigen::Matrix; | ||
using Eigen::Array; | ||
|
||
if (!(stan::length(n) && stan::length(x) && stan::length(beta) | ||
&& stan::length(phi))) | ||
return 0.0; | ||
|
||
T_partials_return logp(0.0); | ||
|
||
check_nonnegative(function, "Failures variables", n); | ||
check_finite(function, "Matrix of independent variables", x); | ||
check_finite(function, "Weight vector", beta); | ||
check_finite(function, "Intercept", alpha); | ||
check_positive_finite(function, "Precision parameter", phi); | ||
check_consistent_sizes(function, | ||
"Rows in matrix of independent variables", | ||
x.col(0), "Vector of dependent variables", n); | ||
check_consistent_sizes(function, | ||
"Rows in matrix of independent variables", | ||
x.col(0), "Vector of failure counts", phi); | ||
check_consistent_sizes(function, | ||
"Columns in matrix of independent variables", | ||
x.row(0), "Weight vector", beta); | ||
|
||
if (!include_summand<propto, T_x, T_beta, T_alpha, T_precision>::value) | ||
return 0.0; | ||
|
||
const size_t N = x.col(0).size(); | ||
const size_t M = x.row(0).size(); | ||
|
||
Array<T_partials_return, Dynamic, 1> n_arr(N, 1); | ||
Array<T_partials_return, Dynamic, 1> phi_arr(N, 1); | ||
{ | ||
scalar_seq_view<T_n> n_vec(n); | ||
scalar_seq_view<T_precision> phi_vec(phi); | ||
for (size_t n = 0; n < N; ++n) { | ||
n_arr[n] = n_vec[n]; | ||
phi_arr[n] = value_of(phi_vec[n]); | ||
} | ||
} | ||
|
||
Matrix<T_partials_return, Dynamic, 1> beta_dbl(M, 1); | ||
{ | ||
scalar_seq_view<T_beta> beta_vec(beta); | ||
for (size_t m = 0; m < M; ++m) { | ||
beta_dbl[m] = value_of(beta_vec[m]); | ||
} | ||
} | ||
Matrix<T_partials_return, Dynamic, Dynamic> x_dbl = value_of(x); | ||
|
||
Array<T_partials_return, Dynamic, 1> theta_dbl = (x_dbl * beta_dbl | ||
+ Matrix<double, Dynamic, 1>::Ones(N, 1) * value_of(alpha)).array(); | ||
Array<T_partials_return, Dynamic, 1> log_phi = phi_arr.log(); | ||
Array<T_partials_return, Dynamic, 1> logsumexp_eta_logphi = | ||
theta_dbl.binaryExpr(log_phi, | ||
[](const T_partials_return& xx, | ||
const T_partials_return& yy) { | ||
return log_sum_exp(xx, yy); | ||
}); | ||
Array<T_partials_return, Dynamic, 1> n_plus_phi = n_arr + phi_arr; | ||
|
||
// Compute the log-density. | ||
if (include_summand<propto>::value) { | ||
logp -= (n_arr | ||
+ Array<double, Dynamic, 1>::Ones(N, 1)) | ||
.unaryExpr([](const T_partials_return& xx) { | ||
return lgamma(xx); | ||
}).sum(); | ||
} | ||
if (include_summand<propto, T_precision>::value) { | ||
logp += (phi_arr.binaryExpr(phi_arr, [](const T_partials_return& xx, | ||
const T_partials_return& yy) { | ||
return multiply_log(xx, yy); | ||
}) | ||
- phi_arr.unaryExpr([](const T_partials_return& xx) { | ||
return lgamma(xx); | ||
})).sum(); | ||
} | ||
if (include_summand<propto, T_x, T_beta, T_alpha, T_precision>::value) | ||
logp -= (n_plus_phi * logsumexp_eta_logphi).sum(); | ||
if (include_summand<propto, T_x, T_beta, T_alpha>::value) | ||
logp += (n_arr * theta_dbl).sum(); | ||
if (include_summand<propto, T_precision>::value) { | ||
logp += n_plus_phi.unaryExpr([](const T_partials_return& xx) { | ||
return lgamma(xx); | ||
}).sum(); | ||
} | ||
|
||
// Compute the necessary derivatives. | ||
operands_and_partials<T_x, T_beta, T_alpha, | ||
T_precision> ops_partials(x, beta, alpha, phi); | ||
|
||
if (!(is_constant_struct<T_x>::value && is_constant_struct<T_beta>::value | ||
&& is_constant_struct<T_alpha>::value)) { | ||
Matrix<T_partials_return, Dynamic, 1> theta_derivative(N, 1); | ||
theta_derivative = (n_arr - (n_plus_phi / (phi_arr / (theta_dbl.exp()) | ||
+ Array<double, Dynamic, 1>::Ones(N, 1)))).matrix(); | ||
if (!is_constant_struct<T_beta>::value) { | ||
ops_partials.edge2_.partials_ = x_dbl.transpose() * theta_derivative; | ||
} | ||
if (!is_constant_struct<T_x>::value) { | ||
ops_partials.edge1_.partials_ = theta_derivative | ||
* beta_dbl.transpose(); | ||
} | ||
if (!is_constant_struct<T_alpha>::value) { | ||
ops_partials.edge3_.partials_[0] = theta_derivative.trace(); | ||
} | ||
} | ||
if (!is_constant_struct<T_precision>::value) { | ||
ops_partials.edge4_.partials_ = (Array<double, Dynamic, 1>::Ones(N, 1) | ||
- n_plus_phi / (theta_dbl.exp() + phi_arr) + log_phi | ||
- logsumexp_eta_logphi | ||
- phi_arr.unaryExpr([](const T_partials_return& xx) { | ||
return digamma(xx); | ||
}) | ||
+ n_plus_phi.unaryExpr([](const T_partials_return& xx) { | ||
return digamma(xx); | ||
})).matrix(); | ||
} | ||
return ops_partials.build(logp); | ||
} | ||
|
||
template <typename T_n, typename T_x, typename T_beta, typename T_alpha, | ||
typename T_precision> | ||
inline | ||
typename return_type<T_x, T_beta, T_alpha, T_precision>::type | ||
neg_binomial_2_log_glm_lpmf(const T_n &n, const T_x &x, | ||
const T_beta &beta, const T_alpha &alpha, | ||
const T_precision& phi) { | ||
return neg_binomial_2_log_glm_lpmf<false>(n, x, beta, alpha, phi); | ||
} | ||
} // namespace math | ||
} // namespace stan | ||
#endif |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have wisdom / rules of thumb to share on when
.matrix()
or.eval()
are required?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, a little bit. .matrix() and .array() convert back and forth between Eigen::Matrix and Eigen::Array types. There is no runtime cost. The two types just provide a different interface: matrix operations vs coefficient-wise operations. Sometimes you need one, sometimes the other.
.eval() forces eager evaluation, as far as I understand it. By default, Eigen has lazy evaluation. I guess there are some cases where you want eager evaluation for efficiency or for correctness purposes, which you can force with .eval(). I haven't used it though.