Repository: pgmpy/pgmpy

Issue:
Reading a XML BIF with isolated nodes
The XMLBIFReader class doesn't allow to return the model from a BIF XML file where there are isolated nodes. 

I can create the XMLBIFReader:
`bif = pgmpy.readwrite.XMLBIF.XMLBIFReader('diabetes.xml')`

but when trying to return the model:
`bif_model = bif.get_model()`

It returns an exception because is trying to load the CPD of the isolated node, but this node is not included in the BayesianModel:
 `ValueError: ('CPD defined on variable not in the model', <TabularCPD representing P(skin:1) at 0x7f669d905c10>)` arises.


Reviewing the  `XMLBIFReader.get_model()`, we can see that the Bayesian model is created from the edges: 

`model = BayesianModel(self.get_edges())`

As an isolated node has no edge by definition, I think that the BayesianModel can't know that an isolated node exists when adding the cpds to the BayesianModel.

I provide the following XML BIF as a MWE. It is a XML BIF learnt using WEKA BayesNet class.
[diabetes.zip](https://github.com/pgmpy/pgmpy/files/1449591/diabetes.zip)

I think that even when an isolated node is not the most useful thing to do, it is a nuisance that we can't load the rest of the network.

Execution environment.
pgmpy: 0.1.3
Python: 2.7
OS: Ubuntu 16.04



Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/pgmpy/pgmpy/pull/937?src=pr&el=h1) Report
> Merging [#937](https://codecov.io/gh/pgmpy/pgmpy/pull/937?src=pr&el=desc) into [dev](https://codecov.io/gh/pgmpy/pgmpy/commit/110b4c1e8ef8c24da83931d87298b96c196c9462?src=pr&el=desc) will **decrease** coverage by `<.01%`.
> The diff coverage is `80%`.

[![Impacted file tree graph](https://codecov.io/gh/pgmpy/pgmpy/pull/937/graphs/tree.svg?token=UaJMCdHaEF&src=pr&height=150&width=650)](https://codecov.io/gh/pgmpy/pgmpy/pull/937?src=pr&el=tree)

```diff
@@            Coverage Diff            @@
##              dev    #937      +/-   ##
=========================================
- Coverage   94.71%   94.7%   -0.01%     
=========================================
  Files         114     114              
  Lines       11176   11185       +9     
=========================================
+ Hits        10585   10593       +8     
- Misses        591     592       +1
```


| [Impacted Files](https://codecov.io/gh/pgmpy/pgmpy/pull/937?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pgmpy/tests/test\_readwrite/test\_ProbModelXML.py](https://codecov.io/gh/pgmpy/pgmpy/pull/937?src=pr&el=tree#diff-cGdtcHkvdGVzdHMvdGVzdF9yZWFkd3JpdGUvdGVzdF9Qcm9iTW9kZWxYTUwucHk=) | `94.95% <ø> (ø)` | :arrow_up: |
| [pgmpy/readwrite/UAI.py](https://codecov.io/gh/pgmpy/pgmpy/pull/937?src=pr&el=tree#diff-cGdtcHkvcmVhZHdyaXRlL1VBSS5weQ==) | `86.4% <0%> (-0.85%)` | :arrow_down: |
| [pgmpy/readwrite/XMLBeliefNetwork.py](https://codecov.io/gh/pgmpy/pgmpy/pull/937?src=pr&el=tree#diff-cGdtcHkvcmVhZHdyaXRlL1hNTEJlbGllZk5ldHdvcmsucHk=) | `92.53% <100%> (+0.11%)` | :arrow_up: |
| [pgmpy/readwrite/ProbModelXML.py](https://codecov.io/gh/pgmpy/pgmpy/pull/937?src=pr&el=tree#diff-cGdtcHkvcmVhZHdyaXRlL1Byb2JNb2RlbFhNTC5weQ==) | `85.68% <100%> (+0.06%)` | :arrow_up: |
| [pgmpy/readwrite/XMLBIF.py](https://codecov.io/gh/pgmpy/pgmpy/pull/937?src=pr&el=tree#diff-cGdtcHkvcmVhZHdyaXRlL1hNTEJJRi5weQ==) | `97.53% <100%> (+0.03%)` | :arrow_up: |
| [pgmpy/readwrite/BIF.py](https://codecov.io/gh/pgmpy/pgmpy/pull/937?src=pr&el=tree#diff-cGdtcHkvcmVhZHdyaXRlL0JJRi5weQ==) | `93.68% <100%> (+0.03%)` | :arrow_up: |
| [pgmpy/models/BayesianModel.py](https://codecov.io/gh/pgmpy/pgmpy/pull/937?src=pr&el=tree#diff-cGdtcHkvbW9kZWxzL0JheWVzaWFuTW9kZWwucHk=) | `95.47% <0%> (+0.41%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pgmpy/pgmpy/pull/937?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pgmpy/pgmpy/pull/937?src=pr&el=footer). Last update [110b4c1...36592af](https://codecov.io/gh/pgmpy/pgmpy/pull/937?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/pgmpy/readwrite/BIF.py b/pgmpy/readwrite/BIF.py
index fac86ab9..98c11d39 100644
--- a/pgmpy/readwrite/BIF.py
+++ b/pgmpy/readwrite/BIF.py
@@ -284,9 +284,10 @@ class BIFReader(object):
         <pgmpy.models.BayesianModel.BayesianModel object at 0x7f20af154320>
         """
         try:
-            model = BayesianModel(self.variable_edges)
-            model.name = self.network_name
+            model = BayesianModel()
             model.add_nodes_from(self.variable_names)
+            model.add_edges_from(self.variable_edges)
+            model.name = self.network_name
 
             tabular_cpds = []
             for var in sorted(self.variable_cpds.keys()):
diff --git a/pgmpy/readwrite/ProbModelXML.py b/pgmpy/readwrite/ProbModelXML.py
index 67908769..b2499ca3 100644
--- a/pgmpy/readwrite/ProbModelXML.py
+++ b/pgmpy/readwrite/ProbModelXML.py
@@ -1030,7 +1030,9 @@ class ProbModelXMLReader(object):
         >>> reader.get_model()
         """
         if self.probnet.get('type') == "BayesianNetwork":
-            model = BayesianModel(self.probnet['edges'].keys())
+            model = BayesianModel()
+            model.add_nodes_from(self.probnet['Variables'].keys())
+            model.add_edges_from(self.probnet['edges'].keys())
 
             tabular_cpds = []
             cpds = self.probnet['Potentials']
@@ -1051,7 +1053,6 @@ class ProbModelXMLReader(object):
             for var in variables:
                 for prop_name, prop_value in self.probnet['Variables'][var].items():
                     model.node[var][prop_name] = prop_value
-
             edges = model.edges()
             for edge in edges:
                 for prop_name, prop_value in self.probnet['edges'][edge].items():
diff --git a/pgmpy/readwrite/UAI.py b/pgmpy/readwrite/UAI.py
index f47598da..ebf86516 100644
--- a/pgmpy/readwrite/UAI.py
+++ b/pgmpy/readwrite/UAI.py
@@ -218,7 +218,9 @@ class UAIReader(object):
         >>> reader.get_model()
         """
         if self.network_type == 'BAYES':
-            model = BayesianModel(self.edges)
+            model = BayesianModel()
+            model.add_nodes_from(self.variables)
+            model.add_edges_from(self.edges)
 
             tabular_cpds = []
             for cpd in self.tables:
diff --git a/pgmpy/readwrite/XMLBIF.py b/pgmpy/readwrite/XMLBIF.py
index a301f3e3..826c6a7c 100644
--- a/pgmpy/readwrite/XMLBIF.py
+++ b/pgmpy/readwrite/XMLBIF.py
@@ -177,7 +177,9 @@ class XMLBIFReader(object):
         return variable_property
 
     def get_model(self):
-        model = BayesianModel(self.get_edges())
+        model = BayesianModel()
+        model.add_nodes_from(self.variables)
+        model.add_edges_from(self.edge_list)
         model.name = self.network_name
 
         tabular_cpds = []
diff --git a/pgmpy/readwrite/XMLBeliefNetwork.py b/pgmpy/readwrite/XMLBeliefNetwork.py
index e28d495a..9328542e 100644
--- a/pgmpy/readwrite/XMLBeliefNetwork.py
+++ b/pgmpy/readwrite/XMLBeliefNetwork.py
@@ -186,7 +186,9 @@ class XBNReader(object):
         """
         Returns an instance of Bayesian Model.
         """
-        model = BayesianModel(self.edges)
+        model = BayesianModel()
+        model.add_nodes_from(self.variables)
+        model.add_edges_from(self.edges)
         model.name = self.model_name
 
         tabular_cpds = []


Test patch:
diff --git a/pgmpy/tests/test_readwrite/test_ProbModelXML.py b/pgmpy/tests/test_readwrite/test_ProbModelXML.py
index 806e41e3..aa4141e3 100644
--- a/pgmpy/tests/test_readwrite/test_ProbModelXML.py
+++ b/pgmpy/tests/test_readwrite/test_ProbModelXML.py
@@ -547,43 +547,51 @@ class TestProbModelXMLReaderString(unittest.TestCase):
                                     'role': 'chance',
                                     'type': 'finiteStates',
                                     'Coordinates': {'y': '52', 'x': '568'},
-                                    'AdditionalProperties': {'Title': 'S', 'Relevance': '7.0'}},
+                                    'AdditionalProperties': {'Title': 'S', 'Relevance': '7.0'},
+                                    'weight': None},
                          'Bronchitis': {'States': {'no': {}, 'yes': {}},
                                         'role': 'chance',
                                         'type': 'finiteStates',
                                         'Coordinates': {'y': '181', 'x': '698'},
-                                        'AdditionalProperties': {'Title': 'B', 'Relevance': '7.0'}},
+                                        'AdditionalProperties': {'Title': 'B', 'Relevance': '7.0'},
+                                        'weight': None},
                          'VisitToAsia': {'States': {'no': {}, 'yes': {}},
                                          'role': 'chance',
                                          'type': 'finiteStates',
                                          'Coordinates': {'y': '58', 'x': '290'},
-                                         'AdditionalProperties': {'Title': 'A', 'Relevance': '7.0'}},
+                                         'AdditionalProperties': {'Title': 'A', 'Relevance': '7.0'},
+                                         'weight': None},
                          'Tuberculosis': {'States': {'no': {}, 'yes': {}},
                                           'role': 'chance',
                                           'type': 'finiteStates',
                                           'Coordinates': {'y': '150', 'x': '201'},
-                                          'AdditionalProperties': {'Title': 'T', 'Relevance': '7.0'}},
+                                          'AdditionalProperties': {'Title': 'T', 'Relevance': '7.0'},
+                                          'weight': None},
                          'X-ray': {'States': {'no': {}, 'yes': {}},
                                    'role': 'chance',
                                    'AdditionalProperties': {'Title': 'X', 'Relevance': '7.0'},
                                    'Coordinates': {'y': '322', 'x': '252'},
                                    'Comment': 'Indica si el test de rayos X ha sido positivo',
-                                   'type': 'finiteStates'},
+                                   'type': 'finiteStates',
+                                   'weight': None},
                          'Dyspnea': {'States': {'no': {}, 'yes': {}},
                                      'role': 'chance',
                                      'type': 'finiteStates',
                                      'Coordinates': {'y': '321', 'x': '533'},
-                                     'AdditionalProperties': {'Title': 'D', 'Relevance': '7.0'}},
+                                     'AdditionalProperties': {'Title': 'D', 'Relevance': '7.0'},
+                                     'weight': None},
                          'TuberculosisOrCancer': {'States': {'no': {}, 'yes': {}},
                                                   'role': 'chance',
                                                   'type': 'finiteStates',
                                                   'Coordinates': {'y': '238', 'x': '336'},
-                                                  'AdditionalProperties': {'Title': 'E', 'Relevance': '7.0'}},
+                                                  'AdditionalProperties': {'Title': 'E', 'Relevance': '7.0'},
+                                                  'weight': None},
                          'LungCancer': {'States': {'no': {}, 'yes': {}},
                                         'role': 'chance',
                                         'type': 'finiteStates',
                                         'Coordinates': {'y': '152', 'x': '421'},
-                                        'AdditionalProperties': {'Title': 'L', 'Relevance': '7.0'}}}
+                                        'AdditionalProperties': {'Title': 'L', 'Relevance': '7.0'},
+                                        'weight': None}}
         edge_expected = {'LungCancer': {'TuberculosisOrCancer': {'weight': None,
                                                                  'directed': 'true'}},
                          'Smoker': {'LungCancer': {'weight': None,