UFCData 0.6.0__tar.gz → 0.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ufcdata-0.6.0 → ufcdata-0.7.0}/PKG-INFO +2 -1
- {ufcdata-0.6.0 → ufcdata-0.7.0}/README.md +109 -11
- {ufcdata-0.6.0 → ufcdata-0.7.0}/UFCData.egg-info/PKG-INFO +2 -1
- {ufcdata-0.6.0 → ufcdata-0.7.0}/UFCData.egg-info/requires.txt +1 -0
- {ufcdata-0.6.0 → ufcdata-0.7.0}/pyproject.toml +2 -1
- {ufcdata-0.6.0 → ufcdata-0.7.0}/ufcdata/__init__.py +1 -1
- {ufcdata-0.6.0 → ufcdata-0.7.0}/ufcdata/evaluation.py +73 -1
- {ufcdata-0.6.0 → ufcdata-0.7.0}/LICENSE.md +0 -0
- {ufcdata-0.6.0 → ufcdata-0.7.0}/UFCData.egg-info/SOURCES.txt +0 -0
- {ufcdata-0.6.0 → ufcdata-0.7.0}/UFCData.egg-info/dependency_links.txt +0 -0
- {ufcdata-0.6.0 → ufcdata-0.7.0}/UFCData.egg-info/top_level.txt +0 -0
- {ufcdata-0.6.0 → ufcdata-0.7.0}/setup.cfg +0 -0
- {ufcdata-0.6.0 → ufcdata-0.7.0}/ufcdata/data.py +0 -0
- {ufcdata-0.6.0 → ufcdata-0.7.0}/ufcdata/fighter.py +0 -0
- {ufcdata-0.6.0 → ufcdata-0.7.0}/ufcdata/helper.py +0 -0
- {ufcdata-0.6.0 → ufcdata-0.7.0}/ufcdata/ratings.py +0 -0
- {ufcdata-0.6.0 → ufcdata-0.7.0}/ufcdata/search.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: UFCData
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Obtain UFC data and functions to manipulate it
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
License-File: LICENSE.md
|
|
@@ -9,4 +9,5 @@ Requires-Dist: pandas
|
|
|
9
9
|
Requires-Dist: numpy
|
|
10
10
|
Requires-Dist: glicko2
|
|
11
11
|
Requires-Dist: rapidfuzz
|
|
12
|
+
Requires-Dist: matplotlib
|
|
12
13
|
Dynamic: license-file
|
|
@@ -4,8 +4,6 @@ An open-source Python package for accessing, manipulating, and analyzing UFC dat
|
|
|
4
4
|
|
|
5
5
|
https://pypi.org/project/UFCData/
|
|
6
6
|
|
|
7
|
-
add helper functions like convert odds
|
|
8
|
-
|
|
9
7
|
## Table of Contents
|
|
10
8
|
|
|
11
9
|
- [Installation](#installation)
|
|
@@ -29,7 +27,11 @@ Helper Functions
|
|
|
29
27
|
- [Mirror](#mirror)
|
|
30
28
|
|
|
31
29
|
Model Evaluation
|
|
32
|
-
- [
|
|
30
|
+
- [Train Test Split](#train-test-split)
|
|
31
|
+
- [Get Expanding Window](#get-expanding-window)
|
|
32
|
+
- [Plotting Accuracy](#plotting-accuracy)
|
|
33
|
+
- [Expanding Window Baseline Example](#expanding-window-cv-and-final-test-example)
|
|
34
|
+
|
|
33
35
|
|
|
34
36
|
Data Sources
|
|
35
37
|
- [Online Sources](#online-sources)
|
|
@@ -100,7 +102,7 @@ This is useful when the exact value stored in the dataset is unknown or when the
|
|
|
100
102
|
|
|
101
103
|
## Elo
|
|
102
104
|
|
|
103
|
-
UFCData provides an Elo rating system for calculating fighter ratings based on their previous fight results. Ratings are calculated chronologically, with each fighter's rating recorded
|
|
105
|
+
UFCData provides an Elo rating system for calculating fighter ratings based on their previous fight results. Ratings are calculated chronologically, with each fighter's rating recorded immediately before each fight.
|
|
104
106
|
|
|
105
107
|
This allows Elo ratings to be used as features for predictive modeling without incorporating information from the fight being predicted.
|
|
106
108
|
|
|
@@ -146,7 +148,7 @@ The resulting `fight_elo` dataframe can then be used to examine or incorporate p
|
|
|
146
148
|
|
|
147
149
|
### Important
|
|
148
150
|
|
|
149
|
-
`fight_df` should be sorted from
|
|
151
|
+
`fight_df` should be sorted from most recent to least recent before being passed to `get_elo()`. The function reverses the dataframe internally to process fights chronologically and returns the resulting data in the original order.
|
|
150
152
|
|
|
151
153
|
## Fighter History
|
|
152
154
|
|
|
@@ -181,14 +183,12 @@ data = ufc.get_data()
|
|
|
181
183
|
fighter_bio = data["fighter_bio"].copy()
|
|
182
184
|
fights_df = data["past_fights"].copy()
|
|
183
185
|
|
|
184
|
-
# Obtain Jon Jones' UFCStats link
|
|
185
186
|
jon_jones = ufc.search(
|
|
186
187
|
fighter_bio,
|
|
187
188
|
"Name",
|
|
188
189
|
"Jon Jones"
|
|
189
190
|
).iloc[0]["Fighter Link"]
|
|
190
191
|
|
|
191
|
-
# Get Jon Jones' fight history
|
|
192
192
|
jon_jones_history = ufc.get_fighter_history(
|
|
193
193
|
jon_jones,
|
|
194
194
|
fighter_bio,
|
|
@@ -201,7 +201,7 @@ This function is useful for analyzing an individual fighter's career, constructi
|
|
|
201
201
|
## Fighter Statistic
|
|
202
202
|
|
|
203
203
|
|
|
204
|
-
The function `get_fighter_statistic()`, transforms a fighter's UFC fight history into a time-series dataset where each row represents the fighter's statistics
|
|
204
|
+
The function `get_fighter_statistic()`, transforms a fighter's UFC fight history into a time-series dataset where each row represents the fighter's statistics as they were known before a particular fight.
|
|
205
205
|
|
|
206
206
|
This is designed for machine-learning applications where using information from the future would cause data leakage.
|
|
207
207
|
|
|
@@ -265,7 +265,7 @@ This includes:
|
|
|
265
265
|
|
|
266
266
|
A DataFrame containing the same types of statistics for each previous UFC fight.
|
|
267
267
|
|
|
268
|
-
Each row represents the fighter's information
|
|
268
|
+
Each row represents the fighter's information immediately before that fight.
|
|
269
269
|
|
|
270
270
|
For example:
|
|
271
271
|
|
|
@@ -291,14 +291,12 @@ fights_df = data["past_fights"].copy()
|
|
|
291
291
|
rounds_df = data['past_rounds'].copy()
|
|
292
292
|
future_df = data['future_fights']
|
|
293
293
|
|
|
294
|
-
# Obtain Jon Jones' UFCStats link
|
|
295
294
|
jon_jones = ufc.search(
|
|
296
295
|
fighter_bio,
|
|
297
296
|
"Name",
|
|
298
297
|
"Jon Jones"
|
|
299
298
|
).iloc[0]["Fighter Link"]
|
|
300
299
|
|
|
301
|
-
# Get Jon Jones' statistic
|
|
302
300
|
jon_jones_current, jon_jones_past = ufc.get_fighter_statistic(
|
|
303
301
|
jon_jones,
|
|
304
302
|
fighter_bio,
|
|
@@ -496,6 +494,106 @@ Mirrored Fight 2
|
|
|
496
494
|
|
|
497
495
|
This is useful when creating fighter-level datasets where each fight should be represented from both fighters' perspectives.
|
|
498
496
|
|
|
497
|
+
## Train Test Split
|
|
498
|
+
The function `train_test_split()` splits a UFC fight DataFrame into training and test sets while preserving the chronological order of the data. Unlike `sklearn.model_selection.train_test_split()`, this function does not randomly shuffle the data.
|
|
499
|
+
|
|
500
|
+
The input `fights_df` should be ordered from newest to oldest. The most recent fights are assigned to the test set, while the older fights are assigned to the training set. Both returned DataFrames are then reordered from oldest to newest.
|
|
501
|
+
|
|
502
|
+
```python
|
|
503
|
+
train_test_split(fights_df, test_size=0.2)
|
|
504
|
+
```
|
|
505
|
+
### Parameters
|
|
506
|
+
|
|
507
|
+
* `fights_df` — UFC fight DataFrame ordered from newest to oldest.
|
|
508
|
+
* `test_size` — Determines the size of the test set. If less than 1, it is interpreted as a proportion of the total number of fights. If greater than or equal to 1, it is interpreted as the exact number of fights to include in the test set. Defaults to 0.2.
|
|
509
|
+
### Returns
|
|
510
|
+
The function returns two dataFrames. The first is a dataFrame containing the older fights used for training, ordered from oldest to newest. The second is a dataFrame containing the most recent fights used for testing, ordered from oldest to newest.
|
|
511
|
+
|
|
512
|
+
### Example
|
|
513
|
+
|
|
514
|
+
```python
|
|
515
|
+
import ufcdata as ufc
|
|
516
|
+
|
|
517
|
+
data = ufc.get_data()
|
|
518
|
+
|
|
519
|
+
past_fights = data["past_fights"].copy()
|
|
520
|
+
train, test = ufc.train_test_split(past_fights, 0.2)
|
|
521
|
+
train
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
## Get Expanding Window
|
|
525
|
+
The function `get_expanding_window()` creates multiple training and test sets for time-series cross-validation using an expanding training window.
|
|
526
|
+
|
|
527
|
+
The input `fights_df` should be ordered from oldest to newest. With each fold, the training set expands to include more historical fights, while the test set remains a fixed size.
|
|
528
|
+
|
|
529
|
+
```python
|
|
530
|
+
fold_results = ufc.get_expanding_window(
|
|
531
|
+
fights_df,
|
|
532
|
+
folds=5,
|
|
533
|
+
test_size=500
|
|
534
|
+
)
|
|
535
|
+
```
|
|
536
|
+
### Parameters
|
|
537
|
+
|
|
538
|
+
* `fights_df` — UFC fight DataFrame ordered from oldest to newest.
|
|
539
|
+
* `folds` — The number of train/test folds to create.
|
|
540
|
+
* `test_size` — The number of fights included in each test set.
|
|
541
|
+
|
|
542
|
+
### Returns
|
|
543
|
+
The function returns a dictionary containing the training and test DataFrames for each fold.
|
|
544
|
+
```python
|
|
545
|
+
{
|
|
546
|
+
"Fold 1": {
|
|
547
|
+
"train": train_dataframe,
|
|
548
|
+
"test": test_dataframe
|
|
549
|
+
},
|
|
550
|
+
"Fold 2": {
|
|
551
|
+
"train": train_dataframe,
|
|
552
|
+
"test": test_dataframe
|
|
553
|
+
},
|
|
554
|
+
...
|
|
555
|
+
}
|
|
556
|
+
```
|
|
557
|
+
### Example
|
|
558
|
+
|
|
559
|
+
```python
|
|
560
|
+
import ufcdata as ufc
|
|
561
|
+
|
|
562
|
+
data = ufc.get_data()
|
|
563
|
+
|
|
564
|
+
past_fights = data["past_fights"].copy()
|
|
565
|
+
train, test = ufc.train_test_split(past_fights, 0.2)
|
|
566
|
+
|
|
567
|
+
folds = ufc.get_expanding_window(train, 10, 500)
|
|
568
|
+
folds['Fold 2']['test']
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
## Plotting Accuracy
|
|
572
|
+
|
|
573
|
+
The function `plot_cv` plots out a line graph showing the accuracy of each fold along with a line showing the mean.
|
|
574
|
+
|
|
575
|
+
```python
|
|
576
|
+
plot_cv(cv_labels, cv_accuracies, title="Cross Validation Accuracy")
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
### Parameters
|
|
580
|
+
|
|
581
|
+
* `cv_labels` — The list of fold names.
|
|
582
|
+
* `cv_accuracies` — The list of accuracies.
|
|
583
|
+
* `title` — The title of the plot.
|
|
584
|
+
|
|
585
|
+
The function `plot_test` plots out a single bar graph showing the accuracy of a single test.
|
|
586
|
+
|
|
587
|
+
```python
|
|
588
|
+
plot_test(accuracy, title="Test Accuracy")
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
### Parameters
|
|
592
|
+
|
|
593
|
+
* `accuracy` — The accuracy.
|
|
594
|
+
* `title` — The title of the plot.
|
|
595
|
+
|
|
596
|
+
## Expanding Window Baseline Example
|
|
499
597
|
|
|
500
598
|
## Online Sources
|
|
501
599
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: UFCData
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Obtain UFC data and functions to manipulate it
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
License-File: LICENSE.md
|
|
@@ -9,4 +9,5 @@ Requires-Dist: pandas
|
|
|
9
9
|
Requires-Dist: numpy
|
|
10
10
|
Requires-Dist: glicko2
|
|
11
11
|
Requires-Dist: rapidfuzz
|
|
12
|
+
Requires-Dist: matplotlib
|
|
12
13
|
Dynamic: license-file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "UFCData"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.7.0"
|
|
4
4
|
description = "Obtain UFC data and functions to manipulate it"
|
|
5
5
|
requires-python = ">=3.10"
|
|
6
6
|
|
|
@@ -10,4 +10,5 @@ dependencies = [
|
|
|
10
10
|
"numpy",
|
|
11
11
|
"glicko2",
|
|
12
12
|
"rapidfuzz",
|
|
13
|
+
"matplotlib",
|
|
13
14
|
]
|
|
@@ -3,4 +3,4 @@ from .search import search
|
|
|
3
3
|
from .ratings import get_elo
|
|
4
4
|
from .fighter import get_fighter_history, get_fighter_statistic
|
|
5
5
|
from .helper import convert_odds, convert_gender, convert_weight, mirror
|
|
6
|
-
from .evaluation import train_test_split, get_expanding_window
|
|
6
|
+
from .evaluation import train_test_split, get_expanding_window, plot_cv, plot_test
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import numpy as np
|
|
2
|
+
import matplotlib.pyplot as plt
|
|
2
3
|
|
|
3
4
|
def train_test_split(fights_df, test_size=0.2):
|
|
4
5
|
"""
|
|
@@ -117,4 +118,75 @@ def get_expanding_window(fights_df, folds, test_size):
|
|
|
117
118
|
"test": test
|
|
118
119
|
}
|
|
119
120
|
|
|
120
|
-
return fold_results
|
|
121
|
+
return fold_results
|
|
122
|
+
|
|
123
|
+
def plot_cv(cv_labels, cv_accuracies, title="Cross Validation Accuracy"):
|
|
124
|
+
plt.figure(figsize=(10, 5))
|
|
125
|
+
|
|
126
|
+
plt.plot(
|
|
127
|
+
cv_labels,
|
|
128
|
+
cv_accuracies,
|
|
129
|
+
color="#666666",
|
|
130
|
+
linestyle="-",
|
|
131
|
+
linewidth=2,
|
|
132
|
+
marker="o",
|
|
133
|
+
markersize=7,
|
|
134
|
+
markerfacecolor="#D20A0A", # UFC red dots
|
|
135
|
+
markeredgecolor="#FFFFFF",
|
|
136
|
+
markeredgewidth=1.5,
|
|
137
|
+
label="Fold Accuracy"
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
# Mean accuracy across folds
|
|
142
|
+
mean_accuracy = np.mean(cv_accuracies)
|
|
143
|
+
|
|
144
|
+
plt.axhline(
|
|
145
|
+
mean_accuracy,
|
|
146
|
+
color="#D20A0A",
|
|
147
|
+
linestyle="--",
|
|
148
|
+
linewidth=2,
|
|
149
|
+
label=f"Mean Accuracy: {mean_accuracy:.1%}"
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
plt.xlabel("Fold")
|
|
154
|
+
plt.ylabel("Accuracy")
|
|
155
|
+
plt.title(title)
|
|
156
|
+
# plt.ylim(0, 1)
|
|
157
|
+
|
|
158
|
+
plt.xticks(rotation=45)
|
|
159
|
+
plt.grid(True, alpha=0.3)
|
|
160
|
+
plt.legend()
|
|
161
|
+
|
|
162
|
+
plt.tight_layout()
|
|
163
|
+
plt.show()
|
|
164
|
+
|
|
165
|
+
def plot_test(accuracy, title="Test Accuracy"):
|
|
166
|
+
plt.figure(figsize=(6, 5))
|
|
167
|
+
|
|
168
|
+
plt.bar(
|
|
169
|
+
0,
|
|
170
|
+
accuracy,
|
|
171
|
+
color="#D20A0A",
|
|
172
|
+
width=0.25
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
plt.ylabel("Accuracy")
|
|
176
|
+
plt.title(title)
|
|
177
|
+
plt.ylim(0, 1)
|
|
178
|
+
|
|
179
|
+
plt.xlim(-0.5, 0.5)
|
|
180
|
+
plt.xticks([0], ["Test Set"])
|
|
181
|
+
|
|
182
|
+
plt.text(
|
|
183
|
+
0,
|
|
184
|
+
accuracy + 0.02,
|
|
185
|
+
f"{accuracy:.1%}",
|
|
186
|
+
ha="center",
|
|
187
|
+
fontweight="bold",
|
|
188
|
+
color="#444444"
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
plt.tight_layout()
|
|
192
|
+
plt.show()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|