gpt4 book ai didi

python - 朴素贝叶斯分类器中特征值的快速计数

转载 作者:行者123 更新时间:2023-12-01 08:53:20 25 4
gpt4 key购买 nike

我正在用 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 包含给定类 c 的特征 j 中值 k 的概率。上面示例的此类矩阵的输出为:

>>> 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 循环很慢,所以这也会变慢。我尝试通过对每个特征值进行 one-hot 编码来缓解这个问题(因此,如果特征值在 [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 (one-hot 编码)是不必要的,并且会杀死它,但我想不出一种方法来摆脱它。我考虑的最后一件事是使用 np.unique()collections.Counter 进行计数,但尚未弄清楚。

最佳答案

所以这是一个非常巧妙的问题(我有一个 similar problem not that long ago )。看起来处理这个问题的最快方法通常是仅使用算术运算构造一个索引数组,然后将其堆积并使用 np.bincount reshape 它。

N, D = X.shape
K = np.max(X) + 1
C = np.max(y) + 1
ccl = np.tile(y, D) * D * K + (X + np.tile(K * range(D), (N,1))).T.flatten()
ccl = np.bincount(ccl, minlength=C*D*K).reshape(C, D, K)
ccl = np.divide(ccl, np.sum(ccl, axis=2)[:, :, np.newaxis])

>>> ccl
array([[[0.5, 0. , 0.5],
[0. , 0.5, 0.5]],

[[0. , 1. , 0. ],
[0. , 0. , 1. ]],

[[0. , 0. , 1. ],
[0. , 0. , 1. ]]])

作为速度比较,funca 是您的第一个基于循环的方法,funcb 是您的第二个基于 numpy 函数的方法,funcc > 是使用 bincount 的方法。

X = np.random.randint(3, size=(10000,2))
y = np.random.randint(3, size=(10000))
>>> timeit.timeit('funca(X,y)', number=100, setup="from __main__ import funca, X, y")
2.632569645998956
>>> timeit.timeit('funcb(X,y)', number=100, setup="from __main__ import funcb, X, y")
0.10547748399949342
>>> timeit.timeit('funcc(X,y)', number=100, setup="from __main__ import funcc, X, y")
0.03524605900020106

也许可以进一步完善它,但我没有更好的想法。

关于python - 朴素贝叶斯分类器中特征值的快速计数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52958786/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com