IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    The Dynamics of the “Gentle Way”: Exploring Judo Attack Combinations as Networks in R

    Vinicius Bastazini发表于 2025-05-27 11:50:51
    love 0
    [This article was first published on R Code – Geekcologist, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
    Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

    As the Judo World Championship draws near this June in Budapest, it feels like the perfect time to bring together my passion for Judo (and Brazilian Jiu-Jitsu) with my gusto for complex network analyses — a fusion that’s been a long time in the making! While my posts typically focus on biodiversity-related topics and statistical modeling, I’ve long considered sharing some thoughts on one of my most cherished interests: Judo. This martial art, with its rich history and intricate techniques, has fascinated me since my childhood. Judo, which means the gentle way in Japanese, is at its competitive heart a dynamic “chess match” of throws, holds, submission techniques, and strategic combinations. While individual techniques (called waza) are foundational, the real artistry lies in how they are chained together — through renraku-waza  (combination techniques) and renzoku-waza (continuous combination techniques). Thus, in a Judo match, these individual techniques usually unfold as sequences of moves, often building toward a decisive action that is likely to result in a score.

    But how can we objectively analyze which attack combinations work best together? Which techniques serve as crucial setups, and which are reliable “killer moves”? This is where network analysis can offer us some insights.

    In this post, we’ll explore how to model combinations of Judo throwing techniques as a network using R, trying to uncover hidden patterns in attacking strategies. So, what we will be doing is treating each individual throwing technique as a node in a network, with an edge (or link) connecting two nodes when one technique naturally sets up or transitions into another as part of an attack sequence. In our Judo attack combination network we should be able to detect: i) which techniques are most frequently used to initiate successful combinations; ii) which techniques are common finishers, “killer moves”; iii) which techniques are most “influential” —or important— in the overall strategic attacking system?

    It is important to note that, this post is not intended as a comprehensive review of judo attack combinations; rather, it draws from some classic literature (Kashiwazaki and Nakanishi 1995, Kawaishi 1963, van Haesendonck 1968). I will focus exclusively on two-move attack sequences using only techniques currently recognized by the Kodokan, the temple of Judo. A more exhaustive analysis—particularly relevant for high-performance athletes—would require empirical data from competitions, a broader inclusion of technical variations, etc.

    In any case, I believe this post offers insights that will resonate with both martial arts enthusiasts and scientists interested in network analysis. For our ecologist readers, do not worry! I will provide links to some examples of ecological applications (EA) of these network analyses. You can also find more info in older network-related pots here.

    Let’s start by loading the necessary packages, building the network from the compiled data, and visualizing it as an interactive network, where you can choose one node, i.e., technique, and see all its relationships.

    ## Packages 
    require(igraph)
    require(ggplot2)
    require(dplyr)
    require(tidyr)
    require(RColorBrewer)
    require(bipartite) 
    require(bbmle)
    require(influential)
    require(visNetwork)
    
    # -----------------------------
    # 1. Build the Graph (directed)
    # -----------------------------
    cat("\n--- 1. Creating Directed Graph of Judo Attack Combinations ---\n")
    
    # Define attack transitions between judo techniques
    # Each line indicates a valid transition in a combination (directed from left to right)
    attack_combinations_igraph =graph.formula(
      Seoi.nage-+Seoi.otoshi,
      Seoi.nage-+O.uchi.gari,
      Seoi.nage-+Ko.uchi.gari,
      Ippon.seoi.nage-+Seoi.otoshi,
      Ippon.seoi.nage-+Ko.uchi.gari,
      Ippon.seoi.nage-+Osoto.gari,
      Harai.goshi-+Osoto.gari,
      Harai.goshi-+Uchi.mata,
      Harai.goshi-+Soto.makikomi,
      Uchi.mata-+O.uchi.gari,
      Uchi.mata-+Ko.uchi.gari,
      O.goshi-+O.uchi.gari,
      O.goshi-+Ko.uchi.gari,
      O.goshi-+Harai.goshi,
      O.uchi.gari-+Uchi.mata,
      O.uchi.gari-+Ko.uchi.gari,
      O.uchi.gari-+Osoto.gari,
      O.uchi.gari-+Tai.otoshi,
      O.uchi.gari-+Harai.goshi,
      Ko.uchi.gari-+O.uchi.gari,
      Ko.uchi.gari-+Seoi.nage,
      Ko.uchi.gari-+Ippon.seoi.nage,
      Ko.uchi.gari-+Hane.goshi,
      Osoto.gari-+Harai.goshi,
      Osoto.gari-+O.uchi.gari,
      Osoto.gari-+Ko.soto.gake,
      Osoto.gari-+Sasae.tsurikomi.ashi,
      Osoto.gari-+Okuri.ashi.harai,
      Osoto.gari-+Hiza.guruma,
      Ko.soto.gari-+Osoto.gari,
      Ko.soto.gari-+Tai.otoshi,
      Ko.soto.gari-+Harai.goshi,
      Hiza.guruma-+Harai.goshi,
      Hiza.guruma-+Sasae.tsurikomi.ashi,
      Hiza.guruma-+Osoto.gari,
      Hiza.guruma-+De.ashi.harai,
      Okuri.ashi.harai-+Sode.tsuri.komi.goshi,
      Okuri.ashi.harai-+Tai.otoshi,
      Okuri.ashi.harai-+Harai.goshi,
      Okuri.ashi.harai-+Ippon.seoi.nage,
      Okuri.ashi.harai-+Seoi.nage,
      Tai.otoshi-+Ko.uchi.gari,
      Tai.otoshi-+O.uchi.gari,
      Hikikomi.gaeshi-+O.uchi.gari,
      Hikikomi.gaeshi-+Ko.uchi.gari,
      Hikikomi.gaeshi-+Harai.goshi,
      Hikikomi.gaeshi-+Ko.soto.gari,
      Hikikomi.gaeshi-+Sukui.nage,
      Tsuri.komi.goshi-+O.uchi.gari,
      Tsuri.komi.goshi-+Sode.tsuri.komi.goshi,
      Hane.goshi-+O.uchi.gari,
      Sasae.tsurikomi.ashi-+Uchi.mata,
      Sasae.tsurikomi.ashi-+Tai.otoshi,
      De.ashi.harai-+Tai.otoshi,
      De.ashi.harai-+Yoko.gake,
      Hiza.guruma-+Ko.soto.gake,
      Hiza.guruma-+Hane.goshi,
      Ko.soto.gake-+Hane.goshi,
      Ko.soto.gake-+Ko.uchi.gari,
      Ko.uchi.gari-+Ko.uchi.makikomi,
      Uki.goshi-+O.uchi.gari,
      Uki.goshi-+Tsuri.goshi,
      Tsuri.goshi-+O.uchi.gari,
      Koshi.guruma-+Ashi.guruma,
      Harai.goshi-+O.uchi.gari,
      Hane.goshi-+Harai.goshi,
      Hane.goshi-+Hane.makikomi,
      Ushiro.goshi-+Tai.otoshi,
      Ushiro.goshi-+Ura.nage,
      Tsuri.komi.goshi-+Harai.goshi,
      Tsuri.komi.goshi-+Ko.uchi.gari,
      Uchi.mata-+Harai.goshi,
      Tai.otoshi-+Seoi.otoshi,
      Uki.otoshi-+O.uchi.gari,
      Uki.otoshi-+Tomoe.nage
      #Koshi.guruma-+Kani.bassami# since this is an illegl movement, I'm excluding it
    )
    
    # We will now manually add the self-loops, that is, moves that can follow themselves
    self_loops <- c(
      "Osoto.gari", "Osoto.gari",
      "Ippon.seoi.nage", "Ippon.seoi.nage",
      "Ko.soto.gari", "Ko.soto.gari",
      "Hiza.guruma", "Hiza.guruma",
      "Tai.otoshi", "Tai.otoshi",
      "Tsuri.komi.goshi", "Tsuri.komi.goshi"
    )
    attack_combinations_igraph <- add_edges(attack_combinations_igraph, self_loops)
    
    # Create a node data frame for use with visNetwork
    nodes <- data.frame(
      id = V(attack_combinations_igraph)$name,
      label = V(attack_combinations_igraph)$name,
      value = 15,  # All nodes same visual size
      color = "lightblue",
      font = list(color = "black")
    )
    
    # Extract edge list from the igraph object
    edges <- igraph::as_data_frame(attack_combinations_igraph, what = "edges")
    
    # -----------------------------
    # 2. Interactive Network Plot
    # -----------------------------
    cat("\n--- 2. Interactive Network Plot using visNetwork ---\n")
    
    # Build interactive graph with directional arrows and physics layout
    visNetwork(nodes, edges, main = "🥋 Judo Attack Combination Network") %>%
      visNodes(font = list(size = 18)) %>%
      visEdges(
        arrows = "to",  # Show arrowheads
        color = list(color = "black", highlight = "black", hover = "black")
      ) %>%
      visOptions(highlightNearest = TRUE, nodesIdSelection = TRUE) %>%
      visPhysics(
        solver = "forceAtlas2Based",
        forceAtlas2Based = list(gravitationalConstant = -50),
        stabilization = TRUE
      )
    
    🥋 Go to the interactive Judo attack combination network

    We will start our analyses by looking at degree centrality (EA1, EA2), a node-level metric that quantifies a technique’s direct importance within attack combinations by counting how many other techniques it either sets up (out-degree) or is preceded by (in-degree) (EA3, EA4). Specifically, in-degree quantifies how many different techniques commonly lead into a particular attack, marking it as a frequent follow-up move, a “finisher” attack. On the other hand, out-degree measures how many subsequent techniques a technique typically sets up, highlighting its versatility as an initial move.

    # -----------------------------
    # 3. Degree Calculation
    # -----------------------------
    cat("\n--- 3. Calculating In, Out, and Total Degrees for Techniques ---\n")
    
    # Compute degrees for each node
    node_names <- V(attack_combinations_igraph)$name
    in_degree <- degree(attack_combinations_igraph, mode = "in")
    out_degree <- degree(attack_combinations_igraph, mode = "out")
    total_degree <- degree(attack_combinations_igraph, mode = "all")
    
    # Create data frame summarizing degrees
    degree_df <- data.frame(
      Technique = node_names,
      InDegree = in_degree,
      OutDegree = out_degree,
      TotalDegree = total_degree
    )
    
    # Output summary
    print("Degree Data for each Technique:")
    print(degree_df)
    
    # -----------------------------
    # 4. Plot Network - Node Size Proportional to Its Degree
    # -----------------------------
    cat("\n--- 4. Plotting Networks Based on Degree ---\n")
    
    # Set layout to be consistent across plots
    set.seed(42)
    layout_fr <- layout_with_fr(attack_combinations_igraph)
    
    # Plot with in-degree node sizes
    V(attack_combinations_igraph)$size <- in_degree * 2 + 5
    V(attack_combinations_igraph)$label <- V(attack_combinations_igraph)$name
    V(attack_combinations_igraph)$label.cex <- 0.7
    V(attack_combinations_igraph)$label.color <- "black"
    V(attack_combinations_igraph)$color <- "lightblue"
    E(attack_combinations_igraph)$arrow.size <- 0.4
    E(attack_combinations_igraph)$color <- "gray30"
    
    plot1 <- function() {
      plot(attack_combinations_igraph, layout = layout_fr, main = "In-Degree Network")
      legend("topleft", legend = c("Low Degree", "Medium", "High"),#add legend
             pt.cex = c(6, 10, 14) / 5, pch = 21, pt.bg = "lightblue", col = "black",
             bty = "n", title = "Degree Scale")##add legend
    }
    
    # Plot with out-degree node sizes
    V(attack_combinations_igraph)$size <- out_degree * 2 + 5
    
    plot2 <- function() {
      plot(attack_combinations_igraph, layout = layout_fr, main = "Out-Degree Network")
    }
    
    # Combined panel plot
    par(mfrow = c(1, 2), mar = c(1, 1, 4, 1))
    plot1()
    plot2()
    

    To facilitate the visualization of each technique, we can plot the data on in- and out-degree as a barplot:

    # -----------------------------
    # 5. Bar Plot of Degrees
    # -----------------------------
    cat("\n--- 5. Plotting Degree Bar Charts ---\n")
    
    # Transform data to long format for ggplot
    degree_df_long <- degree_df %>%
      pivot_longer(cols = c(InDegree, OutDegree),
                   names_to = "DegreeType",
                   values_to = "DegreeValue") %>%
      mutate(DegreeType = factor(DegreeType, levels = c("InDegree", "OutDegree")))
    
    # Create grouped bar chart
    degree_plot <- ggplot(degree_df_long, aes(x = reorder(Technique, -DegreeValue), y = DegreeValue, fill = DegreeType)) +
      geom_bar(stat = "identity", position = position_dodge(width = 0.9)) +
      scale_fill_brewer(palette = "Set2", name = "Degree Type", labels = c("In-Degree", "Out-Degree")) +
      labs(
        title = "Judo Technique Combination Degrees",
        subtitle = "In-degree: follow-up attack\nOut-degree: initiation attack",
        x = "Judo Technique",
        y = "Degree Count"
      ) +
      theme_minimal(base_size = 12) +
      theme(
        axis.text.x = element_text(angle = 65, hjust = 1, vjust = 1, size = 9),
        plot.title = element_text(hjust = 0.5, face = "bold", size = 16),
        plot.subtitle = element_text(hjust = 0.5, size = 10),
        legend.position = "top",
        panel.grid.major.x = element_blank(),
        panel.grid.minor.y = element_blank()
      ) +
      geom_text(aes(label = ifelse(DegreeValue > 0, DegreeValue, "")),
                position = position_dodge(width = 0.9), vjust = -0.25, size = 2.5)
    
    print(degree_plot)
    

    So we see that Ouchi-gari has the highest total degree and in-degree, indicating it’s both a common follow-up and a frequent endpoint in attack sequences. Meanwhile, Hiza-guruma and O-soto-gari have the highest out-degree, suggesting they are often used as initiating moves in combination attacks.

    Now, we will look at the cumulative degree distribution that illustrates the broader pattern of these connections (EA3, EA5, EA6), showing whether a few key techniques act as central hubs or if connections are more evenly spread across many techniques in combination sequences. We will now fit, three basic statistical models that can possibly describe the degree distribution: the power law, truncated power law, and exponential model. A power law distribution suggests that a small number of techniques are highly connected, participating in many combinations, while most techniques are only sparsely connected. This reflects a “rich-get-richer” dynamic, where techniques that already have many connections are more likely to gain additional ones. Such behavior is common in scale-free networks (see for instance EA5). On the other hand, a truncated power law follows a similar pattern but imposes a natural threshold, limiting the number of connections even for the most connected techniques. This implies that while preferential attachment may be present, constraints cap the dominance of any single technique. In contrast, an exponential distribution indicates that high-degree throwing moves are rare and the probability of a technique being highly connected declines rapidly. This model suggests a more uniform structure, compared to a power law model, where connections are distributed more evenly and there is no strong hub dominance. We will identify the “best-fitting” model based on the second-order Akaike Information Criterion (AICc).

    # -----------------------------
    # 6. Degree Distribution & Model Fitting
    # -----------------------------
    cat("\n--- 6. Degree Distribution & Model Comparison ---\n")
    
    # Compute cumulative degree distribution
    deg <- degree_distribution(attack_combinations_igraph, cumulative = TRUE, mode = "all")
    deg_table <- data.frame(Degree = 0:(length(deg) - 1), CumulativeProbability = deg)
    
    # Filter zero values
    deg_table <- deg_table[deg_table$Degree > 0 & deg_table$CumulativeProbability > 0, ]
    
    # Power-law
    pl_model <- nls(CumulativeProbability ~ a * Degree^(-b),
                    data = deg_table, start = list(a = 1, b = 2),
                    control = nls.control(warnOnly = TRUE))
    
    # Exponential model
    exp_model <- nls(CumulativeProbability ~ a * exp(-b * Degree),
                     data = deg_table, start = list(a = 1, b = 0.1),
                     control = nls.control(warnOnly = TRUE))
    
    # Truncated power-law
    tpl_model <- nls(CumulativeProbability ~ a * Degree^(-b) * exp(-c * Degree),
                     data = deg_table, start = list(a = 1, b = 1.5, c = 0.05),
                     control = nls.control(warnOnly = TRUE))
    
    # Compare models using second order Akaike information criterion (AICc)
    AICctab(pl_model, exp_model, tpl_model, nobs = length(deg), weights = TRUE, delta = TRUE, base = TRUE)
    
    # Plot with fitted models
    plot(deg_table$Degree, deg_table$CumulativeProbability, log = "xy", pch = 16,
         xlab = "Degree", ylab = "P(K ≥ k)", main = "Cumulative Degree Distribution")
    
    curve(coef(pl_model)[1] * x^(-coef(pl_model)[2]), add = TRUE, col = "blue", lwd = 2)
    curve(coef(exp_model)[1] * exp(-coef(exp_model)[2] * x), add = TRUE, col = "red", lwd = 2)
    curve(coef(tpl_model)[1] * x^(-coef(tpl_model)[2]) * exp(-coef(tpl_model)[3] * x),
          add = TRUE, col = "darkgreen", lwd = 2)
    
    legend("bottomleft", legend = c("Power-law", "Exponential", "Truncated PL"),
           col = c("blue", "red", "darkgreen"), lwd = 2)
    
    

    Based on model selection using AICc, the truncated power law provided the best fit for the degree distribution, suggesting that while a few techniques are highly connected within attack sequences, there’s a natural limit to how dominant any single technique can be.

    Now, we will refine our understanding of which techniques are most critical, by calculating the Integrated Value of Influence (IVI)  (EA7, EA8) for each technique. The IVI algorithm estimates the importance of nodes in a network – in our case, specific Judo throwing techniques – by combining the most important topological features of the network formed by these techniques. The IVI is the synergistic product of local, semi-local, and global network centrality measures, capable of identifying the most “regulatory” or pivotal techniques within the attack combination network. Thus, the most ‘influential’ techniques (those with the highest IVI values) are those that simultaneously exhibit high levels of “hubness” and a strong potential to direct or facilitate the flow of successful attack combinations.

    # -----------------------------
    # 7. IVI (Integrated Value of Influence)
    # -----------------------------
    cat("\n--- 7. Calculating IVI Centrality ---\n")
    
    Graph_IVI = ivi(attack_combinations_igraph, mode = "all")
    
    cent_network.vis(
      graph = attack_combinations_igraph,
      cent.metric = Graph_IVI,
      legend.title = "IVI",
      plot.title = "Attack Combination Network – IVI",
      layout = "kk",
      dist.power = 1.5,
      legend.position = "right",
      boxed.legend = TRUE,
      show.labels = TRUE
    )
    

    Based on the integrated value of influence, we can see t that Ouchi-gari has the highest influence in the network, followed by Harai-goshi and Hiza Guruma. Most of the other moves have very low values of IVI. This indicates that these techniques, foot throwing techniques (Ashi-waza), play a central role in shaping the overall structure of attack combination strategies.

    At last, we will search for underlying strategic groupings within our Judo network, using the walk trap algorithm for community identification (EA9, EA10). This algorithm works by simulating short random walks starting from different techniques (nodes) in the network. The fundamental idea is that these random walks are more likely to get ‘trapped’ within densely connected groups of techniques – our “communities”of nodes. The algorithm hierarchically merges nodes to identify clusters of techniques that are more frequently used in conjunction, potentially representing distinct strategic approaches.

    # -----------------------------
    # 8. Community Detection
    # -----------------------------
    cat("\n--- 8. Community Detection using Edge Betweenness ---\n")
    
    ceb = cluster_walktrap(attack_combinations_igraph)
    V(attack_combinations_igraph)$color <- rainbow(length(ceb))[membership(ceb)]
    V(attack_combinations_igraph)$label <- V(attack_combinations_igraph)$name
    V(attack_combinations_igraph)$label.cex <- 0.7
    V(attack_combinations_igraph)$label.color <- "black"
    V(attack_combinations_igraph)$size <- 12
    E(attack_combinations_igraph)$arrow.size <- 0.4
    E(attack_combinations_igraph)$color <- "gray40"
    
    par(mar = c(0.5, 0.5, 0.5, 0.5))
    layout_fr <- layout_with_fr(attack_combinations_igraph)
    
    plot(ceb, attack_combinations_igraph, layout = layout_fr,
         main = "Technique Clusters")
    legend("topright", legend = paste("Cluster", 1:length(ceb)),
           col = rainbow(length(ceb)), pch = 21, pt.bg = rainbow(length(ceb)),
           bty = "n", cex = 0.8)
    
    

    We can identify 9 clusters of techniques within our attack combination network. Most clusters were small, but two stood out as larger, more cohesive groups: The first cluster features techniques like Seoi-nage, Tai-otoshi, and Seoi-otoshi, being dominated by hand throwing techniques (Te-waza), while the the second cluster includes O-uchi-gari, Osoto-gari, Uchi-mata, and Harai-goshi, is dominated by powerful foot throwing techniques (Ashi-waza). A more detailed analysis could help identify the factors behind these groupings — such as biomechanical similarities, preferred grips, or common tactical setups.

    References

    Kashiwazaki, K., Nakanishi, H. (1995). Attacking Judo: A Guide to Combinations and Counters. Ippon Books.

    Kawaishi, M. (1963). Standing judo: The combinations and counter-attacks. Budoworks.

    van Haesendonck, F.M. (1968) Judo: Ecyclopédie par l’Image. Éditions Erasme.

    To leave a comment for the author, please follow the link and comment on their blog: R Code – Geekcologist.

    R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
    Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
    Continue reading: The Dynamics of the “Gentle Way”: Exploring Judo Attack Combinations as Networks in R


沪ICP备19023445号-2号
友情链接