impectPy 2.4.4__py3-none-any.whl

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.
@@ -0,0 +1,260 @@
1
+ # load packages
2
+ import pandas as pd
3
+ import requests
4
+ from impectPy.helpers import RateLimitedAPI, unnest_mappings_df
5
+ from .iterations import getIterationsFromHost
6
+
7
+ # define the allowed positions
8
+ allowed_positions = [
9
+ "GOALKEEPER",
10
+ "LEFT_WINGBACK_DEFENDER",
11
+ "RIGHT_WINGBACK_DEFENDER",
12
+ "CENTRAL_DEFENDER",
13
+ "DEFENSE_MIDFIELD",
14
+ "CENTRAL_MIDFIELD",
15
+ "ATTACKING_MIDFIELD",
16
+ "LEFT_WINGER",
17
+ "RIGHT_WINGER",
18
+ "CENTER_FORWARD"
19
+ ]
20
+
21
+ ######
22
+ #
23
+ # This function returns a pandas dataframe that contains all profile scores
24
+ # for a given iteration and a given set of positions per player
25
+ #
26
+ ######
27
+
28
+
29
+ def getPlayerProfileScores(
30
+ iteration: int, positions: list, token: str, session: requests.Session = requests.Session()
31
+ ) -> pd.DataFrame:
32
+
33
+ # create an instance of RateLimitedAPI
34
+ connection = RateLimitedAPI(session)
35
+
36
+ # construct header with access token
37
+ connection.session.headers.update({"Authorization": f"Bearer {token}"})
38
+
39
+ return getPlayerProfileScoresFromHost(iteration, positions, connection, "https://api.impect.com")
40
+
41
+ def getPlayerProfileScoresFromHost(
42
+ iteration: int, positions: list, connection: RateLimitedAPI, host: str
43
+ ) -> pd.DataFrame:
44
+
45
+ # check input for iteration argument
46
+ if not isinstance(iteration, int):
47
+ raise Exception("Input for iteration argument must be an integer")
48
+
49
+ # check input for positions argument
50
+ if not isinstance(positions, list):
51
+ raise Exception("Input for positions argument must be a list")
52
+
53
+ # check if the input positions are valid
54
+ invalid_positions = [position for position in positions if position not in allowed_positions]
55
+ if len(invalid_positions) > 0:
56
+ raise Exception(
57
+ f"Invalid position(s): {', '.join(invalid_positions)}."
58
+ f"\nChoose one or more of: {', '.join(allowed_positions)}"
59
+ )
60
+
61
+ # get squads
62
+ squads = connection.make_api_request_limited(
63
+ url=f"{host}/v5/customerapi/iterations/{iteration}/squads",
64
+ method="GET"
65
+ ).process_response(
66
+ endpoint="Squads"
67
+ )
68
+
69
+ # get squadIds
70
+ squad_ids = squads[squads.access].id.to_list()
71
+
72
+ # compile position string
73
+ position_string = ",".join(positions)
74
+
75
+ # get player profile scores per squad
76
+ profile_scores_raw = pd.concat(
77
+ map(lambda squadId: connection.make_api_request_limited(
78
+ url=f"{host}/v5/customerapi/iterations/{iteration}/"
79
+ f"squads/{squadId}/positions/{position_string}/player-profile-scores",
80
+ method="GET"
81
+ ).process_response(
82
+ endpoint="PlayerIterationScores",
83
+ raise_exception=False
84
+ ).assign(
85
+ iterationId=iteration,
86
+ squadId=squadId,
87
+ positions=position_string
88
+ ),
89
+ squad_ids),
90
+ ignore_index=True)
91
+
92
+ # raise exception if no player played at given positions in entire iteration
93
+ if len(profile_scores_raw) == 0:
94
+ raise Exception(f"No players played at given position in iteration {iteration}.")
95
+
96
+ # print squads without players at given position
97
+ error_list = [str(squadId) for squadId in squad_ids if squadId not in profile_scores_raw.squadId.to_list()]
98
+ if len(error_list) > 0:
99
+ print(f"No players played at positions {positions} for iteration {iteration} for following squads:\n\t{', '.join(error_list)}")
100
+
101
+ # get players
102
+ players = connection.make_api_request_limited(
103
+ url=f"{host}/v5/customerapi/iterations/{iteration}/players",
104
+ method="GET"
105
+ ).process_response(
106
+ endpoint="Players"
107
+ )[["id", "commonname", "firstname", "lastname", "birthdate", "birthplace", "leg", "countryIds", "idMappings"]]
108
+
109
+ # only keep first country id for each player
110
+ country_series = players["countryIds"].explode().groupby(level=0).first()
111
+ players["countryIds"] = players.index.to_series().map(country_series).astype("float").astype("Int64")
112
+ players = players.rename(columns={"countryIds": "countryId"})
113
+
114
+ # unnest mappings
115
+ players = unnest_mappings_df(players, "idMappings").drop(["idMappings"], axis=1).drop_duplicates()
116
+
117
+ # get scores
118
+ scores = connection.make_api_request_limited(
119
+ url=f"{host}/v5/customerapi/player-profiles",
120
+ method="GET"
121
+ ).process_response(
122
+ endpoint="playerProfiles"
123
+ )[["name"]]
124
+
125
+ # get iterations
126
+ iterations = getIterationsFromHost(connection=connection, host=host)
127
+
128
+ # get country data
129
+ countries = connection.make_api_request_limited(
130
+ url=f"{host}/v5/customerapi/countries",
131
+ method="GET"
132
+ ).process_response(
133
+ endpoint="KPIs"
134
+ )
135
+
136
+ # unnest scorings
137
+ profile_scores = profile_scores_raw.explode("profileScores").reset_index(drop=True)
138
+
139
+ # unnest dictionary in kpis column
140
+ profile_scores = pd.concat(
141
+ [profile_scores.drop(["profileScores"], axis=1), pd.json_normalize(profile_scores["profileScores"])],
142
+ axis=1
143
+ )
144
+
145
+ # merge with player scores to ensure all kpis are present
146
+ profile_scores = profile_scores.merge(
147
+ scores,
148
+ left_on="profileName",
149
+ right_on="name",
150
+ how="outer",
151
+ suffixes=("", "_right")
152
+ )
153
+
154
+ # get matchShares
155
+ match_shares = profile_scores[
156
+ ["iterationId", "squadId", "playerId", "positions", "playDuration", "matchShare"]].drop_duplicates()
157
+
158
+ # fill missing values in the "name" column with a default value to ensure players without scorings don't get lost
159
+ if len(profile_scores["name"][profile_scores["name"].isnull()]) > 0:
160
+ profile_scores["name"] = profile_scores["name"].fillna("-1")
161
+
162
+ # pivot kpi values
163
+ profile_scores = pd.pivot_table(
164
+ profile_scores,
165
+ values="value",
166
+ index=["iterationId", "squadId", "playerId", "positions"],
167
+ columns="name",
168
+ aggfunc="sum",
169
+ fill_value=0,
170
+ dropna=False
171
+ ).reset_index()
172
+
173
+ # drop "-1" column
174
+ if "-1" in profile_scores.columns:
175
+ profile_scores.drop(["-1"], inplace=True, axis=1)
176
+
177
+ # merge with playDuration and matchShare
178
+ profile_scores = profile_scores.merge(
179
+ match_shares,
180
+ left_on=["iterationId", "squadId", "playerId", "positions"],
181
+ right_on=["iterationId", "squadId", "playerId", "positions"],
182
+ how="inner",
183
+ suffixes=("", "_right")
184
+ )
185
+ # merge with other data
186
+ profile_scores = profile_scores.merge(
187
+ iterations[["id", "competitionName", "season"]],
188
+ left_on="iterationId",
189
+ right_on="id",
190
+ how="left",
191
+ suffixes=("", "_right")
192
+ ).merge(
193
+ squads[["id", "name"]].rename(
194
+ columns={"id": "squadId", "name": "squadName"}
195
+ ),
196
+ left_on="squadId",
197
+ right_on="squadId",
198
+ how="left",
199
+ suffixes=("", "_right")
200
+ ).merge(
201
+ players[[
202
+ "id", "wyscoutId", "heimSpielId", "skillCornerId", "commonname",
203
+ "firstname", "lastname", "birthdate", "birthplace", "countryId", "leg"
204
+ ]].rename(
205
+ columns={"commonname": "playerName"}
206
+ ),
207
+ left_on="playerId",
208
+ right_on="id",
209
+ how="left",
210
+ suffixes=("", "_right")
211
+ ).merge(
212
+ countries.rename(columns={"fifaName": "playerCountry"}),
213
+ left_on="countryId",
214
+ right_on="id",
215
+ how="left",
216
+ suffixes=("", "_right")
217
+ )
218
+
219
+ # remove NA rows
220
+ profile_scores = profile_scores[profile_scores.iterationId.notnull()]
221
+
222
+ # fix column types
223
+ profile_scores["squadId"] = profile_scores["squadId"].astype("Int64")
224
+ profile_scores["playerId"] = profile_scores["playerId"].astype("Int64")
225
+ profile_scores["iterationId"] = profile_scores["iterationId"].astype("Int64")
226
+ profile_scores["wyscoutId"] = profile_scores["wyscoutId"].astype("Int64")
227
+ profile_scores["heimSpielId"] = profile_scores["heimSpielId"].astype("Int64")
228
+ profile_scores["skillCornerId"] = profile_scores["skillCornerId"].astype("Int64")
229
+
230
+ # define column order
231
+ order = [
232
+ "iterationId",
233
+ "competitionName",
234
+ "season",
235
+ "squadId",
236
+ "squadName",
237
+ "playerId",
238
+ "wyscoutId",
239
+ "heimSpielId",
240
+ "skillCornerId",
241
+ "playerName",
242
+ "firstname",
243
+ "lastname",
244
+ "birthdate",
245
+ "birthplace",
246
+ "playerCountry",
247
+ "leg",
248
+ "positions",
249
+ "matchShare",
250
+ "playDuration"
251
+ ]
252
+
253
+ # add kpiNames to order
254
+ order = order + scores.name.to_list()
255
+
256
+ # select columns
257
+ profile_scores = profile_scores[order]
258
+
259
+ # return result
260
+ return profile_scores