Я реализую наивный байесовский классификатор в Python (как часть университетского задания, поэтому Python является обязательным требованием).Я получил его на работу, и он дает примерно тот же результат, что и sklearn.naive_bayes.MultinomialNB
.Однако это очень медленно по сравнению с реализацией sklearn.
Предположим, что значения объектов являются целыми числами в диапазоне от 0 до max_i, а метки классов также являются целыми числами в диапазоне от 0 до max_y.Пример набора данных выглядит следующим образом:
>>> X = np.array([2,1 1,2 2,2 0,2]).reshape(4,2) # design matrix
>>> print(X)
[[2 1]
[1 2]
[2 2]
[0 2]]
>>> y = np.array([0, 1, 2, 0 ]) # class labels
>>> print(y)
[0 1 2 0]
Теперь, в качестве промежуточного шага, прежде чем работать с вероятностью совместного журнала, мне нужно вычислить условные вероятности класса (то есть P(x_ij | y)
так, чтобы матрица ccl
содержалавероятность значения k в признаке j данного класса C. Вывод такой матрицы для приведенного выше примера будет:
>>> print(ccl)
[[[0.5 0. 0.5]
[0. 0.5 0.5]]
[[0. 1. 0. ]
[0. 0. 1. ]]
[[0. 0. 1. ]
[0. 0. 1. ]]]
>>> print(ccl[0][1][1]) # prob. of value 1 in feature 1 given class 0
0.5
Код, который я реализовал для достижения этой цели, выглядит следующим образом:
N, D = X.shape
K = np.max(X)+1
C = np.max(y)+1
ccl = np.zeros((C,D,K))
# ccl = ccl + alpha - 1 # disregard the dirichlet prior for this question
# Count occurences of feature values given class c
for i in range(N):
for d in range(D):
ccl[y[i]][d][X[i][d]] += 1
# Renormalize so it becomes a probability distribution again
for c in range(C):
for d in range(D):
cls[c][d] = np.divide(cls[c][d], np.sum(cls[c][d]))
Так как цикл Python медленный, это также становится медленным. Я попытался смягчить эту проблему путем горячего кодирования каждого значения свойства (поэтому, если значения объекта находятся в диапазоне [0,1,2], 2 становится: [0,0,1] и т. Д.) И суммируем так: хотя, я думаю, слишком много np-функций вызывается, поэтому вычисление все равно занимает слишком много времени:
ccl = np.zeros((C,D,K))
for c in range(C):
x = np.eye(K)[X[np.where(y==c)]] # one hot encoding
ccl[c] += np.sum(x, axis=0) # summing up
ccl[c] /= ccl[c].sum(axis=1)[:, numpy.newaxis] # renormalization
Это приведет ктот же вывод, что и выше. Любые советы о том, как сделать это быстрее? Я думаю, что np.eye
(однократное кодирование) не нужно и убивает его, но я не могу придумать, как избавиться от него. И последнееЯ считаюкрасный использует np.unique()
или collections.Counter
для подсчета, но еще не понял.