我在使用通过Kevin Murphy 的贝叶斯网络工具箱(以下简称 BNT)训练的贝叶斯网络中学习到的参数时遇到问题。
最终,我想将训练后的参数导出到 Python 中的另一个包,例如pgmpy。当我这样做时,我注意到局部条件属性的总和不等于一。实际上,如果尝试使用贝叶斯网络进行预测,但不满足此条件,则 pgmpy 会引发错误。
我认为这是由于在稀疏数据上使用 BNT 学习参数造成的,其中一些变量的估值实际上并未出现在数据中。最初,我使用期望最大化和连接树算法训练一个带有隐藏变量的复杂网络遇到了这个问题。但是,我可以使用简单的马尔可夫链和最大似然估计 (MLE) 重现相同的问题。在这个例子中,我们定义了一个网络来采样一些测试数据。然后我们创建该网络的新版本,该版本具有不会出现在测试数据中的新“虚构”状态。
O=1:2; % We have 2 observable nodes O(1) and O(2)
node_sizes=repelem(2, 2);
% initially both variables have just two states, but this will change later
num_nodes=length(node_sizes);
onodes=O;
dag=false(num_nodes, num_nodes);
dag(1,2)=true; % O(1) -> O(2)
ix2var = string({'o1','o2'});
seed=42;
rand('state', seed);
randn('state', seed);
% the initial network that will create some test data
bnet = mk_bnet(dag, node_sizes, 'names', cellstr(ix2var), 'observed', onodes);
% set some arbitrary probabilities to get some test data
bnet.CPD{O(1)} = tabular_CPD(bnet, O(1), 'CPT', [0.2, 0.8]);
bnet.CPD{O(2)} = tabular_CPD(bnet, O(2), 'CPT', [0.3, 0.7, 0.6, 0.4]);
N = length(onodes);
nsamples = 200;
samples = cell(N, nsamples);
for i=1:nsamples
samples(:,i) = sample_bnet(bnet);
end
node_sizes=repelem(3, 2); % introduce the imaginary state into our observable variables
% redefined the network with the new imaginary states
bnet = mk_bnet(dag, node_sizes, 'names', cellstr(ix2var), 'observed', onodes);
% initialise the CPTs to uniform distributions prior to training
bnet.CPD{O(1)} = tabular_CPD(bnet, O(1));
bnet.CPD{O(2)} = tabular_CPD(bnet, O(2));
% learn parameters using MLE
bnet = learn_params(bnet, samples);
% copy CPT parameters to cpts
cpts=cell(num_nodes);
for i = 1:num_nodes
cpts{i} = struct(bnet.CPD{i}).CPT;
end
% now check Sigma(i=1..3)(P(O(2)_i)| O(1)=3) == 1
%sum(cpts{O(2)}(3,:))
% ans =
%
% 0
% Oh no! It's zero!
所以我的问题是:
- BNT 工作正常吗?我不是要在稀疏数据上训练它吗?
- 如果我想将这些参数加载到另一个包中,我可以将这些“空”分布设置为均匀,即所有系数 1/n,其中 n 是变量可以采用的状态数?
PS 我觉得麻烦的一件事是,如果学习是以小批量方式进行的,那么学习过程似乎会完全忘记一些局部条件概率,只是因为数据集中没有出现特定值。