class NaiveBayes(object):
def __init__(self, num_class, feature_dim, num_value):
"""Initialize a naive bayes model.
This function will initialize prior and likelihood, where
prior is P(class) with a dimension of (# of class,)
that estimates the empirical frequencies of different classes in the training set.
likelihood is P(F_i = f | class) with a dimension of
(# of features/pixels per image, # of possible values per pixel, # of class),
that computes the probability of every pixel location i being value f for every class label.
Args:
num_class(int): number of classes to classify
feature_dim(int): feature dimension for each example
num_value(int): number of possible values for each pixel
"""
self.num_value = num_value
self.num_class = num_class
self.feature_dim = feature_dim
self.prior = np.zeros((num_class))
self.likelihood = np.zeros((feature_dim, num_value, num_class))
def train(self, train_set, train_label):
""" Train naive bayes model (self.prior and self.likelihood) with training dataset.
self.prior(numpy.ndarray): training set class prior (in log) with a dimension of (# of class,),
self.likelihood(numpy.ndarray): traing set likelihood (in log) with a dimension of
(# of features/pixels per image, # of possible values per pixel, # of class).
You should apply Laplace smoothing to compute the likelihood.
Args:
train_set(numpy.ndarray): training examples with a dimension of (# of examples, feature_dim)
train_label(numpy.ndarray): training labels with a dimension of (# of examples, )
"""
self.calculate_prior_probability(train_set, train_label)
class_count = self.calculate_class_counts(train_label)
self.calculate_likelihood(train_set, train_label, class_count)
def test(self, test_set, test_label):
""" Test the trained naive bayes model (self.prior and self.likelihood) on testing dataset,
by performing maximum a posteriori (MAP) classification.
The accuracy is computed as the average of correctness
by comparing between predicted label and true label.
Args:
test_set(numpy.ndarray): testing examples with a dimension of (# of examples, feature_dim)
test_label(numpy.ndarray): testing labels with a dimension of (# of examples, )
Returns:
accuracy(float): average accuracy value
pred_label(numpy.ndarray): predicted labels with a dimension of (# of examples, )
"""
accuracy = 0
pred_label = np.zeros((len(test_set)))
count = 0
for i in range(len(test_set)):
test_image = test_set[i]
actual_label = test_label[i]
posterior_probabilites = np.zeros(self.num_class)
for c in range(self.num_class):
probability = 0
for j in range(len(test_image)):
current_likelihood = self.likelihood[j][test_image[j]][c]
probability += current_likelihood
probability += np.log(self.prior[c])
posterior_probabilites[c] = probability
predicted_label = np.argmax(posterior_probabilites)
pred_label[i] = predicted_label
if actual_label == predicted_label:
count = count + 1
accuracy = count / len(test_set)
return accuracy, pred_label
def intensity_feature_likelihoods(self, likelihood):
"""
Get the feature likelihoods for high intensity pixels for each of the classes,
by sum the probabilities of the top 128 intensities at each pixel location,
sum k<-128:255 P(F_i = k | c).
This helps generate visualization of trained likelihood images.
Args:
likelihood(numpy.ndarray): likelihood (in log) with a dimension of
(# of features/pixels per image, # of possible values per pixel, # of class)
Returns:
feature_likelihoods(numpy.ndarray): feature likelihoods for each class with a dimension of
(# of features/pixels per image, # of class)
"""
feature_likelihoods = np.zeros((likelihood.shape[0], likelihood.shape[2]))
for i in range(likelihood.shape[0]):
for j in range(likelihood.shape[2]):
sum = 0
for k in range(128,255):
sum = sum + likelihood[i][k][j]
feature_likelihoods[i][j] = sum
return feature_likelihoods
def calculate_prior_probability(self, train_set, train_label):
unique, counts = np.unique(train_label, return_counts=True)
prior_counts = dict(zip(unique, counts))
length_set = len(train_label)
for i in range(self.num_class):
self.prior[i] = prior_counts[i] / length_set
def calculate_likelihood(self, train_set, train_label, class_counts):
laplace = 0.1
for i in range(len(train_set)):
for j in range(self.feature_dim):
self.likelihood[j][train_set[i][j]][train_label[i]] += 1
for i, value in np.ndenumerate(self.likelihood):
counts = self.likelihood[i[0]][i[1]][i[2]]
self.likelihood[i[0]][i[1]][i[2]] = np.log(((counts + laplace) / (laplace * self.num_value + class_counts[i[2]])))
def calculate_class_counts(self, train_label):
unique, counts = np.unique(train_label, return_counts=True)
class_counts = dict(zip(unique, counts))
return class_counts