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.
Table of Contents
Related Topics
Quick Actions