Predicting Poker Hand Strength with MindsDB
Introduction
MindsDB is an open-source tool used for enabling machine learning capabilities in our database. With MindsDB we can train machine learning models and make directions in the database. Our goal in this tutorial is to predict the poker hand strength based on the suits and rank of all five cards.
Firstly, we need to set up a development environment. MindsDB offers a cloud version that is completely online and we can sign up here, or we could use it locally via Pip or Docker. In this tutorial, we will be using MIndsDB via the cloud.
Data Setup
Connecting the data as a file
For this tutorial, will be connecting to our database with a CSV file on the MindsDB cloud. You can download the csv data file here
on Google sheet (tutorial on how to do that here) and upload the poker-hand-training.csv
via MindsDB SQL Editor on the MindsDB cloud
Follow this guide to upload the file to MindsDB
Once you are done uploading, you can query the data directly with the;
SELECT * FROM files.poker_hand_strength
LIMIT 10;
Training a Predictor Model
With the above completed, we can now train our machine-learning predictor with SQL syntax.
Step 1: We will use the CREATE PREDICTOR
syntax to create the predictor where we will specify what subquery to train from FROM
and what it willPREDICT
.
CREATE PREDICTOR mindsdb.poker_hand_strength (Predictor's name)
FROM files (Database name)
(SELECT * FROM poker_hand_training) (table name)
PREDICT Poker Hand (Your Target Parameter)
Note: We used
LIMIT 10000
here as we are using the free version of MindsDB it supports up to 10K rows and will error out if we have more rows.
Step 2: We can check the status of the model with the syntax below. If the query returns Complete, then the model is ready to be used, or else wait if it returns Training.
SELECT status
FROM mindsdb.predictors
WHERE name='poker_hand_strength';
Our Dataset
Hand Ranking
The main goal of this article is to create a predictor to determine poker hand strength based on the suits and ranks of all five cards.
The Data Set
Each record in the dataset we are using in this article is an example of a hand consisting of five playing cards drawn from a standard deck of 52. Each card is described into two attributes (suit and rank), for a total of 10 predictive attributes. The target column describes the hand, with the possibilities being:
- “Suit of Card 1” Ordinal (1–4) representing {Hearts, Spades, Diamonds, Clubs}
- “Rank of Card 1” Numerical (1–13) representing (Ace, 2, 3, … , Queen, King)
- “Suit of Card 2” Ordinal (1–4) representing {Hearts, Spades, Diamonds, Clubs}
- “Rank of Card 2” Numerical (1–13) representing (Ace, 2, 3, … , Queen, King)
- “Suit of Card 3” Ordinal (1–4) representing {Hearts, Spades, Diamonds, Clubs}
- “Rank of Card 3” Numerical (1–13) representing (Ace, 2, 3, … , Queen, King)
- “Suit of Card 4” Ordinal (1–4) representing {Hearts, Spades, Diamonds, Clubs}
- “Rank of Card 4” Numerical (1–13) representing (Ace, 2, 3, … , Queen, King)
- “Suit of Card 5” Ordinal (1–4) representing {Hearts, Spades, Diamonds, Clubs}
- “Rank of Card 5” Numerical (1–13) representing (Ace, 2, 3, … , Queen, King)
- CLASS “Poker Hand” Ordinal (0–9) representing the following:
- 0: Nothing in hand; not a recognized poker hand
- 1: One pair; one pair of equal ranks within five cards
- 2: Two pairs; two pairs of equal ranks within five cards
- 3: Three of a kind; three equal ranks within five cards
- 4: Straight; five cards, sequentially ranked with no gaps
- 5: Flush; five cards with the same suit
- 6: Full house; pair + different rank three of a kind
- 7: Four of a kind; four equal ranks within five cards
- 8: Straight flush; straight + flush
- 9: Royal flush; {Ace, King, Queen, Jack, Ten} + flush
DESCRIBE
PREDICTOR STATEMENT
The DESCRIBE PREDICTOR
, this statement is used to display the attributes of an existing model. It can also help us gain some insights into the Predictor Model. To read more check out the MindsDB docs. We can find more details on the model in the following ways:
- By feature
- By Model
- By ensemble
By Features
DESCRIBE mindsdb.poker_hand_strength.features;
The expected output should be:
+---------------------+-------------+----------------+---------+
| column | type | encoder | role |
+---------------------+-------------+----------------+---------+
| Suit_of_Card_1 | categorical | OneHotEncoder | feature |
| Rank_of_Card_1 | integer | BinaryEncoder | feature |
| Suit_of_Card_2 | categorical | NumericEncoder | feature |
| Rank_of_Card_2 | integer | OneHotEncoder | feature |
| Suit_of_Card_3 | categorical | NumericEncoder | feature |
| Rank_of_Card_3 | integer | OneHotEncoder | feature |
| Suit_of_Card_4 | categorical | NumericEncoder | feature |
| Rank_of_Card_4 | integer | NumericEncoder | feature |
| Suit_of_Card_5 | categorical | OneHotEncoder | feature |
| Rank_of_Card_5 | integer | NumericEncoder | feature |
| Poker_Hand | integer | NumericEncoder | target |
+---------------------+-------------+----------------+---------+
Above the Poker_Hand
column is the target
column to be predicted. As for the feature
columns, these are used to train the ML model to predict the value of the Poker_Hand
column.
By Model
MindsDB uses several candidate models internally to train the data and then picks up the most optimized one for the model to make the predictions. The statement below simply lists out all the candidate models used to train the data along with other details such as performance, and accuracy functions. The model with 1
in its selected
the column is the one with the most optimized and accurate.
DESCRIBE PREDICTOR mindsdb.poker_hand_strength.model;
The output looks something like this:
By Ensemble
The command below lists out a JSON object that lists out multiple attributes used to determine the best candidate model to do the predictions finally.
DESCRIBE PREDICTOR mindsdb.poker_hand_strength.ensemble;
The output would look something like this:
{
"encoders": {
"Poker_Hand": {
"module": "NumericEncoder",
"args": {
"is_target": "True",
"positive_domain": "$statistical_analysis.positive_domain"
}
},
"Suit_of_Card_1": {
"module": "OneHotEncoder",
"args": {}
},
"Rank_of_Card_1": {
"module": "NumericEncoder",
"args": {}
},
"Suit_of_Card_2": {
"module": "OneHotEncoder",
"args": {}
},
"Rank_of_Card_2": {
"module": "NumericEncoder",
"args": {}
},
"Suit_of_Card_3": {
"module": "OneHotEncoder",
"args": {}
},
"Rank_of_Card_3": {
"module": "NumericEncoder",
"args": {}
},
"Suit_of_Card_4": {
"module": "OneHotEncoder",
"args": {}
},
"Rank_of_Card_4": {
"module": "NumericEncoder",
"args": {}
},
"Suit_of_Card_5": {
"module": "OneHotEncoder",
"args": {}
}
"Rank_of_Card_5": {
"module": "NumericEncoder",
"args": {}
}
},
"dtype_dict": {
"Suit_of_Card_1": "categorical",
"Rank_of_Card_1": "integer",
"Suit_of_Card_2": "categorical",
"Rank_of_Card_2": "integer",
"Suit_of_Card_3": "categorical",
"Rank_of_Card_3": "integer",
"Suit_of_Card_4": "categorical",
"Rank_of_Card_4": "integer",
"Suit_of_Card_5": "categorical",
"Rank_of_Card_5": "integer",
"Poker_Hand": "integer"
},
"dependency_dict": {},
"model": {
"module": "BestOf",
"args": {
"submodels": [
{
"module": "Neural",
"args": {
"fit_on_dev": true,
"stop_after": "$problem_definition.seconds_per_mixer",
"search_hyperparameters": true
}
},
{
"module": "LightGBM",
"args": {
"stop_after": "$problem_definition.seconds_per_mixer",
"fit_on_dev": true
}
},
{
"module": "Regression",
"args": {
"stop_after": "$problem_definition.seconds_per_mixer"
}
}
]
}
},
"problem_definition": {
"target": "Poker_Hand",
"pct_invalid": 2,
"unbias_target": true,
"seconds_per_mixer": 57024.0,
"seconds_per_encoder": null,
"expected_additional_time": 12.685770511627197,
"time_aim": 259200,
"target_weights": null,
"positive_domain": false,
"timeseries_settings": {
"is_timeseries": false,
"order_by": null,
"window": null,
"group_by": null,
"use_previous_target": true,
"horizon": null,
"historical_columns": null,
"target_type": "",
"allow_incomplete_history": true,
"eval_cold_start": true,
"interval_periods": []
},
"anomaly_detection": false,
"use_default_analysis": true,
"ignore_features": [],
"fit_on_all": true,
"strict_mode": true,
"seed_nr": 1
},
"identifiers": {},
"imputers": [],
"accuracy_functions": [
"r2_score"
]
}
Making Predictions
Now that we have our Prediction Model, we can simply execute some simple SQL query statements to predict the target value based on the feature parameters.
Making a Single Prediction
You can make predictions by querying the predictor as if it were a table. The SELECT
statement lets you make predictions for the Poker Hand Strength
on the chosen feature parameter.
SELECT Poker_Hand, Poker_Hand_explain
FROM mindsdb.poker_hand_strength
WHERE Suit_of_Card_1 = 1
AND Rank_of_Card_1= 10
AND Suit_of_Card_2 = 1
AND Rank_of_Card_2 = 11
AND Suit_of_Card_3 = 1
AND Rank_of_Card_3 = 13
AND Suit_of_Card_4 = 1
AND Rank_of_Card_4 = 12
AND Suit_of_Card_5 = 1
AND Rank_of_Card_5 = 1;
Our output would be ;
Making a Bulk Prediction
Now let’s make bulk predictions or multiple predictions to predict the Poker_Hand_Strength
by joining our table with the model.
SELECT t.Suit_of_Card_1 AS S1, t.Rank_of_Card_1 AS C1, t.Suit_of_Card_2 AS S2,
t.Rank_of_Card_2 AS C2, t.Suit_of_Card_3, t.Rank_of_Card_3, t.Suit_of_Card_4, t.Rank_of_Card_4, t.Suit_of_Card_5 AS S5, t.Rank_of_Card_5 AS C5, m.Poker_Hand AS Poker_Hand
FROM files.poker AS t
JOIN mindsdb.poker AS m
LIMIT 5;
The expected output would be
Conclusion
In this tutorial, we created our own Mindsdb Cloud, uploaded a dataset to the interface, train a predictor model, and also predicted the poker_hand_strength based on the Rank and Suits of all 5 cards.
Have fun while trying it out yourself!
- Star the MindsDB repository on GitHub.
- Sign up for a free MindsDB account
- Engage with the MindsDB community on Slack or GitHub to ask questions and share your ideas and thoughts.
Give a like or a comment if this tutorial was helpful