我正在用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/

10-12 22:41