Counter Factual explanations are a methdology to investigate model's predictions. whatifact allows data scientists to play with their population features, and find out how predictions are changed.
Specifically, it allows to ask "what-if" questions:
- What would the model predict if a record belonged to a man, instead of a woman?
- What would the model predict if my blood glucose levels were slightly higher, or lower?
It should be noted that this tool can help assess the causal questions of the model's prediction - but not the causal questions of the real world! Answer causal questions of the real worlds require unique design, rather than some UI tool...
In the most basic setting, whatifact only requries the data and a classifier. Everything will be selected automatically:
- Whether a feature is categorical or continuous
- Should missing values be allowed
- How to set-up the sliders for continuous features
You will notice that some sliders have a little checkbox on their left. Un-selecting this checkbox will disable the slider / make an empty selection in a drop-list widget, and will consider this feature to be a missing value.
from sklearn.datasets import fetch_openml
import lightgbm as lgb
from whatifact import whatifact
# Load Titanic dataset
titanic = fetch_openml("titanic", version=1, as_frame=True)
# Convert to DataFrame
df = titanic.data[['pclass', 'sex', 'age', 'sibsp', 'parch', 'fare', 'embarked']]
labels = titanic.target.astype(int)
# Train a LGBMClassifier
clf = lgb.LGBMClassifier(verbose=0).fit(df, labels)
# Running whatifact
app = whatifact(df=df, clf=clf)
# # Output: (Clicking on the http link will open whatifact in the browser)
# INFO: Started server process [42841]
# INFO: Waiting for application startup.
# INFO: Application startup complete.
# INFO: Uvicorn running on http://<LOCAL_IP>:8000 (Press CTRL+C to quit)
However, when running the code above, you will notice a strange behavior.
The sliders for both age
and fare
start at negative values, which is of cource non-sensical, the parch
variable has no missing-value checkbox next to it, and the sibsp
was considered as a continuous feature, but we'd rather handle it as categorical.
To change this behavior, we can send the feature_settings
parameter, such as:
feature_settings = {
'parch': {'null': True},
'age': {'min': 0},
'fare': {'min': 0},
'sibsp': {'type': 'categorical'}
}
app = whatifact(df=df, clf=clf, feature_settings=feature_settings)
This should solve the above behavior.
feature_settings
is a dictionary, with column names as keys and dicionaries as values.
All features may contain null
or type
keys.
null
: a boolearn (True/False) to state whether the feature can have null values.type
: 'continuous' or 'categorical' - manually defining the feature type.
Continuous features may also contain the min
, max
, step
, and decimals
keys. All other keys will be ignored.
The decimals
parameters is an integer defining the number of decimal digits for rounding purposes (default: 1).
The last two parameters in whatifact are sample_id
and run_application
.
sample_id
is the name of a column indf
, that will be used in the sample selector at the top of the app. If it remains None, the index column will be used as sample_id.run_application
is a boolean (True/False, defaults to True) that run the web service to run the shiny app. If changed to False, an App object will be returned, but not run, and running the app will requireshiny run my_file.py
whatifact currently works with binary prediction models only, and should support LogisticRegression, XGBoost, and LGBMClassifier.