diff --git a/.DS_Store b/.DS_Store index b06a9fd..4b2dabf 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/app/src/assets/bramka.jpeg b/app/src/assets/bramka.jpeg new file mode 100644 index 0000000..b2040fd Binary files /dev/null and b/app/src/assets/bramka.jpeg differ diff --git a/app/src/components/Hero.jsx b/app/src/components/Hero.jsx index 5cdf92e..b61daee 100644 --- a/app/src/components/Hero.jsx +++ b/app/src/components/Hero.jsx @@ -148,18 +148,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 = "Lokalizacja: " + 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 @@ -219,6 +219,7 @@ const Hero = () => { //var shooterX = konwerturX(ball.style.left) //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(){ ball.style.background = pColor bojo.removeEventListener("mousemove", whileMove) @@ -229,6 +230,11 @@ const Hero = () => { }) } + function updateXGMeter(xgValue) { + var xgMeter = document.querySelector('.xg-meter'); + var greenIntensity = xgValue * 100; // Zakładając, że xgValue jest między 0 a 1 + //xgMeter.style.background = `linear-gradient(to top, #006400 ${greenIntensity}%, #90EE90)`; +} // // Wyłanie zapytania do serwera @@ -236,6 +242,7 @@ const Hero = () => { ///Dziwny Blad loadPlayers() if (number_of_shooters == 1) { + console.log('Wysyłanie wartości: ', bodyPart, technique); // 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( res => res.json() @@ -245,7 +252,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); @@ -275,6 +283,7 @@ 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 ){ addPlayer(0,ball) @@ -283,7 +292,6 @@ const Hero = () => { setNumberOfShooters(number_of_shooters+1) }else{alert("mozesz dodac tylko jednego strzelca")} }else if(active_bbt == "bbt2"){ - if ( number_of_goalkeepers < 1){ addPlayer(1,ball) bojo.appendChild(ball) @@ -358,7 +366,7 @@ const Hero = () => { - + @@ -371,18 +379,37 @@ const Hero = () => { -
setPossition(event.target.value)} defaultValue={shooterPossition}>
@@ -410,6 +437,36 @@ const Hero = () => { +
+

Parametry strzału

+ + + + + + +
+ + + {/*
@@ -436,13 +493,11 @@ const Hero = () => {
-
- - - +
+ +
- ); }; diff --git a/app/src/components/Loader.jsx b/app/src/components/Loader.jsx index 4abbec8..1153e4e 100644 --- a/app/src/components/Loader.jsx +++ b/app/src/components/Loader.jsx @@ -3,6 +3,7 @@ import React from 'react' const Loader = () => { return (
Loader
+ ) } diff --git a/app/src/flask-server/modele/__pycache__/modele.cpython-39.pyc b/app/src/flask-server/modele/__pycache__/modele.cpython-39.pyc index 1361d5f..616f5ef 100644 Binary files a/app/src/flask-server/modele/__pycache__/modele.cpython-39.pyc and b/app/src/flask-server/modele/__pycache__/modele.cpython-39.pyc differ diff --git a/app/src/index.css b/app/src/index.css index 70a3c0b..6ea3dc1 100644 --- a/app/src/index.css +++ b/app/src/index.css @@ -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: fixed; /* 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
- 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; } - + } diff --git a/notebooks/dataCleaning.R b/notebooks/dataCleaning.R index 29aa883..3d5ef73 100644 --- a/notebooks/dataCleaning.R +++ b/notebooks/dataCleaning.R @@ -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 ##############################