Defensive Line Analysis

Beginner 10 min read 1 views Nov 27, 2025
# Overview Analyze defensive structure including line height, compactness, and pressing intensity to evaluate defensive organization. ## Python Implementation ```python import pandas as pd import numpy as np import matplotlib.pyplot as plt # Load defensive tracking data defensive_data = pd.read_csv('defensive_tracking.csv') # Calculate defensive line metrics def calculate_defensive_metrics(frame_data): defenders = frame_data[frame_data['position'].isin(['CB', 'LB', 'RB'])] line_height = defenders['y_position'].mean() line_width = defenders['x_position'].max() - defenders['x_position'].min() compactness = defenders[['x_position', 'y_position']].std().mean() return { 'line_height': line_height, 'line_width': line_width, 'compactness': compactness } # Analyze by match phase defensive_metrics = defensive_data.groupby(['match_id', 'phase']).apply( lambda x: pd.Series(calculate_defensive_metrics(x)) ).reset_index() # Compare defensive phases phase_comparison = defensive_metrics.groupby('phase').agg({ 'line_height': ['mean', 'std'], 'line_width': ['mean', 'std'], 'compactness': ['mean', 'std'] }) print("Defensive Organization by Phase:") print(phase_comparison) # Pressing intensity analysis pressing_events = defensive_data[defensive_data['event_type'] == 'press'] pressing_intensity = pressing_events.groupby(['match_id', 'half']).size().reset_index(name='press_count') pressing_intensity['presses_per_minute'] = pressing_intensity['press_count'] / 45 print("\nPressing Intensity:") print(pressing_intensity.groupby('half')['presses_per_minute'].describe()) # Visualize defensive line height over time plt.figure(figsize=(12, 6)) for phase in defensive_metrics['phase'].unique(): phase_data = defensive_metrics[defensive_metrics['phase'] == phase] plt.plot(phase_data.index, phase_data['line_height'], label=phase, alpha=0.7) plt.title('Defensive Line Height by Match Phase') plt.xlabel('Time Period') plt.ylabel('Average Line Height') plt.legend() plt.grid(True, alpha=0.3) plt.tight_layout() plt.show() ``` ## R Implementation ```r library(dplyr) library(ggplot2) # Load defensive tracking data defensive_data <- read.csv("defensive_tracking.csv") # Calculate defensive metrics calculate_defensive_metrics <- function(data) { defenders <- data %>% filter(position %in% c("CB", "LB", "RB")) data.frame( line_height = mean(defenders$y_position), line_width = max(defenders$x_position) - min(defenders$x_position), compactness = mean(c(sd(defenders$x_position), sd(defenders$y_position))) ) } # Analyze by match phase defensive_metrics <- defensive_data %>% group_by(match_id, phase) %>% do(calculate_defensive_metrics(.)) %>% ungroup() # Compare phases phase_comparison <- defensive_metrics %>% group_by(phase) %>% summarise( avg_line_height = mean(line_height), sd_line_height = sd(line_height), avg_line_width = mean(line_width), sd_line_width = sd(line_width), avg_compactness = mean(compactness), sd_compactness = sd(compactness), .groups = "drop" ) print("Defensive Organization by Phase:") print(phase_comparison) # Pressing intensity pressing_events <- defensive_data %>% filter(event_type == "press") pressing_intensity <- pressing_events %>% group_by(match_id, half) %>% summarise(press_count = n(), .groups = "drop") %>% mutate(presses_per_minute = press_count / 45) print("\nPressing Intensity Summary:") print(pressing_intensity %>% group_by(half) %>% summarise( mean_ppm = mean(presses_per_minute), sd_ppm = sd(presses_per_minute), .groups = "drop" )) # Visualize ggplot(defensive_metrics, aes(x = seq_along(phase), y = line_height, color = phase)) + geom_line(alpha = 0.7) + labs( title = "Defensive Line Height by Match Phase", x = "Time Period", y = "Average Line Height" ) + theme_minimal() + theme(legend.position = "bottom") ```

Discussion

Have questions or feedback? Join our community discussion on Discord or GitHub Discussions.