{"id":36632511,"url":"https://github.com/sbobek/lux","last_synced_at":"2026-01-12T09:39:59.549Z","repository":{"id":45728730,"uuid":"331771718","full_name":"sbobek/lux","owner":"sbobek","description":"Local Universal Rule-based Explanations","archived":false,"fork":false,"pushed_at":"2025-12-17T09:20:20.000Z","size":320140,"stargazers_count":13,"open_issues_count":3,"forks_count":6,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-12-19T23:47:46.259Z","etag":null,"topics":["counterfactual-explanations","explainability","explainable-artificial-intelligence","interpretability","local-explanations","model-agnostic-explanations","rule-based-explanations"],"latest_commit_sha":null,"homepage":"https://lux-explainer.readthedocs.io","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/sbobek.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"docs/contributing.rst","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-01-21T22:28:05.000Z","updated_at":"2025-12-05T09:42:05.000Z","dependencies_parsed_at":"2023-02-15T15:16:40.620Z","dependency_job_id":"7755b187-263a-44aa-9108-c918d165aaad","html_url":"https://github.com/sbobek/lux","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/sbobek/lux","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbobek%2Flux","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbobek%2Flux/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbobek%2Flux/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbobek%2Flux/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sbobek","download_url":"https://codeload.github.com/sbobek/lux/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbobek%2Flux/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28337740,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T06:09:07.588Z","status":"ssl_error","status_checked_at":"2026-01-12T06:05:18.301Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["counterfactual-explanations","explainability","explainable-artificial-intelligence","interpretability","local-explanations","model-agnostic-explanations","rule-based-explanations"],"created_at":"2026-01-12T09:39:59.491Z","updated_at":"2026-01-12T09:39:59.545Z","avatar_url":"https://github.com/sbobek.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![PyPI](https://img.shields.io/pypi/v/lux-explainer)](https://pypi.org/project/lux-explainer/)  ![License](https://img.shields.io/github/license/sbobek/lux)\n ![PyPI - Downloads](https://img.shields.io/pypi/dm/lux-explainer) [![Documentation Status](https://readthedocs.org/projects/lux-explainer/badge/?version=latest)](https://tsproto.readthedocs.io/en/latest/?badge=latest)\n   \n# LUX (Local Universal Rule-based Explainer)\n\n## Main features\n  \u003cimg align=\"right\"  src=\"https://raw.githubusercontent.com/sbobek/lux/main/pix/lux-logo.png\" width=\"200\"\u003e\n  \n  * Model-agnostic, rule-based and visual local explanations of black-box ML models\n  * Integrated counterfactual explanations\n  * Rule-based explanations (that are executable at the same time)\n  * Oblique trees backbone, which allows to explain more reliable linear decision boundaries\n  * Integration with [Shapley values](https://shap.readthedocs.io/en/latest/) or [Lime](https://github.com/marcotcr/lime) importances (or any other explainer that produces importances) that help in generating high quality rules\n  * It outperforms state-of-the-art explainers (see: [LUX paper](https://arxiv.org/abs/2310.14894) for details )\n  \n## About\nThe workflow for LUX looks as follows:\n  - You train an arbitrary selected machine learning model on your train dataset. The only requirement is that the model is able to output probabilities.\n  \n  ![](https://raw.githubusercontent.com/sbobek/lux/main/pix/decbound-point.png)\n  - Next, you generate neighbourhood of an instance you wish to explain and you feed this neighbourhood to your model. \n  \n  ![](https://raw.githubusercontent.com/sbobek/lux/main/pix/neighbourhood.png)\n  - You obtain a decision stump, which locally explains the model and is executable by [HeaRTDroid](https://heartdroid.re) inference engine\n  \n  ![](https://raw.githubusercontent.com/sbobek/lux/main/pix/hmrp.png)\n  - You can obtain explanation for a selected instance (the number after # represents confidence of an explanation):\n  ```\n  ['IF x2  \u003c 0.01 AND  THEN class = 1 # 0.9229009792453621']\n  ```\n  - It obtained the highest scores for most of the popular metrics on 57 benchmark datasets from OpenML repository in comparison to state of the art algorithms such as LORE, Anchor, EXPLAN. The higher the area in the plot, the better.\n  ![]( https://raw.githubusercontent.com/sbobek/lux/main/pix/spiderplot.svg)\n\n## Installation\n\n\n```\npip install lux-explainer\n```\nIf you want to use LUX with [JupyterLab](https://jupyter.org/) install it and run:\n\n```\npip install jupyterlab\njupyter lab\n```\n\n**Caution**: If you want to use LUX with categorical data, it is advised to use [multiprocessing gower distance](https://github.com/sbobek/gower/tree/add-multiprocessing) package (due to high computational complexity of the problem). \n\n## Usage\n**Note**: Your output may differ from the example below, depending on the instance to explain that is selected, as LUX is local explainer.\n\n  * For online working example (basic usage), see [Colab basic usage example](https://colab.research.google.com/drive/123h5BdTfOK7adhe8nvvd7UPtNPBIuTgL?usp=sharing)\n  * For complete usage see [lux_usage_example.ipynb](https://github.com/sbobek/lux/blob/main/examples/lux_usage_example.ipynb)\n  * Fos usage example with Shap integration see [lux_usage_example_shap.ipynb](https://github.com/sbobek/lux/blob/main/examples/lux_usage_example_shap.ipynb)\n### Simple example on Iris dataset\n\n``` python\nfrom lux.lux import LUX\nfrom sklearn import datasets\nfrom sklearn.model_selection import train_test_split\nfrom sklearn import svm\nimport numpy as np\nimport pandas as pd\n# import some data to play with\niris = datasets.load_iris()\nfeatures = ['sepal_length','sepal_width','petal_length','petal_width']\ntarget = 'class'\n\n#create daatframe with columns names as strings (LUX accepts only DataFrames withj string columns names)\ndf_iris = pd.DataFrame(iris.data,columns=features)\ndf_iris[target] = iris.target\n\n#train classifier\ntrain, test = train_test_split(df_iris)\nclf = svm.SVC(probability=True)\nclf.fit(train[features],train[target])\nclf.score(test[features],test[target])\n\n#pick some instance from datasetr\niris_instance = train[features].sample(1).values\niris_instance\n\n#train lux on neighbourhood equal 20 instances\nlux = LUX(predict_proba = clf.predict_proba, neighborhood_size=20,max_depth=2,  node_size_limit = 1, grow_confidence_threshold = 0 )\nlux.fit(train[features], train[target], instance_to_explain=iris_instance,class_names=[0,1,2])\n\n#see the justification of the instance being classified for a given class\nlux.justify(np.array(iris_instance))\n\n```\n\nThe above code should give you the answer as follows:\n```\n['IF petal_length \u003e= 5.15 THEN class = 2 # 0.9833409059468439\\n']\n```\n\nAlternatively one can get counterfactual explanation for a given instance by calling:\n\n``` python\ncf = lux.counterfactual(np.array(iris_instance), train[features], counterfactual_representative='nearest', topn=1)[0]\nprint(f\"Counterfactual for {iris_instance} to change from class {lux.predict(np.array(iris_instance))[0]} to class {cf['prediction']}: \\n{cf['counterfactual']}\")\n```\nThe result from the above query should look as follows:\n\n```\nCounterfactual for [[7.7 2.6 6.9 2.3]] to change from class 2 to class 1: \nsepal_length    6.9\nsepal_width     3.1\npetal_length    5.1\npetal_width     2.3\n```\n\n### Rule-based model for local uncertain explanations\nYou can obtain a whole rule-based model for the local uncertain explanation that was generated by LUX for given instance by running following code\n\n``` python\n#have a look at the entire rule-based model that can be executed with https:://heartdroid.re\nprint(lux.to_HMR())\n```\n\nThis will generate model which can later be executed by [HeaRTDroid](https://heartdroid.re) which is rule-based inference engine for Android mobile devices.\nAdditionally, the HMR format below, which is used by  [HeaRTDroid](https://heartdroid.re) allows visualization of explanations in a format of decision tables with [HWEd](https://heartdroid.re/hwed/#/) online editor.\n\n\n```\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% TYPES DEFINITIONS %%%%%%%%%%%%%%%%%%%%%%%%%%\n\nxtype [\n name: petal_length, \nbase:numeric,\ndomain : [-100000 to 100000]].\nxtype [\n name: class, \nbase:symbolic,\n domain : [1,0,2]].\n\n%%%%%%%%%%%%%%%%%%%%%%%%% ATTRIBUTES DEFINITIONS %%%%%%%%%%%%%%%%%%%%%%%%%%\nxattr [ name: petal_length,\n type:petal_length,\n class:simple,\n comm:out ].\nxattr [ name: class,\n type:class,\n class:simple,\n comm:out ].\n\n%%%%%%%%%%%%%%%%%%%%%%%% TABLE SCHEMAS DEFINITIONS %%%%%%%%%%%%%%%%%%%%%%%%\n xschm tree : [petal_length]==\u003e [class].\nxrule tree/0:\n[petal_length  lt 3.05] ==\u003e [class set 0]. # 0.9579256691362875\nxrule tree/1:\n[petal_length  gte 3.05, petal_length  lt 5.15] ==\u003e [class set 1]. # 0.8398308552545226\nxrule tree/2:\n[petal_length  gte 3.05, petal_length  gte 5.15] ==\u003e [class set 2]. # 0.9833409059468439\n```\n### Visualization of the local uncertain explanation\nSimilarly you can obtain visualization of the rule-based model in a form of decision tree by executing following code. \n\n``` python\nimport graphviz\nfrom graphviz import Source\nfrom IPython.display import SVG, Image\nlux.uid3.tree.save_dot('tree.dot',fmt='.2f',visual=True, background_data=train)\ngvz=graphviz.Source.from_file('tree.dot')\n!dot -Tpng tree.dot \u003e tree.png\nImage('tree.png')\n```\n\nThe code should yield something like that (depending on the instance that was selected):\n\n![](https://raw.githubusercontent.com/sbobek/lux/main/pix/utree.png)\n\n# Cite this work\n\nThe software is the direct implementation of a method described in the following paper:\n\n```\n@misc{bobek2023local,\n      title={Local Universal Explainer ({LUX}) -- a rule-based explainer with factual, counterfactual and visual explanations}, \n      author={Szymon Bobek and Grzegorz J. Nalepa},\n      year={2023},\n      eprint={2310.14894},\n      archivePrefix={arXiv},\n      primaryClass={cs.AI}\n\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsbobek%2Flux","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsbobek%2Flux","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsbobek%2Flux/lists"}