editablebayesnet.java
来自「Weka」· Java 代码 · 共 1,981 行 · 第 1/5 页
JAVA
1,981 行
package weka.classifiers.bayes.net;/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* * EditableBayesNet.java * */import java.io.Serializable;import java.io.StringReader;import java.util.StringTokenizer;import javax.xml.parsers.DocumentBuilderFactory;import org.w3c.dom.CharacterData;import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import weka.classifiers.bayes.BayesNet;import weka.classifiers.bayes.net.estimate.DiscreteEstimatorBayes;import weka.core.Attribute;import weka.core.FastVector;import weka.core.Instances;import weka.core.SerializedObject;import weka.estimators.Estimator;import weka.filters.Filter;import weka.filters.unsupervised.attribute.Reorder;/** <!-- globalinfo-start --> * Bayes Network that allows for editing operations on a Bayesian network * with undo/redo facilities. * * <br/> * For more information see:<br/> * <br/> * http://www.cs.waikato.ac.nz/~remco/weka.pdf * <p/> <!-- globalinfo-end --> * <!-- options-start --> * Valid options are: <p/> * * <pre> -D * Do not use ADTree data structure * </pre> * * <pre> -B <BIF file> * BIF file to compare with * </pre> * * <pre> -Q weka.classifiers.bayes.net.search.SearchAlgorithm * Search algorithm * </pre> * * <pre> -E weka.classifiers.bayes.net.estimate.SimpleEstimator * Estimator algorithm * </pre> * <!-- options-end --> * * @author Remco Bouckaert (rrb@xm.co.nz) * @version $Revision: 1.1 $ */public class EditableBayesNet extends BayesNet { /** for serialization */ static final long serialVersionUID = 746037443258735954L; /** location of nodes, used for graph drawing * */ protected FastVector m_nPositionX; protected FastVector m_nPositionY; /** marginal distributions * */ protected FastVector m_fMarginP; /** evidence values, used for evidence propagation * */ protected FastVector m_nEvidence; /** standard constructor * */ public EditableBayesNet() { super(); m_nEvidence = new FastVector(0); m_fMarginP = new FastVector(0); m_nPositionX = new FastVector(); m_nPositionY = new FastVector(); clearUndoStack(); } // c'tor /** constructor, creates empty network with nodes based on the attributes in a data set */ public EditableBayesNet(Instances instances) { try { if (instances.classIndex() < 0) { instances.setClassIndex(instances.numAttributes() - 1); } m_Instances = normalizeDataSet(instances); } catch (Exception e) { e.printStackTrace(); } int nNodes = getNrOfNodes(); m_ParentSets = new ParentSet[nNodes]; for (int i = 0; i < nNodes; i++) { m_ParentSets[i] = new ParentSet(); } m_Distributions = new Estimator[nNodes][]; for (int iNode = 0; iNode < nNodes; iNode++) { m_Distributions[iNode] = new Estimator[1]; m_Distributions[iNode][0] = new DiscreteEstimatorBayes(getCardinality(iNode), 0.5); } m_nEvidence = new FastVector(nNodes); for (int i = 0; i < nNodes; i++) { m_nEvidence.addElement(-1); } m_fMarginP = new FastVector(nNodes); for (int i = 0; i < nNodes; i++) { double[] P = new double[getCardinality(i)]; m_fMarginP.addElement(P); } m_nPositionX = new FastVector(nNodes); m_nPositionY = new FastVector(nNodes); for (int iNode = 0; iNode < nNodes; iNode++) { m_nPositionX.addElement(iNode%10 * 50); m_nPositionY.addElement(((int)(iNode/10)) * 50); } } // c'tor /** constructor, copies Bayesian network structure from a Bayesian network * encapsulated in a BIFReader */ public EditableBayesNet(BIFReader other) { m_Instances = other.m_Instances; m_ParentSets = other.getParentSets(); m_Distributions = other.getDistributions(); int nNodes = getNrOfNodes(); m_nPositionX = new FastVector(nNodes); m_nPositionY = new FastVector(nNodes); for (int i = 0; i < nNodes; i++) { m_nPositionX.addElement(other.m_nPositionX[i]); m_nPositionY.addElement(other.m_nPositionY[i]); } m_nEvidence = new FastVector(nNodes); for (int i = 0; i < nNodes; i++) { m_nEvidence.addElement(-1); } m_fMarginP = new FastVector(nNodes); for (int i = 0; i < nNodes; i++) { double[] P = new double[getCardinality(i)]; m_fMarginP.addElement(P); } clearUndoStack(); } // c'tor /** * constructor that potentially initializes instances as well * * @param bSetInstances * flag indicating whether to initialize instances or not */ public EditableBayesNet(boolean bSetInstances) { super(); m_nEvidence = new FastVector(0); m_fMarginP = new FastVector(0); m_nPositionX = new FastVector(); m_nPositionY = new FastVector(); clearUndoStack(); if (bSetInstances) { m_Instances = new Instances("New Network", new FastVector(0), 0); } } // c'tor /** Assuming a network structure is defined and we want to learn from data, * the data set must be put if correct order first and possibly discretized/missing * values filled in before proceeding to CPT learning. * @param instances data set to learn from * @exception when data sets are not compatible, e.g., a variable is missing * or a variable has different nr of values. */ public void setData(Instances instances) throws Exception { // sync order of variables int [] order = new int [getNrOfNodes()]; for (int iNode = 0; iNode < getNrOfNodes(); iNode++) { String sName = getNodeName(iNode); int nNode = 0; while (nNode < getNrOfNodes() && !sName.equals(instances.attribute(nNode).name())) { nNode++; } if (nNode >= getNrOfNodes()) { throw new Exception("Cannot find node named [[[" + sName + "]]] in the data"); } order[iNode] = nNode; } Reorder reorderFilter = new Reorder(); reorderFilter.setAttributeIndicesArray(order); reorderFilter.setInputFormat(instances); instances = Filter.useFilter(instances, reorderFilter); // filter using discretization/missing values filter Instances newInstances = new Instances(m_Instances, 0); if (m_DiscretizeFilter == null && m_MissingValuesFilter == null) { newInstances = normalizeDataSet(instances); } else { for (int iInstance = 0; iInstance < instances.numInstances(); iInstance++) { newInstances.add(normalizeInstance(instances.instance(iInstance))); } } //sanity check for (int iNode = 0; iNode < getNrOfNodes(); iNode++) { if (newInstances.attribute(iNode).numValues() != getCardinality(iNode)) { throw new Exception("Number of values of node [[[" + getNodeName(iNode) + "]]] differs in (discretized) dataset." ); } } // if we got this far, all is ok with the data set and // we can replace data set of Bayes net m_Instances = newInstances; } // setData /** returns index of node with given name, or -1 if no such node exists * @param sNodeName name of the node to get index for */ public int getNode2(String sNodeName) { int iNode = 0; while (iNode < m_Instances.numAttributes()) { if (m_Instances.attribute(iNode).name().equals(sNodeName)) { return iNode; } iNode++; } return -1; } // getNode2 /** returns index of node with given name. Throws exception if no such node exists * @param sNodeName name of the node to get index for */ public int getNode(String sNodeName) throws Exception { int iNode = getNode2(sNodeName); if (iNode < 0) { throw new Exception("Could not find node [[" + sNodeName + "]]"); } return iNode; } // getNode /** * Add new node to the network, initializing instances, parentsets, * distributions. Used for manual manipulation of the Bayesian network. * * @param sName * name of the node. If the name already exists, an x is appended * to the name * @param nCardinality * number of values for this node * @throws Exception */ public void addNode(String sName, int nCardinality) throws Exception { addNode(sName, nCardinality, 100 + getNrOfNodes() * 10, 100 + getNrOfNodes() * 10); } // addNode /** Add node to network at a given position, initializing instances, parentsets, * distributions. Used for manual manipulation of the Bayesian network. * * @param sName * name of the node. If the name already exists, an x is appended * to the name * @param nCardinality * number of values for this node * @param nPosX x-coordiate of the position to place this node * @param nPosY y-coordiate of the position to place this node * @throws Exception */ public void addNode(String sName, int nCardinality, int nPosX, int nPosY) throws Exception { if (getNode2(sName) >= 0) { addNode(sName + "x", nCardinality); return ; } // update instances FastVector values = new FastVector(nCardinality); for (int iValue = 0; iValue < nCardinality; iValue++) { values.addElement("Value" + (iValue + 1)); } Attribute att = new Attribute(sName, values); m_Instances.insertAttributeAt(att, m_Instances.numAttributes()); int nAtts = m_Instances.numAttributes(); // update parentsets ParentSet[] parentSets = new ParentSet[nAtts]; for (int iParentSet = 0; iParentSet < nAtts - 1; iParentSet++) { parentSets[iParentSet] = m_ParentSets[iParentSet]; } parentSets[nAtts - 1] = new ParentSet(); m_ParentSets = parentSets; // update distributions Estimator[][] distributions = new Estimator[nAtts][]; for (int iNode = 0; iNode < nAtts - 1; iNode++) { distributions[iNode] = m_Distributions[iNode]; } distributions[nAtts - 1] = new Estimator[1]; distributions[nAtts - 1][0] = new DiscreteEstimatorBayes(nCardinality, 0.5); m_Distributions = distributions; // update positions m_nPositionX.addElement(nPosX); m_nPositionY.addElement(nPosY); // update evidence & margins m_nEvidence.addElement(-1); double[] fMarginP = new double[nCardinality]; for (int iValue = 0; iValue < nCardinality; iValue++) { fMarginP[iValue] = 1.0 / nCardinality; } m_fMarginP.addElement(fMarginP); // update undo stack if (m_bNeedsUndoAction) { addUndoAction(new AddNodeAction(sName, nCardinality, nPosX, nPosY)); } } // addNode /** * Delete node from the network, updating instances, parentsets, * distributions Conditional distributions are condensed by taking the * values for the target node to be its first value. Used for manual * manipulation of the Bayesian network. * * @param sName * name of the node. If the name does not exists an exception is * thrown * @throws Exception */ public void deleteNode(String sName) throws Exception { int nTargetNode = getNode(sName); deleteNode(nTargetNode); } // deleteNode /** * Delete node from the network, updating instances, parentsets, * distributions Conditional distributions are condensed by taking the * values for the target node to be its first value. Used for manual * manipulation of the Bayesian network. * * @param nTargetNode * index of the node to delete. * @throws Exception */ public void deleteNode(int nTargetNode) throws Exception { // update undo stack if (m_bNeedsUndoAction) { addUndoAction(new DeleteNodeAction(nTargetNode)); } int nAtts = m_Instances.numAttributes() - 1; int nTargetCard = m_Instances.attribute(nTargetNode).numValues(); // update distributions Estimator[][] distributions = new Estimator[nAtts][]; for (int iNode = 0; iNode < nAtts; iNode++) { int iNode2 = iNode; if (iNode >= nTargetNode) { iNode2++; } Estimator[] distribution = m_Distributions[iNode2]; if (m_ParentSets[iNode2].contains(nTargetNode)) { // condense distribution, use values for targetnode = 0 int nParentCard = m_ParentSets[iNode2].getCardinalityOfParents(); nParentCard = nParentCard / nTargetCard; Estimator[] distribution2 = new Estimator[nParentCard]; for (int iParent = 0; iParent < nParentCard; iParent++) { distribution2[iParent] = distribution[iParent]; } distribution = distribution2; } distributions[iNode] = distribution; } m_Distributions = distributions; // update parentsets ParentSet[] parentSets = new ParentSet[nAtts]; for (int iParentSet = 0; iParentSet < nAtts; iParentSet++) { int iParentSet2 = iParentSet; if (iParentSet >= nTargetNode) { iParentSet2++; } ParentSet parentset = m_ParentSets[iParentSet2];
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?