我正在用Javascript实现特定的贝叶斯网络库。
由于找不到在线上可用的任何其他库,因此我不得不从头开始,包括对概率(或潜力)表进行乘法和边缘化。
在边缘化中,要边缘化的变量的列被取出。
然后将公共行相加。
例如,c将在表phi(a,b,c)中被边缘化。
相对于c的列被取出,并且公共行a和b被求和,即(0,0)和(1,1)的总和分别为0.3和0.1。
在乘法中,我们在公共变量(列)中查找相等的值。
然后,我们将匹配的行相乘。
例如,要将表phi(a,b)和phi(b,c)相乘。
公共栏为b。
在两个表中(所有可能的组合)b均为0时,我们将这些值相乘。
我的第一个尝试是以Map方式实现表,其中每一行是一个键,而概率值是该值。
但这似乎不是一个好主意,因为要实现乘法,我们需要知道变量的标签。因此,我对代码进行了一些修改,以便从function参数中获取标签,但由于行与标签没有直接关系,因此它无法正常工作。
因此,我将这段代码放在一边,现在我正在寻找新的想法。
拜托,有人对如何实现这些示例有任何想法?
最佳答案
以下似乎可以做到这一点。它创建一个具有行的表,该行具有成员和一个值。表中的每一行必须具有相同数量的成员。
它还没有实现乘法(必须在某个时候完成实际工作……)。请注意,在ECMAScript中,0.1 + 0.2 = 0.30000000000000004
,因此您需要实现某种舍入方法以解决该问题并保持准确性。
/**
* A table has rows, all rows within a table have the same number of members
* Each row as 1 to n members plus a value
* e.g. a = 0, b = 0, c = 0, value = 0.1
* a = 0, b = 0, c = 1, value = 0.2
* a = 1, b = 0, c = 0, value = 0.1
* a = 1, b = 1, c = 0, value = 0.1
* a = 1, b = 1, c = 1, value = 0.1
*
* Marginalisation addition takes the values of matching values and sums them,
*
* e.g.
* marginalisation of {a, b} where a=0 and b=0:
* matching rows are 0 and 1, so add 0.1 + 0.2 => 0.3
*
* marginalisation of {a, b} where a=1 and b=1:
* matching rows are 3 and 4, so add 0.1 + 0.1 => 0.2
*
* @param {number} numberOfValues - number of values in each row. So for 3 members
* plus value then numberOfValues is 4
*/
function BayTable (numberOfValues) {
// Array containing rows of values
this.rows = [];
// Number of values in a row, so for [a, b, c, value] memberCount is 4
this.memberCount = numberOfValues;
}
/**
* @param {number} memberValue[, memberValue, ...], rowValue
*
* e.g. addRow(0, 0, 0, 0.1)
*/
BayTable.prototype.addRow = function() {
if (arguments.length != this.memberCount) return; // or throw error
var row = [];
for (var i=0, iLen=arguments.length; i<iLen; i++) {
row.push(arguments[i]);
}
this.rows.push(row);
}
/**
* marginalise finds matching rows and adds their values,
* so marginalise(0,0) finds rows where a=0 and b=0 ignoring
* any other member in the row and
* sums the value for the rows
*/
BayTable.prototype.marginalise = function() {
// Guard agains too many arguments
if (arguments.length > this.memberCount - 2) return; // or throw error
var total = 0;
var row, match;
// For each row
for (var i=0, iLen=this.rows.length; i<iLen; i++) {
row = this.rows[i];
match = true
// Check values against arguments until a missmatch
for (var j=0, jLen=arguments.length; j<jLen && match; j++) {
match = row[j] === arguments[j];
}
// If no missmatch, add row value
if (match) total += row[row.length - 1];
}
return total;
}
var x = new BayTable(4);
x.addRow(0, 0, 0, 0.1);
x.addRow(0, 0, 1, 0.2);
x.addRow(1, 0, 0, 0.1);
x.addRow(1, 1, 0, 0.1);
x.addRow(1, 1, 1, 0.1);
console.log(x.marginalise(0, 0)); // 0.30000000000000004
console.log(x.marginalise(1, 0)); // 0.1
console.log(x.marginalise(1, 1)); // 0.2
这是对象版本,它使用几种ES5方法:
/**
* A table has rows, all rows within a table have the same number of members
* Each row as 1 to n members plus a value
* e.g. a = 0, b = 0, c = 0, value = 0.1
* a = 0, b = 0, c = 1, value = 0.2
* a = 1, b = 0, c = 0, value = 0.1
* a = 1, b = 1, c = 0, value = 0.1
* a = 1, b = 1, c = 1, value = 0.1
*
* Marginalisation addition takes the values of matching values and sums them,
*
* e.g.
* marginalisation of {a, b} where a=0 and b=0:
* matching rows are 0 and 1, so add 0.1 + 0.2 => 0.3
*
* marginalisation of {a, b} where a=1 and b=1:
* matching rows are 3 and 4, so add 0.1 + 0.1 => 0.2
*
* @param {number} numberOfValues - number of values in each row. So for 3 members plus value
* then numberOfValues is 4
*/
function BayTable (numberOfValues) {
// Array containing rows of values
this.rows = [];
// Number of values in a row, so for [a, b, c, value] memberCount is 4
this.memberCount = numberOfValues;
}
/**
* @param {Object} row - {label:value[, label:value, ...], 'value':value}
*
* e.g. addRow({a:0, b:0, c:0, value:0.1})
*/
BayTable.prototype.addRow = function(row) {
this.rows.push(row);
}
/**
* marginalise finds matching rows and adds their values,
* so marginalise({a:0, b:0}) finds rows where a=0 and b=0 ignoring
* any other member in the row and sums the values of matched rows
*/
BayTable.prototype.marginalise = function(obj) {
var keys = Object.keys(obj);
// For each row
return this.rows.reduce(function(total, row) {
// If all key/values match, accumlate value
if (keys.every(function(key){return obj[key] === row[key]}))
total += row.value;
return total;
}, 0);
/*
// Less obscure version, same number of lines of code
var total = 0;
var keys = Object.keys(obj);
// For each row
this.rows.forEach(function(row) {
// If key/values match, add row value to total
if (keys.every(function(key){return obj[key] === row[key]}))
total += row.value;
});
return total;
*/
}
var x = new BayTable(4);
x.addRow({a:0, b:0, c:0, value:0.1});
x.addRow({a:0, b:0, c:1, value:0.2});
x.addRow({a:1, b:0, c:0, value:0.1});
x.addRow({a:1, b:1, c:0, value:0.1});
x.addRow({a:1, b:1, c:1, value:0.1});
console.log(x.marginalise({a:0, b:0})); // 0.30000000000000004
console.log(x.marginalise({a:1, b:0})); // 0.1
console.log(x.marginalise({a:1, b:1})); // 0.2
console.log(x.marginalise({a:1, c:1})); // 0.1
console.log(x.marginalise({b:0, c:0})); // 0.2
关于javascript - 乘法和边缘化概率表的算法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27830677/