 |
| |
Hi .......
In a previous post, I noted that too many acts have NaN values when running GNB. I was reviewing the GNB code and I noticed that the joint probability is used without normalization. I quote the following comment from the file 'test_gnb.m'
% with uniform priors, the final log posterior is just the % normalized log likelihood. We would normally try to normalize
% within logs to avoid underflow, but that doesn't seem to be % necessary here.
This is true when very few voxels are used, but when thousands (and may be hundreds) of voxels are used as input, it will lead to zeroing the posteriori probability. I think it is better (and might be necessary) to do the normalization
as follows (to be placed right after the above comment):
ZZ = abs(sum(log_likelihood,1)/nConds); % I found this to be very useful
for k=1:nTimepoints log_likelihood(:,k) = log_likelihood(:,k)/ZZ(k);
end
I think, however, that the above is not 100% correct since the normalization is placed before exp(log_likelihood) which violates Bayes formula. Thus, to solve the problem we may just use the log_likelihood itself, after adding a simple shifting statement. I copy paste 'test_gnb' after slightly modifying the code to the one I propose.
Regards
Al-Rawi..
function [acts,scratch] = test_gnb(testpats,testtargs, scratch)
% Use a Gaussian Naive Bayes classifier to predict regressors.
%
% [ACTS, SCRATCHPAD] = TEST_GNB(TESTPATS, TESTTARGS, SCRATCH)
%
% See TRAIN_GNB for more info.
% License:
%=====================================================================
%
% This is part of the Princeton MVPA toolbox, released under
% the GPL. See http://www.csbmb.princeton.edu/mvpa for more
% information.
%
% The Princeton MVPA toolbox is available free and
% unsupported to those who might find it useful. We do not
% take any responsibility whatsoever for any problems that
% you have related to the use of the MVPA toolbox.
%
% ======================================================================
nConds = size(testtargs,1);
[nVox nTimepoints] = size(testpats);
% To make a prediction for a given test pattern, we compute the
% posterior likelihood of observing the label for the given
% pattern:
%
% Pr(Y = y | X = x) ~ Pr( X = x | Y = y) * Pr (Y = y)
warning('off');
% compute the likelihood of the data under the MLE estimated
% gaussian model for each category
for k = 1:nConds
% we calculate the proper mu and sigma for each voxel and each
% timepoint:
% scratch.mu is a nVox x 1 vector of voxel means for that condition
mu = repmat(scratch.mu(:,k), 1, nTimepoints);
% scratch.sigma is a nVox x 1 vector of voxel variances for a condition
sigma = repmat(scratch.sigma(:,k), 1, nTimepoints);
% compute the likelihood of the data under label k (this just the
% value of the gaussian equation using the estimated means and variances)
raw_likelihood = normpdf(testpats, mu, sigma);
% GNB assumes all voxels are independent, so we multiply these probabilities
% together to get the likelihood of each data point: we do this in
% the log domain by summing to avoid underflow
log_likelihood(k, :) = sum(log(raw_likelihood), 1);
end
% makes it more correct if we want to add a prior
log_posterior = log_likelihood + repmat(log(scratch.prior), 1, nTimepoints);
% The exp will result in underflow as in acts = exp(log_posterior), we might face cases like exp(-1000) which gives 0. However,
% if P(w1) > P(w2), then log(P(w1)) > log(P(w2)) , so lets forget the exp and normalization and use the log itself
posterior = log_posterior - repmat( min(log_posterior),nConds,1) ; % simple shifting to produce +ve values
acts = posterior;
acts = acts ./ repmat(sum(acts,1), nConds, 1);
| | | | | |