UFCData 0.1.2__tar.gz → 0.2.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: UFCData
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: Obtain UFC data and functions to manipulate it
5
5
  Requires-Python: >=3.10
6
6
  License-File: LICENSE.md
@@ -8,4 +8,5 @@ Requires-Dist: huggingface-hub
8
8
  Requires-Dist: pandas
9
9
  Requires-Dist: numpy
10
10
  Requires-Dist: glicko2
11
+ Requires-Dist: rapidfuzz
11
12
  Dynamic: license-file
@@ -0,0 +1,173 @@
1
+ # UFCData
2
+
3
+ An open-source Python package for accessing, manipulating, and analyzing UFC data.
4
+
5
+ https://pypi.org/project/UFCData/
6
+
7
+ add helper functions like convert odds
8
+
9
+ ## Table of Contents
10
+
11
+ - [Installation](#installation)
12
+
13
+ Accessing Data
14
+ - [Loading Data](#loading-data)
15
+ - [Search](#search)
16
+
17
+ Rating Functions
18
+ - [Elo](#elo)
19
+ - [Glicko-2](#glicko-2)
20
+
21
+ Fighter Functions
22
+ - [Fighter Record](#elo)
23
+ - [Fighter Statistic](#elo)
24
+
25
+ Model Evaluation
26
+ - [Odds Baseline Example](#elo)
27
+
28
+ Helper Functions
29
+ - [Odds Convert](#elo)
30
+ - [Weight Convert](#elo)
31
+ - [Gender Convert](#elo)
32
+ - [Mirror](#elo)
33
+
34
+ Data Sources
35
+ - [Online Sources](#online-sources)
36
+ - [Discrepancies in Data](#discrepancies-in-data)
37
+ - [Update Frequency](#update-frequency)
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ pip install ufcdata
43
+ ```
44
+
45
+ ## Loading Data
46
+
47
+ ```python
48
+ import ufcdata as ufc
49
+ data = ufc.get_data()
50
+
51
+ ## Obtain fighter_bio dataframe
52
+ fighter_bio = data["fighter_bio"].copy()
53
+
54
+ ```
55
+
56
+ Note that data in here and other functions below reference data that is available prior to the data.
57
+
58
+ ## Search
59
+
60
+ Due to various event naming conventions and fighters sharing the same name, the primary keys for the dataframes are links, which can be difficult for humans to interpret. The `search()` function uses fuzzy string matching to make it easier to find fighters, events, and other records.
61
+
62
+ ```python
63
+ search(data, column, query, matches=1)
64
+ ```
65
+
66
+ ### Parameters
67
+
68
+ * `data` — The dataframe you are searching.
69
+ * `column` — The name of the column to search.
70
+ * `query` — The name or text you are searching for.
71
+ * `matches` — The number of closest matches to return. Defaults to `1`.
72
+
73
+ ### Example
74
+
75
+ ```python
76
+ john_jones = ufc.search(fighter_bio, "Name", "Jon Jones", 3)
77
+ ```
78
+
79
+ This searches the `"Name"` column of the `fighter_bio` dataframe for the three closest matches to `"Jon Jones"`.
80
+
81
+ The results are returned as a dataframe, with the closest match appearing first.
82
+
83
+ Output:
84
+
85
+ ```text
86
+ Name Nickname Height Weight Reach Stance Total W Total L Fighter Link
87
+ Jon Jones Bones 76.0 248.0 84.0 Orthodox 28 1 ufcstats.com/...
88
+ Roshaun Jones NaN 68.0 135.0 NaN NaN 2 6 ufcstats.com/...
89
+ Mason Jones The Dragon 70.0 155.0 74.0 Orthodox 18 2 ufcstats.com/...
90
+ ```
91
+
92
+ This is useful when the exact value stored in the dataset is unknown or when there are multiple similar names. The same function can be used with any dataframe and column containing searchable text.
93
+
94
+
95
+ ## Elo
96
+
97
+ 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**.
98
+
99
+ This allows Elo ratings to be used as features for predictive modeling without incorporating information from the fight being predicted.
100
+
101
+
102
+ ```python
103
+ ufc.get_elo(fight_df, fighter_df, r=1500, k=30, s=400)
104
+ ```
105
+
106
+ ### Parameters
107
+
108
+ * `fight_df` — The UFC fight dataframe, sorted from most recent to least recent.
109
+ * `fighter_df` — The fighter information dataframe containing a `"Fighter Link"` column.
110
+ * `r` — Initial Elo rating for each fighter. Defaults to `1500`.
111
+ * `k` — K-factor controlling how much ratings change after each fight. Defaults to `30`.
112
+ * `s` — Scaling factor used when calculating expected scores. Defaults to `400`.
113
+
114
+ ### Returns
115
+
116
+ The function returns a tuple containing:
117
+
118
+ 1. `fighter_elo` — A dictionary mapping each fighter's UFCStats link to their final Elo rating.
119
+ 2. `elo` — A dataframe containing fight-level Elo ratings. `"Fighter 1 Elo"` and `"Fighter 2 Elo"` represent each fighter's rating immediately before the corresponding fight.
120
+
121
+ ### Example
122
+
123
+ ```python
124
+ import ufcdata as ufc
125
+
126
+ data = ufc.get_data()
127
+
128
+ fight_df = data["past_fights"].copy()
129
+ fighter_df = data["fighter_bio"].copy()
130
+
131
+ fighter_elo, fight_elo = ufc.get_elo(
132
+ fight_df,
133
+ fighter_df
134
+ )
135
+ ```
136
+
137
+ The resulting `fight_elo` dataframe can then be used to examine or incorporate pre-fight Elo ratings into analysis and predictive models.
138
+
139
+
140
+ ### Important
141
+
142
+ `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.
143
+
144
+
145
+ ## Glicko-2
146
+ Glicko-2 extends the Elo system by incorporating rating deviation (RD) and volatility. Unlike Elo, which represents a fighter's ability with a single rating, Glicko-2 also estimates the uncertainty and consistency of that rating.
147
+
148
+ fighter_glicko, fight_glicko = ufc.glicko_2(
149
+ fight_df,
150
+ fighter_df
151
+ )
152
+
153
+ ## Online Sources
154
+
155
+ Odds and birthplace data was obtained from https://www.tapology.com
156
+
157
+ Venue and attendance data was obtained from https://en.wikipedia.org/wiki/List_of_UFC_events
158
+
159
+ All other data was obtained from http://ufcstats.com
160
+
161
+ ## Discrepancies in Data
162
+
163
+ UFCStats is treated as the authoritative source for UFCData. When discrepancies exist between UFCStats and other sources, such as Wikipedia or Tapology, the UFCStats data is used.
164
+
165
+ The UFCStats completed events page serves as the authoritative source for event, fight, and round data. Individual fighter profiles may contain fights from organizations or events that are not included in the completed events database, including WEC, Strikeforce, and PRIDE. These events are therefore excluded from UFCData.
166
+
167
+ ## Update Frequency
168
+
169
+ The dataset is updated at the start of the scheduled broadcast time for each event. This update captures changes to betting odds, as well as any cancelled, postponed, or otherwise modified fights.
170
+
171
+ A second update occurs 24 hours after the start of the broadcast. This update captures the finalized event, fight, and round data, as well as information on upcoming events and fights.
172
+
173
+ Changes occurring between these scheduled updates are not automatically captured. Users are responsible for manually updating the dataset if they require the most current data for analysis or prediction.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: UFCData
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: Obtain UFC data and functions to manipulate it
5
5
  Requires-Python: >=3.10
6
6
  License-File: LICENSE.md
@@ -8,4 +8,5 @@ Requires-Dist: huggingface-hub
8
8
  Requires-Dist: pandas
9
9
  Requires-Dist: numpy
10
10
  Requires-Dist: glicko2
11
+ Requires-Dist: rapidfuzz
11
12
  Dynamic: license-file
@@ -8,6 +8,8 @@ UFCData.egg-info/requires.txt
8
8
  UFCData.egg-info/top_level.txt
9
9
  ufcdata/__init__.py
10
10
  ufcdata/data.py
11
+ ufcdata/ratings.py
12
+ ufcdata/search.py
11
13
  ufcdata.egg-info/PKG-INFO
12
14
  ufcdata.egg-info/SOURCES.txt
13
15
  ufcdata.egg-info/dependency_links.txt
@@ -2,3 +2,4 @@ huggingface-hub
2
2
  pandas
3
3
  numpy
4
4
  glicko2
5
+ rapidfuzz
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "UFCData"
3
- version = "0.1.2"
3
+ version = "0.2.0"
4
4
  description = "Obtain UFC data and functions to manipulate it"
5
5
  requires-python = ">=3.10"
6
6
 
@@ -9,4 +9,5 @@ dependencies = [
9
9
  "pandas",
10
10
  "numpy",
11
11
  "glicko2",
12
+ "rapidfuzz",
12
13
  ]
@@ -0,0 +1,3 @@
1
+ from .data import get_data
2
+ from .search import search
3
+ from .ratings import get_elo
@@ -3,6 +3,20 @@ import pickle
3
3
  import logging
4
4
 
5
5
  def get_data():
6
+ """
7
+ Obtains all UFC related data
8
+
9
+ Returns
10
+ dict
11
+ Dictionary containing UFC data as pandas DataFrames.
12
+ Individual DataFrames can be accessed using their
13
+ corresponding dictionary keys.
14
+
15
+ Examples
16
+ --------
17
+ >>> data = get_data()
18
+ >>> past_events = data["past_events"].copy()
19
+ """
6
20
 
7
21
  logging.getLogger("huggingface_hub").setLevel(logging.ERROR)
8
22
 
@@ -0,0 +1,130 @@
1
+ import pandas as pd
2
+ from glicko2 import Player
3
+
4
+ #@title Elo function
5
+ def expected_score(rating, opponent_rating, s):
6
+ return (1)/(1 + 10**((opponent_rating - rating)/(s)))
7
+
8
+ #Rating update
9
+ def update_rating(rating, k, outcome, expected):
10
+ return rating + k*(outcome - expected)
11
+
12
+ # Elo function
13
+ # Make sure fights are sorted from most recent to least recent. Gets Elo prior to fight.
14
+ def get_elo(fight_df, fighter_df, r=1500, k=30, s=400):
15
+ """
16
+ Calculates pre-fight Elo ratings for UFC fighters.
17
+
18
+ Fights are processed chronologically from oldest to newest, with
19
+ each fighter's Elo rating recorded immediately before each fight.
20
+ Fighter ratings are initialized to `r` and updated after each fight
21
+ using the specified K-factor and Elo scale.
22
+
23
+ Parameters
24
+ ----------
25
+ fight_df : pandas.DataFrame
26
+ UFC fight data sorted from most recent to least recent.
27
+ Must contain fighter links, fight outcomes, and the fight
28
+ information required to construct the output.
29
+ fighter_df : pandas.DataFrame
30
+ DataFrame containing fighter information. Must contain a
31
+ "Fighter Link" column used to identify each fighter.
32
+ r : float, default=1500
33
+ Initial Elo rating assigned to each fighter.
34
+ k : float, default=30
35
+ K-factor controlling the magnitude of Elo rating changes
36
+ after each fight.
37
+ s : float, default=400
38
+ Elo scaling factor used when calculating expected scores.
39
+
40
+ Returns
41
+ -------
42
+ current_elo : dict
43
+ Dictionary mapping each fighter's link to their current Elo rating
44
+ after processing all fights.
45
+
46
+ past_elo : pandas.DataFrame
47
+ Fight-level DataFrame containing the original fight information
48
+ and the Elo rating of each fighter immediately before the fight.
49
+
50
+ Notes
51
+ -----
52
+ The input fight data should be sorted from most recent to least
53
+ recent. The function reverses this order internally to process
54
+ fights chronologically, then returns the resulting data in the
55
+ original order.
56
+
57
+ Examples
58
+ --------
59
+ >>> fighter_elo, fight_elo = get_elo(fight_df, fighter_df)
60
+ >>> fight_elo[["Fighter 1", "Fighter 1 Elo",
61
+ ... "Fighter 2", "Fighter 2 Elo"]].head()
62
+ """
63
+
64
+ fight_df = fight_df[::-1]
65
+
66
+ original_fight_df = fight_df.copy()
67
+
68
+ fighter_1_elo = []
69
+ fighter_2_elo = []
70
+
71
+ ## Create a dictionary of fighters and their Elo
72
+ fighter_df = fighter_df.copy()
73
+ fighter_df["Elo"] = r
74
+ fighter_df = dict(zip(fighter_df["Fighter Link"], fighter_df["Elo"]))
75
+
76
+ ## Create a list of fights
77
+ fight_df = fight_df[["Fighter 1 Link", "Fighter 1 Outcome", "Fighter 2 Link", "Fighter 2 Outcome"]]
78
+ fight_df = fight_df.values.tolist()
79
+
80
+
81
+ ## Loop through each fight in order
82
+ for fight in fight_df:
83
+ ## Get fighters Elo from fighter_df
84
+ elo_1 = fighter_df[fight[0]]
85
+ elo_2 = fighter_df[fight[2]]
86
+ ## Add to final list
87
+ fighter_1_elo.append(elo_1)
88
+ fighter_2_elo.append(elo_2)
89
+ ## Update Elo
90
+ if (fight[1] == "W") and ((fight[3] == "L")):
91
+ expected_1 = expected_score(elo_1, elo_2, s)
92
+ elo_1_new = update_rating(elo_1, k, 1, expected_1)
93
+ expected_2 = expected_score(elo_2, elo_1, s)
94
+ elo_2_new = update_rating(elo_2, k, 0, expected_2)
95
+ fighter_df[fight[0]] = elo_1_new
96
+ fighter_df[fight[2]] = elo_2_new
97
+ elif (fight[1] == "L") and (fight[3] == "W"):
98
+ expected_1 = expected_score(elo_1, elo_2, s)
99
+ elo_1_new = update_rating(elo_1, k, 0, expected_1)
100
+ expected_2 = expected_score(elo_2, elo_1, s)
101
+ elo_2_new = update_rating(elo_2, k, 1, expected_2)
102
+ fighter_df[fight[0]] = elo_1_new
103
+ fighter_df[fight[2]] = elo_2_new
104
+ elif (fight[1] == "D") and (fight[3] == "D"):
105
+ expected_1 = expected_score(elo_1, elo_2, s)
106
+ elo_1_new = update_rating(elo_1, k, 0.5, expected_1)
107
+ expected_2 = expected_score(elo_2, elo_1, s)
108
+ elo_2_new = update_rating(elo_2, k, 0.5, expected_2)
109
+ fighter_df[fight[0]] = elo_1_new
110
+ fighter_df[fight[2]] = elo_2_new
111
+
112
+
113
+ elo_1 = pd.DataFrame(fighter_1_elo, columns=["Fighter 1 Elo"])
114
+ elo_2 = pd.DataFrame(fighter_2_elo, columns=["Fighter 2 Elo"])
115
+ elo = pd.concat(
116
+ [
117
+ original_fight_df.reset_index(drop=True),
118
+ elo_1.reset_index(drop=True),
119
+ elo_2.reset_index(drop=True)
120
+ ],
121
+ axis=1
122
+ )
123
+ elo = elo[['Date', 'Event Link', 'Fight Number', 'Fight Link', 'Weight Class',
124
+ 'Gender', 'Title', 'Fighter 1', 'Fighter 1 Elo', 'Fighter 1 Odds', 'Fighter 1 Link',
125
+ 'Fighter 1 Outcome', 'Fighter 1 Bonus', 'Fighter 2','Fighter 2 Elo', 'Fighter 2 Odds',
126
+ 'Fighter 2 Link', 'Fighter 2 Outcome', 'Fighter 2 Bonus', 'Method',
127
+ 'Round', 'Time', 'Time Format', 'Referee', 'Details']]
128
+ past_elo = elo[::-1].copy()
129
+ current_elo = fighter_df
130
+ return (current_elo, past_elo)
@@ -0,0 +1,39 @@
1
+ from rapidfuzz.fuzz import ratio
2
+
3
+ def search(data, column , query, matches=1):
4
+ """
5
+ Searches a UFC DataFrame for rows matching a query.
6
+
7
+ Uses fuzzy string matching to identify the rows in the specified
8
+ column that most closely match the query.
9
+
10
+ Parameters
11
+ ----------
12
+ data : pandas.DataFrame
13
+ UFC DataFrame to search.
14
+ column : str
15
+ Name of the column to search.
16
+ query : str
17
+ Search query to match against the specified column.
18
+ matches : int, default=1
19
+ Number of closest matches to return.
20
+
21
+ Returns
22
+ -------
23
+ pandas.DataFrame
24
+ DataFrame containing the closest matching rows, sorted from
25
+ highest to lowest similarity.
26
+
27
+ Examples
28
+ --------
29
+ >>> data = get_data()
30
+ >>> results = search(data["fighters"], "Name", "Jon Jones")
31
+ """
32
+ scores = data[column].fillna("").apply(
33
+ lambda x: ratio(str(x), query))
34
+
35
+ result = data.loc[scores.nlargest(matches).index].copy()
36
+ result["score"] = scores.loc[result.index]
37
+ result = result.sort_values("score", ascending=False).drop(columns="score")
38
+
39
+ return result
ufcdata-0.1.2/README.md DELETED
File without changes
@@ -1 +0,0 @@
1
- from .data import get_data
File without changes
File without changes