{"id":21906089,"url":"https://github.com/yakuza8/bayesian-inference","last_synced_at":"2025-10-25T13:42:42.158Z","repository":{"id":57414229,"uuid":"268592403","full_name":"yakuza8/bayesian-inference","owner":"yakuza8","description":"Bayesian Inference","archived":false,"fork":false,"pushed_at":"2020-08-23T09:04:53.000Z","size":107,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-29T02:51:31.824Z","etag":null,"topics":["bayesian-inference","bayesian-network","bayesian-statistics","exact-inference","joint-probability","posterior-probability","prior-probability","probability","probability-parser"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yakuza8.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-06-01T17:49:58.000Z","updated_at":"2022-02-02T02:15:45.000Z","dependencies_parsed_at":"2022-08-26T20:13:19.886Z","dependency_job_id":null,"html_url":"https://github.com/yakuza8/bayesian-inference","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yakuza8%2Fbayesian-inference","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yakuza8%2Fbayesian-inference/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yakuza8%2Fbayesian-inference/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yakuza8%2Fbayesian-inference/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yakuza8","download_url":"https://codeload.github.com/yakuza8/bayesian-inference/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248618280,"owners_count":21134202,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bayesian-inference","bayesian-network","bayesian-statistics","exact-inference","joint-probability","posterior-probability","prior-probability","probability","probability-parser"],"created_at":"2024-11-28T16:40:40.993Z","updated_at":"2025-10-25T13:42:42.090Z","avatar_url":"https://github.com/yakuza8.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Bayesian Inference\n[![Build Status](https://travis-ci.com/yakuza8/bayesian-inference.svg?branch=master)](https://travis-ci.com/yakuza8/bayesian-inference)\n[![codecov](https://codecov.io/gh/yakuza8/bayesian-inference/branch/master/graph/badge.svg)](https://codecov.io/gh/yakuza8/bayesian-inference)\n\n## Project Description\nProbabilistic reasoning module on `Bayesian Networks` where the dependencies between variables are\nrepresented as links among nodes on the `directed acyclic graph`. Even we could infer any probability\nin the knowledge world via full joint distribution, we can optimize this calculation by independence\nand conditional independence. \n\nIn current implementation, one can define properties of the network as follows:\n* Each node represents a single random variable\n* Links between nodes represent direct effect on each other such as if `random variable X` has link\nto `random variable Y`, then there is a conditional probability relation between them. \n* There is no cycle in the network and that makes the network `Directed Acyclic Graph`\n\n### Entities\nUsable entities available in the project are listed below which are `NetworkNode` and `BayesianNetwork`.\nThere is a simple network configuration as dictionary format below and entities will be explained with\nrespect to example network.\n\n```python\n\u003e\u003e\u003e from bayesian_inference import BayesianNetwork, InputParser\n\u003e\u003e\u003e\n\u003e\u003e\u003e BURGLARY = \"Burglary\"\n\u003e\u003e\u003e EARTHQUAKE = \"Earthquake\"\n\u003e\u003e\u003e ALARM = \"Alarm\"\n\u003e\u003e\u003e JOHN_CALLS = \"JohnCalls\"\n\u003e\u003e\u003e MARRY_CALLS = \"MaryCalls\"\n\u003e\u003e\u003e \n\u003e\u003e\u003e sample_network = {\n...     BURGLARY: {\n...         \"predecessors\": [], \"random_variables\": [\"t\", \"f\"], \"probabilities\": {\n...             \"(t)\": 0.001, \"(f)\": 0.999\n...         }\n...     }, EARTHQUAKE: {\n...         \"predecessors\": [], \"random_variables\": [\"t\", \"f\"], \"probabilities\": {\n...             \"(t)\": 0.002, \"(f)\": 0.998\n...         }\n...     }, ALARM: {\n...         \"predecessors\": [BURGLARY, EARTHQUAKE], \"random_variables\": [\"t\", \"f\"], \"probabilities\": {\n...             \"(f,f,f)\": 0.999, \"(f,f,t)\": 0.001, \"(f,t,f)\": 0.71, \"(f,t,t)\": 0.29, \"(t,f,f)\": 0.06,\n...             \"(t,f,t)\": 0.94, \"(t,t,f)\": 0.05, \"(t,t,t)\": 0.95\n...         }\n...     }, JOHN_CALLS: {\n...         \"predecessors\": [ALARM], \"random_variables\": [\"t\", \"f\"], \"probabilities\": {\n...             \"(f,f)\": 0.95, \"(f,t)\": 0.05, \"(t,f)\": 0.10, \"(t,t)\": 0.90\n...         }\n...     }, MARRY_CALLS: {\n...         \"predecessors\": [ALARM], \"random_variables\": [\"t\", \"f\"], \"probabilities\": {\n...             \"(f,f)\": 0.99, \"(f,t)\": 0.01, \"(t,f)\": 0.30, \"(t,t)\": 0.70\n...         }\n...     }\n... }\n\u003e\u003e\u003e network = BayesianNetwork(initial_network=InputParser.from_dict(sample_network))\n```\n\n#### Network Node\nSingle unit in the network representing a random variable in the uncertain world.\nIt has the following fields expected by constructor:\n* node_name: Random variable name which will be the node name in the network\n* random_variables: List of available values of random variable in string format\n* predecessors: Parents of the random variable in the network as a list of string where each item\nis the name of parent random variable\n* probabilities: Probability list of the random variable described as conditional probabilities\n* all_random_variables: List of lists of strings representing random variable values respectively\nparents of the node and the values of current node\n\nSingle node can be represented with the following representation:\n\n```python\n\u003e\u003e\u003e from bayesian_inference import NetworkNode\n\u003e\u003e\u003e node = eval(NetworkNode('Alarm', ['t', 'f'], ['Burglary', 'Earthquake'], {'(f,f,f)': 0.999, '(f,f,t)': 0.001, '(f,t,f)': 0.71, '(f,t,t)': 0.29, '(t,f,f)': 0.06, '(t,f,t)': 0.94, '(t,t,f)': 0.05, '(t,t,t)': 0.95}, [['t', 'f'], ['t', 'f'], ['t', 'f']]))\n\u003e\u003e\u003e print(node)\n| Burglary   | Earthquake   |   P(Alarm=t) |   P(Alarm=f) |\n|------------|--------------|--------------|--------------|\n| t          | t            |        0.95  |        0.05  |\n| t          | f            |        0.94  |        0.06  |\n| f          | t            |        0.29  |        0.71  |\n| f          | f            |        0.001 |        0.999 |\n```\n\n**Note:** It is important that you need to provide probability dictionary of `NetworkNode` as explained\nin the following example. Let's have node named `X` and parents as `[A, B, C]`, then you need to have all\nprobability keys as `(value_a,value_b,value_c,value_x)` where no whitespace between commas and value are\nlisted order of parents and node itself if you want to create node from yourself.\nIf you parse with `InputParser`, then it goes over keys and removes whitespaces to make them as expected format. \n\n#### Bayesian Network\nBayesian network structure that keeps `Directed Acyclic Graph` inside and encapsulates `NetworkNode` instances\nThe structure has an instance of [NetworkX](https://github.com/networkx/networkx) DiGraph. Network can be created\nwith initial node list. Also, one can add and remove node to the network at runtime. From probability perspective,\none can query exact inference of probability from Bayesian network. Also, one can control independence property of\nnodes in the graph with `is_independent` method of `BayesianNetwork`. `D-separation principle` is applied for\ndeciding whether the nodes are independent or not where additionally one can provide evidence variable list for\nchecking the independence property while verification of conditional independence. \n\n```python\n\u003e\u003e\u003e # Network initiated above\n\u003e\u003e\u003e from bayesian_inference import NetworkNode\n\u003e\u003e\u003e node1 = NetworkNode(node_name='B', predecessors=['A'], random_variables=[], probabilities={}, all_random_variables=[])\n\u003e\u003e\u003e node2 = NetworkNode(node_name='C', predecessors=['B'], random_variables=[], probabilities={}, all_random_variables=[])\n\u003e\u003e\u003e \n\u003e\u003e\u003e # Adding node to network, Method expects network node directly\n\u003e\u003e\u003e network.add_node(node1)\n\u003e\u003e\u003e network.add_node(node2)\n\u003e\u003e\u003e \n\u003e\u003e\u003e # Removal of node from network. Method expects node name to remove\n\u003e\u003e\u003e network.remove_node(node2.node_name)\n\u003e\u003e\u003e\n\u003e\u003e\u003e # Query exact inference from network, details of queries will be explained in next sections\n\u003e\u003e\u003e network.P('Burglary | JohnCalls = t, MaryCalls = t')\n{\"{'Burglary': 't'}\": 0.28417183536439294, \"{'Burglary': 'f'}\": 0.7158281646356072}\n\u003e\u003e\u003e network.P('JohnCalls = t, MaryCalls = t, Alarm = t,  Burglary = f, Earthquake = f')\n0.0006281112599999999\n\u003e\u003e\u003e \n\u003e\u003e\u003e # Independence check\n\u003e\u003e\u003e network.is_independent('JohnCalls', 'MaryCalls')\n\u003e\u003e\u003e False\n\u003e\u003e\u003e network.is_independent('JohnCalls', 'MaryCalls', evidence_variables=['Alarm'])\n\u003e\u003e\u003e True\n```\n\n### Expected form of probabilistic query\nThere is a query parser module under `probability` package that makes query for Bayesian network that\ncan be conditional or full joint probability. The form/structure of query should be following regex.\nOne can reach visual representation of regex from [this link](https://regexper.com/#%28%3F%3A%28%5Cs*%5Cw%2B%5Cs*%29%28%3F%3A%3D%28%5Cs*%5Cw%2B%5Cs*%29%29%3F%29%28%3F%3A%2C%28%3F%3A%28%5Cs*%5Cw%2B%5Cs*%29%28%3F%3A%3D%28%5Cs*%5Cw%2B%5Cs*%29%29%3F%29%29*%28%3F%3A%5Cs*%5C%7C%5Cs*%28%3F%3A%28%5Cs*%5Cw%2B%5Cs*%29%3D%28%5Cs*%5Cw%2B%5Cs*%29%29%28%3F%3A%2C%28%3F%3A%28%5Cs*%5Cw%2B%5Cs*%29%3D%28%5Cs*%5Cw%2B%5Cs*%29%29%29*%29%3F).\n\n```python\n\u003e\u003e\u003e WORD = r'(\\s*\\w+\\s*)'\n\u003e\u003e\u003e NON_VALUED_GROUP = rf'(?:{WORD}(?:={WORD})?)'\n\u003e\u003e\u003e VALUED_GROUP = rf'(?:{WORD}={WORD})'\n\u003e\u003e\u003e QUERY_VARIABLES = rf'{NON_VALUED_GROUP}(?:,{NON_VALUED_GROUP})*'\n\u003e\u003e\u003e EVIDENCE_VARIABLES = rf'{VALUED_GROUP}(?:,{VALUED_GROUP})*'\n\u003e\u003e\u003e QUERY = rf'{QUERY_VARIABLES}(?:\\s*\\|\\s*{EVIDENCE_VARIABLES})?'\n\u003e\u003e\u003e QUERY\n'(?:(\\s*\\w+\\s*)(?:=(\\s*\\w+\\s*))?)(?:,(?:(\\s*\\w+\\s*)(?:=(\\s*\\w+\\s*))?))*(?:\\s*\\|\\s*(?:(\\s*\\w+\\s*)=(\\s*\\w+\\s*))(?:,(?:(\\s*\\w+\\s*)=(\\s*\\w+\\s*)))*)?'\n```\n\n#### Textual meaning of query format is\n* There should be at least one `Valued` or `Non-valued` query parameter.\n    * Valued: Alarm=True\n    * Non-valued: Alarm (No value assigned)\n* There can be conditional/posterior probability section after `|` (pipe) symbol optionally.\n* All the valued and non-valued should be separated by `,` (comma) symbol.\n\n#### Examples\n```python\nfrom bayesian_inference import query_parser\n\u003e\u003e\u003e # Valid queries\n\u003e\u003e\u003e query_parser('A, B, C')[0]\nTrue\n\u003e\u003e\u003e query_parser('A, B=b, C')[0]\nTrue\n\u003e\u003e\u003e query_parser('A=1, B, C')[0]\nTrue\n\u003e\u003e\u003e query_parser('A, B, C=2')[0]\nTrue\n\u003e\u003e\u003e query_parser('A=1, B=2, C=3')[0]\nTrue\n\u003e\u003e\u003e query_parser('A, B, C | D=d')[0]\nTrue\n\u003e\u003e\u003e query_parser('A=1, B=2, C=2 | D=d')[0]\nTrue\n\u003e\u003e\u003e query_parser('A, B=2, C | D=d, E=5')[0]\nTrue\n\u003e\u003e\u003e # Invalid queries (It is expected that all evidence variables should have value)\n\u003e\u003e\u003e query_parser('A, B, C | D')[0]\nFalse\n\u003e\u003e\u003e query_parser('A, B=b, C | D')[0]\nFalse\n\u003e\u003e\u003e query_parser('A=1, B, C | D')[0]\nFalse\n```\n\n#### Validations\n1. Variable uniqueness validation: No repeated random variable should exist in the query. \n2. **[Optional]** Contextual name/value validation: If `expected_symbol_and_values` parameter is provided,\n`query_parser` checks names of parsed random variables and validates their values if parsed variable has\nvalue.\n\n### Input Format and Parsing\nThe input format will be explained nearby how you can import them into code. You can directly parse\njson file to get list of `NetworkNode` where keys are node/random variable name and values is an\nobject of expected values to create node instance.\n\nExpected fields are:\n* predecessors: List of names of parents of the node where they will be search in the json\n* random_variables: Values for the random variable that are list of string \n* probabilities: Probabilities of the node explained under `NetworkNode` section.\n\nOne can obtain list of nodes by reading json from file with `parse` method of `InputParser` or \nreading dict and map them to network node with `from_dict` method of `InputParser`. The same\nexpectations are hold here defined for json format.\n\n**Note:** Necessary validations are done for parsing nodes so that if there is an unexpected\nvalue for input by raising corresponding exception.\n\n#### Example Input Format\n```json\n{\n    \"Burglary\": {\n        \"predecessors\": [],\n        \"random_variables\": [\n            \"t\",\n            \"f\"\n        ],\n        \"probabilities\": {\n            \"(t)\": 0.001,\n            \"(f)\": 0.999\n        }\n    },\n    \"Earthquake\": {\n        \"predecessors\": [],\n        \"random_variables\": [\n            \"t\",\n            \"f\"\n        ],\n        \"probabilities\": {\n            \"(t)\": 0.002,\n            \"(f)\": 0.998\n        }\n    },\n    \"Alarm\": {\n        \"predecessors\": [\n            \"Burglary\",\n            \"Earthquake\"\n        ],\n        \"random_variables\": [\n            \"t\",\n            \"f\"\n        ],\n        \"probabilities\": {\n            \"(f,f,f)\": 0.999,\n            \"(f,f,t)\": 0.001,\n            \"(f,t,f)\": 0.71,\n            \"(f,t,t)\": 0.29,\n            \"(t,f,f)\": 0.06,\n            \"(t,f,t)\": 0.94,\n            \"(t,t,f)\": 0.05,\n            \"(t,t,t)\": 0.95\n        }\n    },\n    \"JohnCalls\": {\n        \"predecessors\": [\n            \"Alarm\"\n        ],\n        \"random_variables\": [\n            \"t\",\n            \"f\"\n        ],\n        \"probabilities\": {\n            \"(f,f)\": 0.95,\n            \"(f,t)\": 0.05,\n            \"(t,f)\": 0.1,\n            \"(t,t)\": 0.9\n        }\n    },\n    \"MaryCalls\": {\n        \"predecessors\": [\n            \"Alarm\"\n        ],\n        \"random_variables\": [\n            \"t\",\n            \"f\"\n        ],\n        \"probabilities\": {\n            \"(f,f)\": 0.99,\n            \"(f,t)\": 0.01,\n            \"(t,f)\": 0.3,\n            \"(t,t)\": 0.7\n        }\n    }\n}\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyakuza8%2Fbayesian-inference","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyakuza8%2Fbayesian-inference","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyakuza8%2Fbayesian-inference/lists"}