Compare commits

..

22 Commits

Author SHA1 Message Date
811964e519 readme update and add user instructions 2024-03-09 11:15:21 +00:00
020857a1e7 zmiana leyotu prawegomenu oraz pozycji licznika eX 2024-01-20 20:21:48 +01:00
2d338824f8 usuniecie auomatycznego liczenia 2024-01-20 20:15:03 +01:00
234d08d0c1 naprawa danych kategorycznych 2024-01-20 17:47:55 +01:00
ffe2c13cdf model update 2024-01-20 17:18:19 +01:00
7bbe593dde more data training 2024-01-20 12:55:53 +01:00
09ebd98fb4 train model on new data 2024-01-20 09:26:51 +01:00
Maciej Chmielarz
9b7136b1af Naprawienie checklisty 2024-01-20 00:59:24 +01:00
Maciej Chmielarz
db214d217e Naprawa kategorycznych, Zmiana zapisywania/wczytywania xgboost 2024-01-19 15:25:32 +01:00
Szymon Obst
3749cf22b0 dodanie automatycznego liczenie eX , naprawa bledu zlego generowania kafelkow zawodnikow 2024-01-15 16:33:39 +01:00
5b3ae8684e dodanie ograniczen dodawania pilkarzy 2024-01-14 23:00:13 +01:00
378c897959 kilka mniejszych bledow 2024-01-14 22:01:50 +01:00
1b42cd208b small data and model improvement 2024-01-12 20:39:14 +01:00
412dd57577 Dodanie wszystkich zmiennych z modelu do apki oraz ich obsługa 2024-01-11 20:10:52 +01:00
f93d8c5c67 dodanie nowych parametrów do apki plus edycja UI 2024-01-11 17:32:16 +01:00
Maciej Chmielarz
cd5efc6921 zmiany ustawien domyslnych na angielskie nazwy 2024-01-09 15:34:52 +01:00
Maciej Chmielarz
0da7ccae42 zmiany server.py, ogarniecie xgboosta 2024-01-09 15:26:35 +01:00
Maciej Chmielarz
fc85d2f8f6 Merge branch 'modServera' of https://git.wmi.amu.edu.pl/s478993/fantastyczne_gole into modServera 2024-01-09 00:40:06 +01:00
Maciej Chmielarz
7a49396823 zmiana xgboost, zmiana typu danych, dodanie wartosci domyslnych 2024-01-09 00:39:38 +01:00
e03d8b48af work work work 2024-01-08 23:02:58 +01:00
f96465ed56 zmiana jezyka zmiennych kategorycznych 2024-01-08 22:50:39 +01:00
0b3e58f05e some work 2024-01-08 22:32:55 +01:00
29 changed files with 320629 additions and 38861 deletions

BIN
.DS_Store vendored

Binary file not shown.

BIN
.RData Normal file

Binary file not shown.

Binary file not shown.

View File

@ -1,4 +1,4 @@
# Analiza piłkarska z aplikacją `CoachStats`
# Aplikacja `CoachStats`
## Wstęp
@ -9,21 +9,18 @@ CoachStats to innowacyjne narzędzie służące do analizowania statystyk Expect
- **Analiza XG:** Analiza XG dla danej sytuacji meczowej.
- **Personalizowana makieta:** Możliwość tworzenia własnej makiety odpowiadającej sytuacji meczowej.
## Technologie
## Uruchomienie
## Instalacja i Uruchomienie
Aby uruchomić aktualną wersję aplikacji, wykonaj następujące kroki:
Aby uruchomić beta wersję aplikacji, wykonaj następujące kroki:
1. **Uruchomienie serwera:** Aby uruchomić serwer należy wejść w [link](https://sg-server-ne4h.onrender.com/) oraz zaczekać do pojawienia się komunikatu o błędzie 404. Aplikacja korzysta z darmowej wersji obsługi serwera, stąd sposób jego uruchomienia nie jest standardowy.
1. **Uruchomienie Klienta:**
Otwórz terminal w folderze `app` i uruchom następującą komendę:\
`npm run dev`
2. **Uruchomienie Serwera Flask:**
W innym terminalu, przejdź do folderu `app/src/flask-server` i uruchom serwer Flask przy użyciu poniższej komendy:\
`python server.py`
2. **Uruchomienie aplikacji webowej** Po wykonaiu kroku 1 można wejść na właściwą stronę [aplikacji](https://statgoals.onrender.com/).
## Dane
- <https://statsbomb.com/what-we-do/soccer-data/>
## Szczegóły
Działanie aplikacji zostało opisane w podręczniku użytkownika znajdującym się w drzewie plików na repozytorium. Poza tym odsyłam do [repozytorium](https://git.wmi.amu.edu.pl/s478993/fantastyczne_gole) uniwersytetu na którym powstała aplikacja. Zawiera ono kod źródłowy aplikacji.

BIN
app/src/assets/bramka.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

View File

@ -5,11 +5,49 @@ import { Link } from "react-router-dom";
const Hero = () => {
const [isOpen, setIsOpen] = useState(false);
const [gameMinute, setGameMinute] = useState('');
const toggleDropdown = () => setIsOpen(!isOpen);
const handleMinuteChange = (e) => setGameMinute(e.target.value);
const [firstShot, setfirstShot] = useState(0);
const [oneOnOne, SetoneOnOne] = useState(0);
const [afterAirDuel, SetafterAirDuele] = useState(0);
const [openGoal, SetOpenGoal] = useState(0);
const [afterDribbling, SetafterDribbling] = useState(0);
const [redirect, SetRedirect] = useState(0);
const handleMinuteChange = (e) => { setGameMinute(e.target.value);
//sentQuestion();
}
const handleFirstShotChange = (event) => {
setfirstShot(event.target.checked);
//sentQuestion();
};
const handleOneOnOneChange = (event) => {
SetoneOnOne(event.target.checked);
//sentQuestion();
};
const handleAfterAirDuelChange = (event) => {
SetafterAirDuele(event.target.checked);
//sentQuestion();
};
const handleOpenGoalChange = (event) => {
SetOpenGoal(event.target.checked);
//sentQuestion();
};
const handleAfterDribblingChange = (event) => {
SetafterDribbling(event.target.checked);
//sentQuestion();
};
const handleRedirectChange = (event) => {
SetRedirect(event.target.checked);
//sentQuestion();
};
const [data, setData] = useState("");
//zmienne globalne
@ -17,10 +55,24 @@ const Hero = () => {
//przez listener nanoszący zawodników na boisko. 1 - strzelec , 2 - bramkarz , 3 - obronca, 4 - napasnik. zmienna przez aktywacje przycskówk bb1, bb2, bb3 i bb4
let active_bbt = "bbt1";
const [number_of_defenders, setNumberOfDevenders] = useState(0);
const [number_of_strikers, setNumberOfStrikers] = useState(0)
const [number_of_goalkeepers, setNumberOfGoalkeppers] = useState(0);
const [number_of_shooters,setNumberOfShooters] = useState(0);
const [number_of_defenders, setNumberOfDevenders] = useState(()=>{
return 0;
});
const [number_of_strikers, setNumberOfStrikers] = useState(() => {
return 0;
})
const [number_of_goalkeepers, setNumberOfGoalkeppers] = useState(()=>{
return 0;
});
const [number_of_shooters,setNumberOfShooters] = useState(() => {
return 0}
);
const number_of_shooters_rev = React.useRef(number_of_shooters)
const number_of_strikers_rev = React.useRef(number_of_strikers)
const number_of_goalkeepers_rev = React.useRef(number_of_goalkeepers)
const number_of_defenders_rev = React.useRef(number_of_defenders)
// zmienne globalne bedace danymi wejsciowymi do modelu
@ -30,10 +82,10 @@ const Hero = () => {
var stricers = new Array;
var defenders = new Array;
const [bodyPart,setBodyPart] = useState('prawa');
const [technique,setTechnique] = useState('zwykly');
const [actionType,setActionType] = useState('pozycyjny');
const [shooterPossition,setPossition] = useState('napastnik');
const [bodyPart,setBodyPart] = useState('Right Foot');
const [technique,setTechnique] = useState('Normal');
const [actionType,setActionType] = useState('Open Play');
const [shooterPossition,setPossition] = useState('Center Forward');
//zamiana procentowych pozycji na kartezyjskie
function konwerturX(x){
@ -57,7 +109,6 @@ const Hero = () => {
// Reset Boiska
function resetField() {
var footballField = document.getElementById('footballField');
var footballs = document.querySelectorAll('.football');
var list = document.getElementById('list')
@ -69,13 +120,20 @@ const Hero = () => {
players.forEach(function(element) {
list.removeChild(element);
})
setNumberOfDevenders(0);
setNumberOfStrikers(0)
setNumberOfGoalkeppers(0)
setNumberOfShooters(0)
setGameMinute('')
number_of_shooters_rev.current = 0;
number_of_goalkeepers_rev.current = 0;
number_of_defenders_rev.current = 0;
number_of_strikers_rev.current = 0;
document.getElementById("ex").innerHTML = 0;
}
//funkcja dodaje zawodnika do listy zawodnikow. zmienne x oraz y to wspolrzedne a position
// to pozycja zawodnika 0 - strzelec, 1 - bramkarz, 2 - broniacy, 3 napastnik
// ball - to odnosnik do punktu na boisku
@ -86,14 +144,15 @@ const Hero = () => {
list.removeChild(player)
bojo.removeChild(ball)
if(possition == 1){
setNumberOfGoalkeppers(0)
setNumberOfGoalkeppers(number_of_goalkeepers_rev.current -= 1);
}else if(possition == 2){
setNumberOfDevenders(number_of_defenders-1) ;
setNumberOfDevenders(number_of_defenders_rev.current -= 1) ;
}else if (possition == 3){
setNumberOfStrikers(number_of_strikers-1) ;
}else if(possition == 0){
setNumberOfShooters(0)
setNumberOfStrikers(number_of_strikers_rev.current -= 1);
}else if(possition == 0){
setNumberOfShooters(number_of_shooters_rev.current -= 1);
}
//sentQuestion()
}
// funkcja zsczytuje pozycje zawodnikow przed wyslaniem zapytania do serwera
@ -127,19 +186,22 @@ const Hero = () => {
var pName = "Strzelec"
//kolor kropki
// kolor tła kafelka
var pColor = "#fc0303"
if(possition == 1){
var pName = "Bramkarz"
var pColor = "#03e7fc"
setNumberOfGoalkeppers(number_of_goalkeepers_rev.current += 1);
}else if(possition == 2){
var pName = "Obrońca"
var pColor = "#0324fc"
setNumberOfDevenders(number_of_defenders_rev.current += 1);
}else if (possition ==3){
var pName = "Napastnik"
var pColor = "#fc6703"
setNumberOfStrikers(number_of_strikers_rev.current += 1);
}else{
setNumberOfShooters(number_of_shooters_rev.current += 1);
}
var player = document.createElement('div');
player.className = 'player';
player.style.width = "inherit"
@ -148,18 +210,18 @@ const Hero = () => {
// div z nazwa gracza
var tekst = document.createElement('div')
tekst.style.fontSize = "10px";
tekst.style.fontSize = "12px";
tekst.innerHTML = pName;
// div z pozycja gracza
var posytion = document.createElement('div')
posytion.style.fontSize = "10px"
posytion.innerHTML = "x:" + konwerturX(ball.style.left) + "m " + "y:" + konwetujY(ball.style.top) + "m";
posytion.style.fontSize = "12px"
posytion.innerHTML = konwerturX(ball.style.left) + " m, " + konwetujY(ball.style.top) + " m";
player.setAttribute('possition',[konwerturX(ball.style.left),konwetujY(ball.style.top)])
//div z przyciskiem usuwającym
var btnDelete = document.createElement('button')
btnDelete.innerHTML = 'Usun'
btnDelete.style.fontSize = "10px"
btnDelete.innerHTML = 'Usuń'
btnDelete.style.fontSize = "12px"
btnDelete.style = 'background-color: #FFB266;color:#000000'
btnDelete.addEventListener("click",function(){deletePlayer(ball,player,possition)},false)
//dodanie elementów do kafelka
@ -209,8 +271,8 @@ const Hero = () => {
tekst.style.color = "white"
posytion.style.color = "white"
x = parseFloat(x) -2
y = parseFloat(y) -2
x = parseFloat(x) -3
y = parseFloat(y) -3
if(bojo.parentNode.querySelector(":hover")){
ball.style.left = x + "%"
@ -220,25 +282,28 @@ const Hero = () => {
//var shooterY = konwetujY(ball.style.top)
posytion.innerHTML = "x:" + konwerturX(ball.style.left) + "m " + "y:" + konwetujY(ball.style.top) + "m";
player.setAttribute('possition',[konwerturX(ball.style.left),konwetujY(ball.style.top)]);
bojo.addEventListener("mouseup", function(){
bojo.addEventListener("mouseup", function afterUp(){
ball.style.background = pColor
bojo.removeEventListener("mousemove", whileMove)
bojo.removeEventListener("mouseup", afterUp)
})
})
})
bojo.addEventListener("mouseup", function reload(){
//sentQuestion();
bojo.removeEventListener("mouseup",reload)
})
})
//sentQuestion();
}
// // Wyłanie zapytania do serwera
function sentQuestion() {
///Dziwny Blad
loadPlayers()
if (number_of_shooters == 1) {
if (number_of_shooters_rev.current == 1) {
//console.log('Wysyłanie wartości: ', bodyPart, technique, actionType, shooterPossition, gameMinute, firstShot);
// Użyj backticksów zamiast zwykłych cudzysłowów
fetch(`http://127.0.0.1:5000/get_model?shooter=${shooter}&goalkeeper=${goalkeeper}&defenders=${defenders}&strickers=${stricers}&bodyPart=${bodyPart}&technique=${technique}&actionType=${actionType}&shooterPossition=${shooterPossition}`).then(
fetch(`http://127.0.0.1:5000/get_model?shooter=${shooter}&goalkeeper=${goalkeeper}&defenders=${defenders}&strickers=${stricers}&bodyPart=${bodyPart}&technique=${technique}&actionType=${actionType}&shooterPossition=${shooterPossition}&gameMinute=${gameMinute}&shot_first_time=${firstShot}&shot_one_on_one=${oneOnOne}&shot_aerial_won=${afterAirDuel}&shot_open_goal=${openGoal}&shot_follows_dribble=${afterDribbling}&shot_redirect=${redirect}`).then(
res => res.json()
).then(
data => {
@ -246,7 +311,8 @@ const Hero = () => {
console.log(data);
// Przenieś tę linię do środka bloku .then(), aby uniknąć błędów
let eX = data.response;
document.getElementById("ex").innerHTML = "Współczynnik xG: " + eX;
document.getElementById("ex").innerHTML = eX;
//updateXGMeter(eX);
}
).catch(error => {
console.error('Błąd:', error);
@ -254,10 +320,9 @@ const Hero = () => {
} else {
alert('Piłka nie jest obecnie na boisku.');
}
}
/* Funkcja dodająca listener do boiska*/
@ -276,38 +341,32 @@ const Hero = () => {
ball.style.top = y + "%"
//dodanie zawodnika do listy oraz punktu do mapy w zaleznosci od aktywnosci przycisku 1,2,3 lub 4
if(active_bbt=="bbt1"){
if(number_of_shooters < 1 ){
if(number_of_shooters_rev.current < 1 ){
addPlayer(0,ball)
bojo.appendChild(ball)
ball.style.background = "#fc0303"
setNumberOfShooters(number_of_shooters+1)
}else{alert("mozesz dodac tylko jednego strzelca")}
}else if(active_bbt == "bbt2"){
if ( number_of_goalkeepers < 1){
if ( number_of_goalkeepers_rev.current < 1){
addPlayer(1,ball)
bojo.appendChild(ball)
ball.style.background = "#03e7fc"
setNumberOfGoalkeppers(number_of_goalkeepers+1)
ball.style.background = "#03e7fc"
}else{alert("mozesz dodac tylko jednego bramkarza")}
}else if(active_bbt == "bbt3"){
if(number_of_defenders <= 10){
if(number_of_defenders_rev.current < 10){
addPlayer(2,ball);
setNumberOfDevenders(number_of_defenders+1)
bojo.appendChild(ball)
ball.style.background = "#0324fc"
}else{alert("maksymalna liczba obroncow")}
}else if(active_bbt == "bbt4"){
if(number_of_strikers <= 10){
if(number_of_strikers_rev.current < 10){
addPlayer(3,ball);
setNumberOfStrikers(number_of_strikers+1);
bojo.appendChild(ball)
ball.style.background = "#fc6703"
}else{alert("maksymalna liczba napastnikow")}
}
}
// funkcja działą po utworzeniu komponentów, dodaje listenry do elementów
@ -336,16 +395,18 @@ const Hero = () => {
<div className="container">
{/* Listy zwijane */}
<div className="top-bar">
<div className="top-bar" id = "top-bar">
<form className="dropdown" id = "bodyPartList">
<select className="dropbtn"
onChange={event => setBodyPart(event.target.value)}
onChange={event => {setBodyPart(event.target.value);
//sentQuestion()
}}
defaultValue={bodyPart}>
<option value = "prawa">Noga Prawa</option>
<option value = "lewa">Noga Lewa</option>
<option value = "glowa">Głowa</option>
<option value = "inna" >Inna</option>
<option value = "Right Foot">Noga Prawa</option>
<option value = "Left Foot">Noga Lewa</option>
<option value = "Head">Głowa</option>
<option value = "Other" >Inna</option>
</select>
</form>
@ -353,37 +414,62 @@ const Hero = () => {
<form className="dropdown" id = "shootTypeList">
<select className="dropbtn" onChange={event => setTechnique(event.target.value)}
<select className="dropbtn" onChange={event => {setTechnique(event.target.value);
//sentQuestion()
}}
defaultValue = {technique}>
<option value="zwykly"> Zwykły </option>
<option value = "voley"> Wolej </option>
<option value = "pol-voley"> Półwolej </option>
<option value = "lob"> Lob </option>
<option value = "szczupak"> Szczupak </option>
<option value = "z_gory"> Kopnięcie z góry </option>
<option value = "pietka"> Piętka </option>
<option value="Normal"> Zwykły </option>
<option value = "Volley"> Wolej </option>
<option value = "Half Volley"> Półwolej </option>
<option value = "Lob"> Lob </option>
<option value = "Diving Header"> Szczupak </option>
<option value = "Overhead Kick"> Kopnięcie z góry </option>
<option value = "Backheel"> Piętka </option>
</select>
</form>
<form className="dropdown" id = "actionTypeList" onChange={event => setActionType(event.target.value)}
<form className="dropdown" id = "actionTypeList" onChange={event => {setActionType(event.target.value);
//sentQuestion()
}}
defaultValue={technique}>
<select className="dropbtn">
<option value = "pozycyjny"> Atak Pozycyjny </option>
<option value = "wolny"> Rzut Wolny </option>
<option value = "karny"> Rzut Karny </option>
<option value= "rozny"> Rzut Rozny </option>
<option value="rozpoczecie"> Rozpoczęcie </option>
<option value = "Open Play"> Atak Pozycyjny </option>
<option value = "Free Kick"> Rzut Wolny </option>
<option value = "Penalty"> Rzut Karny </option>
<option value= "Corner"> Rzut Rozny </option>
</select>
</form>
<form className="dropdown" id = "possitionList"
onChange={event => setPossition(event.target.value)}
onChange={event => {setPossition(event.target.value);
//sentQuestion()
}}
defaultValue={shooterPossition}>
<select className="dropbtn">
<option value= "napastnik" > Napastnik </option>
<option value = "bramkarz"> Bramkarz </option>
<option value = "obronca"> Obrońca </option>
<option value = "pomocnik"> Pomocnik </option>
<option value="Right Center Forward">Prawy Środkowy Napastnik</option>
<option value="Left Center Forward">Lewy Środkowy Napastnik</option>
<option value="Secondary Striker">Drugi Napastnik</option>
<option value="Center Forward">Środkowy Napastnik</option>
<option value="Center Midfield">Środkowy Pomocnik</option>
<option value="Left Center Midfield">Lewy Środkowy Pomocnik</option>
<option value="Right Center Midfield">Prawy Środkowy Pomocnik</option>
<option value="Left Midfield">Lewy Pomocnik</option>
<option value="Center Attacking Midfield">Środkowy Ofensywny Pomocnik</option>
<option value="Left Defensive Midfield">Lewy Defensywny Pomocnik</option>
<option value="Left Attacking Midfield">Lewy Ofensywny Pomocnik</option>
<option value="Right Attacking Midfield">Prawy Ofensywny Pomocnik</option>
<option value="Right Defensive Midfield">Prawy Defensywny Pomocnik</option>
<option value="Center Defensive Midfield">Środkowy Defensywny Pomocnik</option>
<option value="Right Midfield">Prawy Pomocnik</option>
<option value="Left Wing Back">Lewy Pomocnik Skrzydłowy</option>
<option value="Left Wing">Lewe Skrzydło</option>
<option value="Right Wing">Prawe Skrzydło</option>
<option value="Right Wing Back">Prawy Pomocnik Skrzydłowy</option>
<option value="Center Back">Środkowy Obrońca</option>
<option value="Left Center Back">Lewy Środkowy Obrońca</option>
<option value="Right Center Back">Prawy Środkowy Obrońca</option>
<option value="Right Back">Prawy Obrońca</option>
<option value="Left Back">Lewy Obrońca</option>
<option value="Goalkeeper">Bramkarz</option>
</select>
</form>
@ -409,25 +495,40 @@ const Hero = () => {
<div className="field-pic"></div>
</div>
<div className="rightMenu">
<div className="xg-meter">
<b id="ex" className="xg-value">0</b>
</div>
{/* <div className="ChoosingPlayer">
<button className="cho-one_on_one" id = "bbt8">Sam na sam</button>
</div>
<div className="ChoosingPlayer">
<button className="cho-first_time" id = "bbt12">Pierwszy w meczu</button>
</div>
<div className="ChoosingPlayer">
<button className="cho-aerial_won" id = "bbt13">Pojedynek powietrzny</button>
</div>
<div className="ChoosingPlayer">
<button className="cho-follows_dribble" id = "bbt14">Drybling</button>
</div>
<div className="ChoosingPlayer">
<button className="cho-redirect" id = "bbt15">Rykoszet</button>
</div> */}
<div className="additional-parameters">
<h3>Parametry strzału</h3>
<label>
<input type="checkbox" id="firstShot" onChange={handleFirstShotChange} />
Pierwszy w meczu
</label>
<label>
<input type="checkbox" id="oneOnOne" onChange={handleOneOnOneChange} />
Akcja sam na sam
</label>
<label>
<input type="checkbox" id="afterAirDuel" onChange={handleAfterAirDuelChange} />
Po pojedynku powietrznym
</label>
<label>
<input type="checkbox" id="openGoal" onChange={handleOpenGoalChange} />
Na pustą bramkę
</label>
<label>
<input type="checkbox" id="afterDribbling" onChange={handleAfterDribblingChange} />
Poprzedzony dryblingiem
</label>
<label>
<input type="checkbox" id="redirect" onChange={handleRedirectChange} />
Rykoszet
</label>
</div>
</div>
</div>
<div className="bottom-bar">
<button className="cho-shooter" id = "bbt1">Strzelec</button>
@ -437,13 +538,8 @@ const Hero = () => {
<button className="reset-button" onClick={resetField}>Reset</button>
<button className="info-button" onClick={sentQuestion}>xG</button>
</div>
<div>
<b id = "ex" className="Ex">
</b>
</div>
</div>
</div>
);
};

View File

@ -3,6 +3,7 @@ import React from 'react'
const Loader = () => {
return (
<div>Loader</div>
)
}

Binary file not shown.

View File

@ -2,105 +2,157 @@ from joblib import load
import pandas as pd
from math import sqrt
import math
import numpy as np
import xgboost
from sklearn.preprocessing import OrdinalEncoder
# Funkcja zwraca prawdopodobieństwo zdobycia gola
def LogisticRegression_predict_proba(position_x, position_y, distance_to_goalM, angle, match_minute, Number_Intervening_Opponents, Number_Intervening_Teammates, isFoot, isHead):
# distance_to_goalM = sqrt(( (position_x**2) + (position_y**2)))
def LogisticRegression_predict_proba(position_x, position_y, distance_to_goalM, angle, match_minute, Number_Intervening_Opponents, Number_Intervening_Teammates, isFoot, isHead):
# distance_to_goalM = sqrt(( (position_x**2) + (position_y**2)))
model = load('regresja_logistyczna.joblib')
X_new = pd.DataFrame(columns=['position_x', 'position_y', 'distance_to_goalM', 'angle','match_minute', 'Number_Intervening_Opponents','Number_Intervening_Teammates', 'isFoot', 'isHead'])
X_new.loc[len(X_new.index)] = [position_x, position_y, distance_to_goalM, angle, match_minute, Number_Intervening_Opponents, Number_Intervening_Teammates, isFoot, isHead]
return model.predict_proba(X_new)[0][1].round(2)
#xgBoost
def xgboost_predict_proba(minute, position_name, shot_body_part_name, shot_technique_name,
shot_type_name, shot_first_time, shot_one_on_one,
shot_aerial_won, shot_deflected, shot_open_goal,
shot_follows_dribble, shot_redirect, x1, y1,
number_of_players_opponents, number_of_players_teammates,
angle, distance, x_player_opponent_Goalkeeper,
x_player_opponent_8, x_player_opponent_1, x_player_opponent_2,
x_player_opponent_3, x_player_teammate_1, x_player_opponent_4,
x_player_opponent_5, x_player_opponent_6, x_player_teammate_2,
x_player_opponent_9, x_player_opponent_10, x_player_opponent_11,
x_player_teammate_3, x_player_teammate_4, x_player_teammate_5,
x_player_teammate_6, x_player_teammate_7, x_player_teammate_8,
x_player_teammate_9, x_player_teammate_10,
y_player_opponent_Goalkeeper, y_player_opponent_8,
y_player_opponent_1, y_player_opponent_2, y_player_opponent_3,
y_player_teammate_1, y_player_opponent_4, y_player_opponent_5,
y_player_opponent_6, y_player_teammate_2, y_player_opponent_9,
y_player_opponent_10, y_player_opponent_11, y_player_teammate_3,
y_player_teammate_4, y_player_teammate_5, y_player_teammate_6,
y_player_teammate_7, y_player_teammate_8, y_player_teammate_9,
y_player_teammate_10, x_player_opponent_7, y_player_opponent_7,
x_player_teammate_Goalkeeper, y_player_teammate_Goalkeeper,
shot_kick_off):
def xgboost_predict_proba(minute=0, position_name='Center Forward', shot_body_part_name='Right Foot',
shot_technique_name='Normal', shot_type_name='Open Play', shot_first_time=False,
shot_one_on_one=False, shot_aerial_won=False,
shot_open_goal=False, shot_follows_dribble=False, shot_redirect=False, x1=0.0, y1=0.0,
number_of_players_opponents=0, number_of_players_teammates=0,
angle=0.0, distance=0.0, x_player_opponent_Goalkeeper=np.nan,
x_player_opponent_8=np.nan, x_player_opponent_1=np.nan, x_player_opponent_2=np.nan,
x_player_opponent_3=np.nan, x_player_teammate_1=np.nan, x_player_opponent_4=np.nan,
x_player_opponent_5=np.nan, x_player_opponent_6=np.nan, x_player_teammate_2=np.nan,
x_player_opponent_9=np.nan, x_player_opponent_10=np.nan, x_player_opponent_11=np.nan,
x_player_teammate_3=np.nan, x_player_teammate_4=np.nan, x_player_teammate_5=np.nan,
x_player_teammate_6=np.nan, x_player_teammate_7=np.nan, x_player_teammate_8=np.nan,
y_player_opponent_Goalkeeper=np.nan, y_player_opponent_8=np.nan,
x_player_teammate_9=np.nan, x_player_teammate_10=np.nan,
y_player_opponent_1=np.nan, y_player_opponent_2=np.nan, y_player_opponent_3=np.nan,
y_player_teammate_1=np.nan, y_player_opponent_4=np.nan, y_player_opponent_5=np.nan,
y_player_opponent_6=np.nan, y_player_teammate_2=np.nan, y_player_opponent_9=np.nan,
y_player_opponent_10=np.nan, y_player_opponent_11=np.nan, y_player_teammate_3=np.nan,
y_player_teammate_4=np.nan, y_player_teammate_5=np.nan, y_player_teammate_6=np.nan,
y_player_teammate_7=np.nan, y_player_teammate_8=np.nan, y_player_teammate_9=np.nan,
y_player_teammate_10=np.nan, x_player_opponent_7=np.nan, y_player_opponent_7=np.nan,
x_player_teammate_Goalkeeper=np.nan, y_player_teammate_Goalkeeper=np.nan):
model = load('xgboost.joblib')
X_new = pd.DataFrame(columns=['minute', 'position_name', 'shot_body_part_name', 'shot_technique_name',
'shot_type_name', 'shot_first_time', 'shot_one_on_one',
'shot_aerial_won', 'shot_deflected', 'shot_open_goal',
'shot_follows_dribble', 'shot_redirect', 'x1', 'y1',
'number_of_players_opponents', 'number_of_players_teammates',
'angle', 'distance', 'x_player_opponent_Goalkeeper',
'x_player_opponent_8', 'x_player_opponent_1', 'x_player_opponent_2',
'x_player_opponent_3', 'x_player_teammate_1', 'x_player_opponent_4',
'x_player_opponent_5', 'x_player_opponent_6', 'x_player_teammate_2',
'x_player_opponent_9', 'x_player_opponent_10', 'x_player_opponent_11',
'x_player_teammate_3', 'x_player_teammate_4', 'x_player_teammate_5',
'x_player_teammate_6', 'x_player_teammate_7', 'x_player_teammate_8',
'x_player_teammate_9', 'x_player_teammate_10',
'y_player_opponent_Goalkeeper', 'y_player_opponent_8',
'y_player_opponent_1', 'y_player_opponent_2', 'y_player_opponent_3',
'y_player_teammate_1', 'y_player_opponent_4', 'y_player_opponent_5',
'y_player_opponent_6', 'y_player_teammate_2', 'y_player_opponent_9',
'y_player_opponent_10', 'y_player_opponent_11', 'y_player_teammate_3',
'y_player_teammate_4', 'y_player_teammate_5', 'y_player_teammate_6',
'y_player_teammate_7', 'y_player_teammate_8', 'y_player_teammate_9',
'y_player_teammate_10', 'x_player_opponent_7', 'y_player_opponent_7',
'x_player_teammate_Goalkeeper', 'y_player_teammate_Goalkeeper',
'shot_kick_off'])
model = xgboost.XGBClassifier()
model.load_model('xgboost.json')
enc = OrdinalEncoder()
enc = load('labelEncoder.joblib')
X_new = pd.DataFrame(columns=['minute', 'position_name', 'shot_body_part_name', 'shot_technique_name',
'shot_type_name', 'shot_first_time', 'shot_one_on_one',
'shot_aerial_won', 'shot_open_goal',
'shot_follows_dribble', 'shot_redirect', 'x1', 'y1',
'number_of_players_opponents', 'number_of_players_teammates',
'angle', 'distance', 'x_player_opponent_Goalkeeper',
'x_player_opponent_8', 'x_player_opponent_1', 'x_player_opponent_2',
'x_player_opponent_3', 'x_player_teammate_1', 'x_player_opponent_4',
'x_player_opponent_5', 'x_player_opponent_6', 'x_player_teammate_2',
'x_player_opponent_9', 'x_player_opponent_10', 'x_player_opponent_11',
'x_player_teammate_3', 'x_player_teammate_4', 'x_player_teammate_5',
'x_player_teammate_6', 'x_player_teammate_7', 'x_player_teammate_8',
'x_player_teammate_9', 'x_player_teammate_10',
'y_player_opponent_Goalkeeper', 'y_player_opponent_8',
'y_player_opponent_1', 'y_player_opponent_2', 'y_player_opponent_3',
'y_player_teammate_1', 'y_player_opponent_4', 'y_player_opponent_5',
'y_player_opponent_6', 'y_player_teammate_2', 'y_player_opponent_9',
'y_player_opponent_10', 'y_player_opponent_11', 'y_player_teammate_3',
'y_player_teammate_4', 'y_player_teammate_5', 'y_player_teammate_6',
'y_player_teammate_7', 'y_player_teammate_8', 'y_player_teammate_9',
'y_player_teammate_10', 'x_player_opponent_7', 'y_player_opponent_7',
'x_player_teammate_Goalkeeper', 'y_player_teammate_Goalkeeper'])
X_new.loc[len(X_new.index)] = [minute, position_name, shot_body_part_name, shot_technique_name,
shot_type_name, shot_first_time, shot_one_on_one,
shot_aerial_won, shot_deflected, shot_open_goal,
shot_follows_dribble, shot_redirect, x1, y1,
number_of_players_opponents, number_of_players_teammates,
angle, distance, x_player_opponent_Goalkeeper,
x_player_opponent_8, x_player_opponent_1, x_player_opponent_2,
x_player_opponent_3, x_player_teammate_1, x_player_opponent_4,
x_player_opponent_5, x_player_opponent_6, x_player_teammate_2,
x_player_opponent_9, x_player_opponent_10, x_player_opponent_11,
x_player_teammate_3, x_player_teammate_4, x_player_teammate_5,
x_player_teammate_6, x_player_teammate_7, x_player_teammate_8,
x_player_teammate_9, x_player_teammate_10,
y_player_opponent_Goalkeeper, y_player_opponent_8,
y_player_opponent_1, y_player_opponent_2, y_player_opponent_3,
y_player_teammate_1, y_player_opponent_4, y_player_opponent_5,
y_player_opponent_6, y_player_teammate_2, y_player_opponent_9,
y_player_opponent_10, y_player_opponent_11, y_player_teammate_3,
y_player_teammate_4, y_player_teammate_5, y_player_teammate_6,
y_player_teammate_7, y_player_teammate_8, y_player_teammate_9,
y_player_teammate_10, x_player_opponent_7, y_player_opponent_7,
x_player_teammate_Goalkeeper, y_player_teammate_Goalkeeper,
shot_kick_off]
return model.predict_proba(X_new)[0][1].round(2)
X_new.loc[len(X_new.index)] = [minute, position_name, shot_body_part_name, shot_technique_name,
shot_type_name, shot_first_time, shot_one_on_one,
shot_aerial_won, shot_open_goal,
shot_follows_dribble, shot_redirect, x1, y1,
number_of_players_opponents, number_of_players_teammates,
angle, distance, x_player_opponent_Goalkeeper,
x_player_opponent_8, x_player_opponent_1, x_player_opponent_2,
x_player_opponent_3, x_player_teammate_1, x_player_opponent_4,
x_player_opponent_5, x_player_opponent_6, x_player_teammate_2,
x_player_opponent_9, x_player_opponent_10, x_player_opponent_11,
x_player_teammate_3, x_player_teammate_4, x_player_teammate_5,
x_player_teammate_6, x_player_teammate_7, x_player_teammate_8,
x_player_teammate_9, x_player_teammate_10,
y_player_opponent_Goalkeeper, y_player_opponent_8,
y_player_opponent_1, y_player_opponent_2, y_player_opponent_3,
y_player_teammate_1, y_player_opponent_4, y_player_opponent_5,
y_player_opponent_6, y_player_teammate_2, y_player_opponent_9,
y_player_opponent_10, y_player_opponent_11, y_player_teammate_3,
y_player_teammate_4, y_player_teammate_5, y_player_teammate_6,
y_player_teammate_7, y_player_teammate_8, y_player_teammate_9,
y_player_teammate_10, x_player_opponent_7, y_player_opponent_7,
x_player_teammate_Goalkeeper, y_player_teammate_Goalkeeper]
X_new[['position_name',
'shot_technique_name',
'shot_type_name',
'shot_body_part_name']] = enc.transform(X_new[['position_name', 'shot_technique_name', 'shot_type_name', 'shot_body_part_name']], )
X_new[['minute',
'position_name',
'shot_technique_name',
'shot_type_name',
'number_of_players_opponents',
'number_of_players_teammates',
'shot_body_part_name']] = X_new[['minute',
'position_name',
'shot_technique_name',
'shot_type_name',
'number_of_players_opponents',
'number_of_players_teammates',
'shot_body_part_name']].astype(int)
# X_new[['minute',
# 'position_name',
# 'shot_technique_name',
# 'shot_type_name',
# 'number_of_players_opponents',
# 'number_of_players_teammates',
# 'shot_body_part_name']] = X_new[['minute',
# 'position_name',
# 'shot_technique_name',
# 'shot_type_name',
# 'number_of_players_opponents',
# 'number_of_players_teammates',
# 'shot_body_part_name']].astype('category')
X_new[['shot_first_time',
'shot_one_on_one',
'shot_aerial_won',
'shot_open_goal',
'shot_follows_dribble',
'shot_redirect']] = X_new[['shot_first_time',
'shot_one_on_one',
'shot_aerial_won',
'shot_open_goal',
'shot_follows_dribble',
'shot_redirect']].astype(int)
print(X_new)
print(X_new.dtypes)
return model.predict_proba(X_new)[0][1].round(3)
#XgBoost_2
def xgboost_predict_proba_v2(shooter,goalkeeper,teamMatesList,opponentsList, minute,position_name,shot_body_part_name,
shot_technique_name,shot_type_name,shot_first_time,shot_aerial_won,shot_deflected,shot_open_goal,
shot_follows_dribble,shot_redirect, shot_kick_off):
shot_technique_name,shot_type_name,shot_first_time,shot_aerial_won,shot_open_goal,
shot_follows_dribble,shot_redirect):
model = load('xgboost.joblib')
X_new = pd.DataFrame(columns=['minute', 'position_name', 'shot_body_part_name',
'shot_technique_name','shot_type_name', 'shot_first_time',
'shot_one_on_one','shot_aerial_won', 'shot_deflected',
'shot_one_on_one','shot_aerial_won',
'shot_open_goal','shot_follows_dribble', 'shot_redirect',
'x1', 'y1','number_of_players_opponents',
'number_of_players_teammates','angle', 'distance',
'x_player_opponent_Goalkeeper',
'x_player_opponent_Goalkeeper', 'x_player_opponent_8',
'x_player_opponent_1', 'x_player_opponent_2','x_player_opponent_3',
'x_player_opponent_4','x_player_opponent_5', 'x_player_opponent_6',
'x_player_teammate_2','x_player_opponent_9', 'x_player_opponent_10',
@ -116,8 +168,7 @@ def xgboost_predict_proba_v2(shooter,goalkeeper,teamMatesList,opponentsList, min
'y_player_teammate_4', 'y_player_teammate_5', 'y_player_teammate_6',
'y_player_teammate_7', 'y_player_teammate_8', 'y_player_teammate_9',
'y_player_teammate_10', 'x_player_opponent_7', 'y_player_opponent_7',
'x_player_teammate_Goalkeeper', 'y_player_teammate_Goalkeeper',
'shot_kick_off'])
'x_player_teammate_Goalkeeper', 'y_player_teammate_Goalkeeper'])
shooter = konwertujDoListy(shooter)
@ -137,8 +188,10 @@ def xgboost_predict_proba_v2(shooter,goalkeeper,teamMatesList,opponentsList, min
teamMatesList = zmienWMaciez(teamMatesList)
opponentsList = zmienWMaciez(opponentsList)
number_of_players_opponents = len(teamMatesList)
number_of_players_teammates = len(opponentsList)
# DO ROZBUDOWY
number_of_players_opponents = 3
number_of_players_teammates = 3
# Bramkarz
x_player_opponent_Goalkeeper = goalkeeper[0]
y_player_opponent_Goalkeeper = goalkeeper[1]
@ -146,19 +199,16 @@ def xgboost_predict_proba_v2(shooter,goalkeeper,teamMatesList,opponentsList, min
shot_one_on_one = True if number_of_players_opponents == 1 else False
# TeamMate goalkeppe
x_player_teammate_Goalkeeper = None
y_player_teammate_Goalkeeper = None
x_player_teammate_Goalkeeper = np.nan
y_player_teammate_Goalkeeper = np.nan
#Reszta Zawodnikow
print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
print(X_new.head)
X_new.loc[len(X_new.index)] = [minute, position_name, shot_body_part_name,
shot_technique_name,shot_type_name, shot_first_time,
shot_one_on_one,shot_aerial_won, shot_deflected,
shot_one_on_one,shot_aerial_won,
shot_open_goal,shot_follows_dribble, shot_redirect,
shooter[0], shooter[1],number_of_players_opponents,
number_of_players_teammates,angle, distance,
x_player_opponent_Goalkeeper,
x_player_opponent_Goalkeeper, opponentsList[8][0],
opponentsList[0][0], opponentsList[1][0], opponentsList[2][0],
opponentsList[3][0], opponentsList[4][0], opponentsList[5][0],
opponentsList[6][0], opponentsList[7][0], teamMatesList[8][0],
@ -175,13 +225,17 @@ def xgboost_predict_proba_v2(shooter,goalkeeper,teamMatesList,opponentsList, min
teamMatesList[0][1],teamMatesList[1][1], teamMatesList[2][1],
teamMatesList[4][1],teamMatesList[5][1], teamMatesList[6][1], teamMatesList[7][1],
teamMatesList[8][1], teamMatesList[9][1],
x_player_teammate_Goalkeeper, y_player_teammate_Goalkeeper,
shot_kick_off]
x_player_teammate_Goalkeeper, y_player_teammate_Goalkeeper]
categorical_columns = ['position_name', 'shot_technique_name', 'shot_type_name', 'number_of_players_opponents', 'number_of_players_teammates', 'shot_body_part_name'] # list all your object columns here
# X_new = pd.get_dummies(X_new, columns=categorical_columns)
X_new[categorical_columns] = X_new[categorical_columns].astype('category')
return model.predict_proba(X_new)[0][1].round(2)
# Pomocnicze Funkcje
# trzeba uzupelnic
def sortNearestToShooter(playerList, shooter):
return playerList
@ -198,14 +252,14 @@ def loc2angle(x, y):
rads = math.pi + rads if rads < 0 else rads
deg = math.degrees(rads)
return deg
# zamiana stringa odzielonego ',' na liste
def konwertujDoListy(listaString):
listaString = listaString.split(",")
listaFloat = []
for elem in listaString:
listaFloat.append(float(elem))
return listaFloat
#Zamiana listy w formie [1x,1y,2x,2y,3x,3y...] do postaci maciezy [xi, yi]
def zmienWMaciez(lista):
maciez = []
for i in range(0,len(lista),2):
@ -213,5 +267,5 @@ def zmienWMaciez(lista):
maciez.append(player)
if(len(maciez) < 10):
for i in range(len(maciez),11,1):
maciez.append([None,None])
return maciez
maciez.append([np.nan,np.nan])
return maciez

View File

@ -1,6 +1,8 @@
from flask import Flask, request, jsonify
from flask_cors import CORS
from modele.modele import LogisticRegression_predict_proba, xgboost_predict_proba, xgboost_predict_proba_v2
import numpy as np
import math
app = Flask(__name__)
@ -24,37 +26,218 @@ def get_model():
# Elementy z list: czesc ciała,rodzaj uderzenia,pozycja strzelca oraz typ akcji
position_name = request.args.get('shooter')
body_part = request.args.get('bodyPart')
technique = request.args.get('technique')
acionType = request.args.get('actionType')
minute = request.args.get('gameMinute')
position_name = request.args.get('shooterPossition')
gameMinute = request.args.get('gameMinute')
print("pozycja strzelca: " + position_name)
shot_first_time = request.args.get('shot_first_time')
shot_one_on_one = request.args.get('shot_one_on_one')
shot_aerial_won = request.args.get('shot_aerial_won')
shot_open_goal = request.args.get('shot_open_goal')
shot_follows_dribble = request.args.get('shot_follows_dribble')
shot_redirect = request.args.get('shot_redirect')
shooter_x, shooter_y = shooter.split(',')
shooter_x = float(shooter_x)
shooter_y = float(shooter_y)
print("minuta: ", minute)
print("pozycja x1 strzelca: ", shooter_x)
print("pozycja y1 strzelca: ", shooter_y)
print("czesc ciala: " + body_part)
print("technika: " + technique)
print("typ akcji: " + acionType)
# lista wspolzawodnikow oraz przeciwnikow
# lista atakujacy oraz obroncy
teamMatesList = request.args.get('defenders')
opponentsList = request.args.get('strickers')
def konwertujDoListy(listaString):
listaString = listaString.split(",")
listaFloat = []
for elem in listaString:
listaFloat.append(float(elem))
return listaFloat
def zmienWMaciez(lista):
maciez = []
for i in range(0,len(lista),2):
player = [float(lista[i]),float(lista[i+1])]
maciez.append(player)
if(len(maciez) < 10):
for i in range(len(maciez),11,1):
maciez.append([np.nan,np.nan])
return maciez
obroncy = request.args.get('defenders')
atakujacy = request.args.get('strickers')
print("wspolrzedne obroncow: ", obroncy)
if obroncy == "":
obroncy_macierz = [[np.nan, np.nan]]
else:
obroncy_lista = konwertujDoListy(obroncy)
obroncy_macierz = zmienWMaciez(obroncy_lista)
print("wspolrzedne obroncow: " + teamMatesList)
print("wspolrzedne przeciwnikow: " + opponentsList)
if atakujacy == "":
atakujacy_macierz = [[np.nan, np.nan]]
else:
atakujacy_lista = konwertujDoListy(atakujacy)
atakujacy_macierz = zmienWMaciez(atakujacy_lista)
if gameMinute == "":
gameMinute = 1.0 # to change
# Bramkarz
goalkepper = "2,2"
#goalkepper = request.args.get('goalkeeper')
print("wspolrzedne obroncow: ", obroncy)
print("wspolrzedne atakujacych: ", atakujacy)
def euclidean_distance(point1, point2):
"""Calculate the Euclidean distance between two points."""
return math.sqrt((point1[0] - point2[0])**2 + (point1[1] - point2[1])**2)
def sort_coordinates_by_distance(coordinates, reference_point):
"""Sort a list of coordinates based on Euclidean distance from a reference point.
Coordinates with NaN values are placed at the end of the list.
"""
def distance_or_inf(coord):
"""Helper function to handle coordinates with NaN values."""
if hasattr(coord, '__iter__') and len(coord) >= 2:
if np.isnan(coord[0]) or np.isnan(coord[1]):
return float('inf') # Set distance to infinity for NaN coordinates
return euclidean_distance(coord, reference_point)
return float('inf') # Set distance to infinity for non-iterable coordinates
sorted_coordinates = sorted(coordinates, key=distance_or_inf)
if(len(sorted_coordinates) < 10):
for i in range(len(sorted_coordinates),11,1):
sorted_coordinates.append([np.nan,np.nan])
return sorted_coordinates
print("bramkarz: " + str(goalkepper) )
# POSORTOWANI OBRONCY I ATAKUJACY
posortowani_obroncy = sort_coordinates_by_distance(obroncy_macierz, [shooter_x, shooter_y])
posortowani_atakujacy = sort_coordinates_by_distance(atakujacy_macierz, [shooter_x, shooter_y])
response = xgboost_predict_proba_v2(shooter = shooter,
opponentsList = opponentsList, teamMatesList = teamMatesList ,minute = 20, position_name = position_name, shot_body_part_name = body_part, shot_technique_name = technique,
shot_type_name = acionType, shot_first_time = False,
shot_aerial_won = False, shot_deflected = False, shot_open_goal = False,
shot_follows_dribble = False, shot_redirect = False, shot_kick_off = False, goalkeeper= goalkepper
)
print("Posortowani obroncy: ", posortowani_obroncy)
print("Posortowani atakujacy: ", posortowani_atakujacy)
number_of_players_opponents = float(np.sum(~np.isnan(posortowani_obroncy).all(axis=1)))
number_of_players_teammates = float(np.sum(~np.isnan(posortowani_atakujacy).all(axis=1)))
print("Liczba obroncow:", number_of_players_opponents)
print("Liczba atakujacych:", number_of_players_teammates)
## add angle, match minutes and number of players
def loc2angle(x, y):
rads = math.atan(7.32 * x / (x**2 + (y - 34)**2 - (7.32/2)**2))
rads = math.pi + rads if rads < 0 else rads
deg = math.degrees(rads)
return deg
def loc2distance(x, y):
return math.sqrt(x**2 + (y - 34)**2)
angle = loc2angle(x = shooter_x, y = shooter_y)
dist = loc2distance(x = shooter_x, y = shooter_y)
# BRAMKARZ
goalkepper = request.args.get('goalkeeper')
if goalkepper == "null":
goalkepper_x, goalkepper_y = np.nan, np.nan
else:
goalkepper_x, goalkepper_y = goalkepper.split(',')
goalkepper_x = float(goalkepper_x)
goalkepper_y = float(goalkepper_y)
print("bramkarz:", goalkepper_x, goalkepper_y)
if shot_first_time == 'true':
shot_first_time = True
else:
shot_first_time = False
if shot_one_on_one == 'true':
shot_one_on_one = True
else:
shot_one_on_one = False
if shot_aerial_won == 'true':
shot_aerial_won = True
else:
shot_aerial_won = False
if shot_open_goal == 'true':
shot_open_goal = True
else:
shot_open_goal = False
if shot_follows_dribble == 'true':
shot_follows_dribble = True
else:
shot_follows_dribble = False
if shot_redirect == 'true':
shot_redirect = True
else:
shot_redirect = False
#### CHECKLIST
print('CHECKLISTA')
print('shot_first_time', shot_first_time)
print('shot_one_on_one', shot_one_on_one)
print('shot_aerial_won', shot_aerial_won)
print('shot_open_goal', shot_open_goal)
print('shot_follows_dribble', shot_follows_dribble)
print('shot_redirect', shot_redirect)
# MODEL XGBOOST
response = xgboost_predict_proba(minute=int(gameMinute), #minute=0,
position_name=position_name,
shot_body_part_name=body_part,
shot_technique_name=technique,
shot_type_name=acionType,
shot_first_time=shot_first_time,
shot_one_on_one=shot_one_on_one,
shot_aerial_won=shot_aerial_won,
shot_open_goal=shot_open_goal,
shot_follows_dribble=shot_follows_dribble,
shot_redirect=shot_redirect,
x1=shooter_x, y1=shooter_y,
number_of_players_opponents=number_of_players_opponents,
number_of_players_teammates=number_of_players_teammates,
angle=angle, distance=dist,
x_player_opponent_Goalkeeper=goalkepper_x, y_player_opponent_Goalkeeper=goalkepper_y,
x_player_opponent_1=posortowani_obroncy[0][0], y_player_opponent_1=posortowani_obroncy[0][1],
x_player_opponent_2=posortowani_obroncy[1][0], y_player_opponent_2=posortowani_obroncy[1][1],
x_player_opponent_3=posortowani_obroncy[2][0], y_player_opponent_3=posortowani_obroncy[2][1],
x_player_opponent_4=posortowani_obroncy[3][0], y_player_opponent_4=posortowani_obroncy[3][1],
x_player_opponent_5=posortowani_obroncy[4][0], y_player_opponent_5=posortowani_obroncy[4][1],
x_player_opponent_6=posortowani_obroncy[5][0], y_player_opponent_6=posortowani_obroncy[5][1],
x_player_opponent_7=posortowani_obroncy[6][0], y_player_opponent_7=posortowani_obroncy[6][1],
x_player_opponent_8=posortowani_obroncy[7][0], y_player_opponent_8=posortowani_obroncy[7][1],
x_player_opponent_9=posortowani_obroncy[8][0], y_player_opponent_9=posortowani_obroncy[8][1],
x_player_opponent_10=posortowani_obroncy[9][0], y_player_opponent_10=posortowani_obroncy[9][1],
x_player_teammate_Goalkeeper=np.nan, y_player_teammate_Goalkeeper=np.nan,
x_player_teammate_1=posortowani_atakujacy[0][0], y_player_teammate_1=posortowani_atakujacy[0][1],
x_player_teammate_2=posortowani_atakujacy[1][0], y_player_teammate_2=posortowani_atakujacy[1][1],
x_player_teammate_3=posortowani_atakujacy[2][0], y_player_teammate_3=posortowani_atakujacy[2][1],
x_player_teammate_4=posortowani_atakujacy[3][0], y_player_teammate_4=posortowani_atakujacy[3][1],
x_player_teammate_5=posortowani_atakujacy[4][0], y_player_teammate_5=posortowani_atakujacy[4][1],
x_player_teammate_6=posortowani_atakujacy[5][0], y_player_teammate_6=posortowani_atakujacy[5][1],
x_player_teammate_7=posortowani_atakujacy[6][0], y_player_teammate_7=posortowani_atakujacy[6][1],
x_player_teammate_8=posortowani_atakujacy[7][0], y_player_teammate_8=posortowani_atakujacy[7][1],
x_player_teammate_9=posortowani_atakujacy[8][0], y_player_teammate_9=posortowani_atakujacy[8][1],
x_player_teammate_10=posortowani_atakujacy[9][0], y_player_teammate_10=posortowani_atakujacy[9][1])
# response = xgboost_predict_proba(shooter = shooter,
# opponentsList = opponentsList, teamMatesList = teamMatesList, minute = 20, position_name = position_name, shot_body_part_name = body_part, shot_technique_name = technique,
# shot_type_name = acionType, shot_first_time = False,
# shot_aerial_won = False, shot_deflected = False, shot_open_goal = False,
# shot_follows_dribble = False, shot_redirect = False, shot_kick_off = False, goalkeeper= goalkepper
# )
#print(response)
res = str(response)

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -4,19 +4,55 @@
@tailwind components;
@tailwind utilities;
.Ex{
display: block; /* Może być inline-block, jeśli preferujesz */
margin: 20px auto; /* Centralnie i z marginesem */
padding: 10px;
background-color: #4CAF50; /* Przykładowy kolor tła */
color: white; /* Kolor tekstu */
text-align: center;
border-radius: 5px; /* Lekko zaokrąglone rogi */
font-size: 20px; /* Duża, czytelna czcionka */
font-weight: bold; /* Pogrubienie dla lepszej widoczności */
width: 50%; /* Dostosuj szerokość zgodnie z potrzebami */
/* Dodatkowe style, takie jak cienie, mogą być dodane */
}
.Ex {
display: block; /* Może być inline-block, jeśli preferujesz */
margin: 20px auto; /* Centralnie i z marginesem */
padding: 10px;
background-color: #4CAF50; /* Przykładowy kolor tła */
color: white; /* Kolor tekstu */
text-align: center;
border-radius: 5px; /* Lekko zaokrąglone rogi */
font-size: 20px; /* Duża, czytelna czcionka */
font-weight: bold; /* Pogrubienie dla lepszej widoczności */
width: 100%; /* Poszerzone pole */
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.5); /* Cień dla dodatkowej głębi */
/* Opcjonalnie, można dodać gradient tła dla większego efektu */
background-image: linear-gradient(to right, #32CD32 , #4CAF50);
transition: transform 0.3s ease; /* Delikatna animacja */
}
.Ex:hover {
transform: scale(1.10); /* Efekt powiększenia przy najechaniu */
}
.xg-meter {
width: 200px;
height: 100px; /* Zmiana wysokości, aby pasowała do proporcji bramki */
display: flex;
align-items: center;
justify-content: center;
text-align: center;
color: white;
font-size: 48px;
font-weight: bold;
background: url('assets/bramka.jpeg') no-repeat center center; /* Tło z obrazem bramki */
background-size: cover; /* Dopasowanie obrazu do rozmiaru elementu */
border-radius: 10px; /* Opcjonalnie, dla zaokrąglonych rogów */
}
.xg-value {
display: block;
background: rgba(0, 0, 0, 0.5); /* Półprzezroczyste tło dla lepszej czytelności tekstu */
padding: 5px 10px; /* Dodanie odstępu */
border-radius: 5px; /* Zaokrąglone rogi dla tekstu */
}
/* Funkcja JavaScript będzie sterować stopniem gradientu */
body {
margin: 50px;
display: grid;
@ -25,7 +61,7 @@
grid-template-rows: auto;
grid-template-columns: auto auto auto;
}
.container {
display: flex;
flex-direction: column;
@ -49,19 +85,20 @@
max-height: 100%;
}
.container span {
display: block;
}
.main-content {
display: flex;
justify-content: space-between;
align-items: center;
}
.main-content {
display: flex;
justify-content: space-between;
align-items: center;
}
.player{
width: inherit;
height: 8vh;
@ -84,7 +121,7 @@
background-color: #cccccc;
justify-content: space-between;
}
.subMenu {
display: grid;
grid-template-rows: auto auto auto;
@ -95,14 +132,15 @@
background-color: #f0f0f0; /* Example background color */
z-index: 1000; /* Ensure it stays on top of other content */
}
.player-list{
.player-list {
background-color: rgb(61, 38, 38);
width: 13vw;
height: calc(50vw*68/105);
overflow: scroll;
font-size: 12px; /* Example font size - adjust as needed */
}
.top-bar {
display: flex;
justify-content: space-between;
@ -112,7 +150,7 @@
/* Możesz dodać dodatkowe style, jak tło, obramowanie itp. */
z-index: 2;
}
.bottom-bar {
display: flex;
justify-content: space-between; /* Rozmieszcza przyciski równomiernie */
@ -128,7 +166,7 @@
border-radius: 50%;
position: absolute
}
.reset-button {
position: relative;
margin: 5px;
@ -200,7 +238,7 @@
color: #000000;
font-size: 16px;
}
.cho-first_time {
position: relative;
padding: 10px;
@ -237,7 +275,38 @@
color: #000000;
font-size: 16px;
}
.additional-parameters {
position: relative; /* Or absolute, depending on layout */
right: 0;
top: 30%; /* Adjusted to a higher position */
width: 250px; /* Increased width */
background-color: #000000;
padding: 15px; /* Increased padding */
border: 1px solid #ddd;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
z-index: 100; /* To ensure it stays on top */
color: #ffffff; /* Optional: change text color for better visibility on dark background */
}
.additional-parameters h3 {
margin-top: 0;
font-size: 18px; /* Increased font size for heading */
}
.additional-parameters label {
display: flex; /* Updated to flex for better alignment */
align-items: center; /* Aligns checkbox and label text vertically */
margin-bottom: 10px; /* Increased spacing between checkboxes */
font-size: 16px; /* Increased font size for labels */
}
.additional-parameters input[type="checkbox"] {
margin-right: 10px; /* Adds spacing between checkbox and label text */
}
/* DROPDOWNS */
/* Style the dropdown button */
.dropbtn {
@ -253,13 +322,13 @@
.dropbtn:hover, .dropbtn:focus {
background-color: #3e8e41;
}
/* The container <div> - needed to position the dropdown content */
.dropdown {
position: relative;
display: inline-block;
}
.cho-dropdown_body_part {
display: none;
position: absolute;
@ -268,7 +337,7 @@
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
.cho-dropdown_body_part a{
color: black;
padding: 12px 16px;
@ -276,15 +345,15 @@
display: block;
font-size: 16px;
}
/* Change color of dropdown links on hover */
.cho-dropdown_body_part a:hover {background-color: #f1f1f1}
/* Show the dropdown menu on hover */
.dropdown:hover .cho-dropdown_body_part {
display: block;
}
.cho-dropdown_position_name {
display: none;
position: absolute;
@ -293,7 +362,7 @@
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
.cho-dropdown_position_name a {
color: black;
padding: 12px 16px;
@ -301,15 +370,15 @@
display: block;
font-size: 16px;
}
/* Change color of dropdown links on hover */
.cho-dropdown_position_name a:hover {background-color: #f1f1f1}
/* Show the dropdown menu on hover */
.dropdown:hover .cho-dropdown_position_name {
display: block;
}
.cho-dropdown_technique_name {
position: relative;
display: none;
@ -319,7 +388,7 @@
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
.cho-dropdown_technique_name a {
color: black;
padding: 12px 16px;
@ -327,15 +396,15 @@
display: block;
font-size: 16px;
}
/* Change color of dropdown links on hover */
.cho-dropdown_technique_name a:hover {background-color: #f1f1f1}
/* Show the dropdown menu on hover */
.dropdown:hover .cho-dropdown_technique_name {
display: block;
}
.cho-dropdown_type_name {
display: none;
position: absolute;
@ -344,7 +413,7 @@
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
.cho-dropdown_type_name a {
color: black;
padding: 12px 16px;
@ -352,16 +421,16 @@
display: block;
font-size: 16px;
}
/* Change color of dropdown links on hover */
.cho-dropdown_type_name a:hover {background-color: #f1f1f1}
/* Show the dropdown menu on hover */
.dropdown:hover .cho-dropdown_type_name {
display: block;
}
/* MANUAL INPUT */
.cho-minute {
margin-top: 10px;
@ -574,5 +643,5 @@
-2.6em 0em 0 0em rgba(255, 255, 255, 0.7), -1.8em -1.8em 0 0em #ffffff;
}
}

BIN
data/.DS_Store vendored

Binary file not shown.

File diff suppressed because it is too large Load Diff

82822
data/final_data_new.csv Normal file

File diff suppressed because it is too large Load Diff

38343
data/final_data_old.csv Normal file

File diff suppressed because it is too large Load Diff

BIN
notebooks/.DS_Store vendored

Binary file not shown.

View File

@ -11,33 +11,33 @@ library(purrr)
# code and data from https://github.com/Dato-Futbol/xg-model
get_shots <- function(file_path, name_detail, save_files = F){
players <- fromJSON("data/players.json")
shots <- fromJSON(file_path) %>%
filter(subEventName == "Shot")
tags <- tibble(tags = shots$tags) %>%
hoist(tags,
hoist(tags,
tags_id = "id") %>%
unnest_wider(tags_id, names_sep = "")
tags2 <- tags %>%
mutate(is_goal = ifelse(rowSums(. == "101", na.rm = T) > 0, 1, 0),
is_blocked = ifelse(rowSums(. == "2101", na.rm = T) > 0, 1, 0),
is_CA = ifelse(rowSums(. == "1901", na.rm = T) > 0, 1, 0), # is countre attack
body_part = ifelse(rowSums(. == "401", na.rm = T) > 0, "left",
ifelse(rowSums(. == "402", na.rm = T) > 0, "right",
body_part = ifelse(rowSums(. == "401", na.rm = T) > 0, "left",
ifelse(rowSums(. == "402", na.rm = T) > 0, "right",
ifelse(rowSums(. == "403", na.rm = T) > 0, "head/body", "NA"))))
pos <- tibble(positions = shots$positions) %>%
hoist(positions,
hoist(positions,
y = "y",
x = "x") %>%
unnest_wider(y, names_sep = "") %>%
unnest_wider(x, names_sep = "") %>%
dplyr::select(-c(x2, y2))
shots_ok <- shots %>%
dplyr::select(matchId, teamId, playerId, eventSec, matchPeriod) %>%
bind_cols(pos, tags2) %>%
@ -46,14 +46,14 @@ get_shots <- function(file_path, name_detail, save_files = F){
left_join(players %>%
dplyr::select(c("wyId", "foot")), by = c("playerId" = "wyId")) %>%
mutate(league = name_detail)
if(save_files){
write_rds(shots, paste0("shots", name_detail, ".rds"))
write_rds(tags2, paste0("tags2", name_detail, ".rds"))
write_rds(pos, paste0("pos", name_detail, ".rds"))
write_rds(shots_ok, paste0("unblocked_shots", name_detail, ".rds"))
}
shots_ok
}
# shotsEN <- get_shots("data/events/events_England.json", "EN")
@ -63,12 +63,12 @@ get_shots <- function(file_path, name_detail, save_files = F){
# shotsGE <- get_shots("data/events/events_Germany.json", "GE")
# shotsFR <- get_shots("data/events/events_France.json", "FR")
# shotsEC <- get_shots("data/events/events_European_Championship.json", "EC")
#
#
# shots <- shotsEN %>%
# bind_rows(shotsFR, shotsGE, shotsIT, shotsSP, shotsWC, shotsEC)
get_final_data <- function(data) {
data <- data %>% select(eventSec, y1, x1, is_goal, is_blocked, is_CA, body_part, foot)
data$x1 <- (100 - data$x1) * 105/100
data$y1 <- data$y1 * data$y1/100
@ -77,7 +77,7 @@ get_final_data <- function(data) {
data <- data %>% mutate(distance = sqrt( (100 - x1)^2 + (34 - y1)^2),
minute = round(eventSec / 60),
eventSec = round(eventSec))
data
}
@ -89,14 +89,14 @@ get_final_data <- function(data) {
get_data <- function(event_path, info_path) {
events <- read.csv(event_path)
info <- read.csv(info_path)
events <- merge(events, info[, c('id_odsp', 'country', 'date')], by = 'id_odsp', all.x = TRUE)
data <- subset(events, event_type == 1)
data_final <- data %>% select(sort_order, time, shot_place, shot_outcome, is_goal, location, bodypart, assist_method, situation,
fast_break)
data_final
}
# data2 <- get_data(event_path = "data/events.csv", info_path = "data/ginf.csv")
@ -124,18 +124,18 @@ loc2locdistance <- function(x1, y1, x2, y2) {
get_shots2 <- function(json_file) {
data <- fromJSON(json_file) %>% filter(type$name == "Shot") %>% dplyr::select(c(minute, position, location, shot))
df_temp <- do.call(rbind, lapply(data$location, function(loc) c(120, 80) - loc))
colnames(df_temp) <- c("x1", "y1")
data$x1 <- df_temp[,1]
data$y1 <- df_temp[,2]
data$shot$freeze_frame <- Map(function(ff, x1, y1) {
ff$x1 <- yd_to_m(x1)
ff$y1 <- yd_to_m(y1)
return(ff)
},
},
data$shot$freeze_frame, data$x1, data$y1)
tryCatch({
@ -148,17 +148,17 @@ get_shots2 <- function(json_file) {
df <- df %>% mutate(teammate = ifelse(teammate, "teammate", "opponent"),
distance = loc2locdistance(x1 = x, y1 = y, x2 = x1, y2 = y1)) %>%
arrange(distance)
groups_count <- df %>% group_by(teammate) %>% count() %>% as.data.frame()
if ( !("opponent" %in% groups_count$teammate) ) {
groups_count <- groups_count %>% add_row(teammate = "opponent", n = 0)
} else if ( !("teammate" %in% groups_count$teammate) ) {
groups_count <- groups_count %>% add_row(teammate = "teammate", n = 0)
}
na_df <- as.data.frame(matrix("na", nrow = 21 - nrow(df), ncol = ncol(df)))
colnames(na_df) <- colnames(df)
na_df$teammate <- rep(c("opponent", "teammate"), c(11, 10) - groups_count$n)
dff <- rbind(df, na_df)
dff <- dff %>% group_by(teammate) %>% mutate(rown = row_number(distance)) %>% ungroup() %>%
@ -170,9 +170,9 @@ get_shots2 <- function(json_file) {
dff <- as.data.frame(matrix("na", nrow = 21, ncol = 3))
colnames(dff) <- c("x", "y", "teammate")
dff$teammate <- rep(c("opponent", "teammate"), c(11, 10))
dff <- dff %>% group_by(teammate) %>% mutate(rown = row_number()) %>% ungroup() %>%
mutate(position_teammate = paste(teammate, rown, sep = "_")) %>%
select(-c(teammate, rown)) %>%
dff <- dff %>% group_by(teammate) %>% mutate(rown = row_number()) %>% ungroup() %>%
mutate(position_teammate = paste(teammate, rown, sep = "_")) %>%
select(-c(teammate, rown)) %>%
mutate(x = ifelse(x == "na", NA, x),
y = ifelse(x == "na", NA, y))
}
@ -181,7 +181,7 @@ get_shots2 <- function(json_file) {
# %>%
# stop("123")
wider_df <- dff %>%
pivot_wider(names_from = position_teammate, values_from = c(x, y), names_sep = "_player_") %>%
pivot_wider(names_from = position_teammate, values_from = c(x, y), names_sep = "_player_") %>%
mutate(across(everything(), as.numeric))
wider_df
# wider_df <- apply(wider_df, MARGIN = 2, unlist)
@ -193,7 +193,7 @@ get_shots2 <- function(json_file) {
print(paste("An error occurred:", e$message))
})
df_players_location <- df_players_location %>% t()
tryCatch({ # TODO reduce error cases
data$number_of_players_opponents <- mapply(function(sublist, x1_threshold) {
# Extracting the first location value and converting it to numeric
@ -213,12 +213,12 @@ get_shots2 <- function(json_file) {
# handle the error
print(paste("An error occurred:", e$message))
})
tryCatch({ # TODO reduce error cases
data$number_of_players_teammates <- mapply(function(sublist, x1_threshold) {
# Extracting the first location value and converting it to numeric
first_location_values <- sapply(sublist$location, function(loc) as.numeric(loc[1]))
if ("teammate" %in% names(sublist)) {
# Filtering and counting
res <- sum(sublist$teammate & first_location_values > x1_threshold) # error here
@ -233,71 +233,71 @@ get_shots2 <- function(json_file) {
# handle the error
print(paste("An error occurred:", e$message))
})
data$shot <- data$shot %>% select(-freeze_frame, -statsbomb_xg, -key_pass_id)
data$shot$body_part <- data$shot$body_part %>% select(-id)
data$shot$technique <- data$shot$technique %>% select(-id)
data$shot$type <- data$shot$type %>% select(-id)
data$position <- data$position %>% select(-id)
data$shot <- data$shot %>% select(-end_location)
tryCatch({ # TODO reduce error cases
if ("one_on_one" %in% colnames(data$shot)) {
data[is.na(data$shot$one_on_one), ]$shot$one_on_one <- FALSE
} else {
data$shot$one_on_one <- FALSE
}
if ("first_time" %in% colnames(data$shot)) {
data[is.na(data$shot$first_time), ]$shot$first_time <- FALSE
} else {
data$shot$first_time <- FALSE
}
if ("aerial_won" %in% colnames(data$shot)) {
data[is.na(data$shot$aerial_won), ]$shot$aerial_won <- FALSE
} else {
data$shot$aerial_won <- FALSE
}
if ("saved_to_post" %in% colnames(data$shot)) {
data[is.na(data$shot$saved_to_post), ]$shot$saved_to_post <- FALSE
} else {
data$shot$saved_to_post <- FALSE
}
if ("deflected" %in% colnames(data$shot)) {
data[is.na(data$shot$deflected), ]$shot$deflected <- FALSE
} else {
data$shot$deflected <- FALSE
}
if ("saved_off_target" %in% colnames(data$shot)) {
data[is.na(data$shot$saved_off_target), ]$shot$saved_off_target <- FALSE
} else {
data$shot$saved_off_target <- FALSE
}
if ("open_goal" %in% colnames(data$shot)) {
data[is.na(data$shot$open_goal), ]$shot$open_goal <- FALSE
} else {
data$shot$open_goal <- FALSE
}
if ("follows_dribble" %in% colnames(data$shot)) {
data[is.na(data$shot$follows_dribble), ]$shot$follows_dribble <- FALSE
} else {
data$shot$follows_dribble <- FALSE
}
if ("redirect" %in% colnames(data$shot)) {
data[is.na(data$shot$redirect), ]$shot$redirect <- FALSE
} else {
data$shot$redirect <- FALSE
}
if ("kick_off" %in% colnames(data$kick_off)) {
data[is.na(data$shot$kick_off), ]$shotf$kick_off <- FALSE
} else {
@ -308,21 +308,21 @@ get_shots2 <- function(json_file) {
# handle the error
print(paste("An error occurred:", e$message))
})
data <- data %>% mutate(is_goal = ifelse(shot$outcome$id == 97, 1, 0),
x1 = yd_to_m(x1) %>% round(., digits = 1),
y1 = yd_to_m(y1) %>% round(., digits = 1),
angle = loc2angle(x1, y1) %>% round(., digits = 1),
distance = loc2distance(x = x1, y = y1)) %>%
distance = loc2distance(x = x1, y = y1)) %>%
select(-location)
data$shot$outcome <- data$shot$outcome %>% select(-id)
data <- data %>% unnest(shot, names_sep = "_") %>%
unnest(position, names_sep = "_") %>%
unnest(shot_type, names_sep = "_") %>%
data <- data %>% unnest(shot, names_sep = "_") %>%
unnest(position, names_sep = "_") %>%
unnest(shot_type, names_sep = "_") %>%
unnest(shot_outcome, names_sep = "_") %>%
unnest(shot_technique, names_sep = "_") %>%
unnest(shot_technique, names_sep = "_") %>%
unnest(shot_body_part, names_sep = "_")
data <- cbind(data, df_players_location)
data
}
@ -338,12 +338,12 @@ skimr::skim(combined_data)
data3_final <- combined_data %>% select(-c(shot_outcome_name,
shot_saved_off_target,
shot_saved_to_post,
kick_off)) %>%
kick_off)) %>%
mutate(shot_kick_off = ifelse(is.na(shot_kick_off), FALSE, shot_kick_off))
pattern <- "^(x_player_|y_player_).*$"
cols <- names(data3_final)[grepl(pattern, names(data3_final))]
data_final <- data3_final %>% unnest(all_of(cols))
skimr::skim(data_final)
write_csv(data_final, file = "data/final_data.csv")
df_test <- read.csv("data/final_data.csv", nrows = 1000)
#df_test <- read.csv("data/final_data.csv", nrows = 10000)
##################### The fourth dataset ##############################

38343
notebooks/final_data.csv Normal file

File diff suppressed because it is too large Load Diff

82822
notebooks/final_data_new.csv Normal file

File diff suppressed because it is too large Load Diff

38343
notebooks/final_data_old.csv Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long