Skip to main content

The Competition Data Standard

The data standard

The IRW competition data standard is meant to describe data derived from pairwise comparisons or competitions. Such data are widely analyzed using Elo or Bradley-Luce-Terry approaches; more information about these approaches is available here. The key distinction between these data and the conventional IRW data is that there are not id and item identifiers here but rather identifiers of the two agents that are involved in a given competition.

These tables form the competitions data family (source = "comp"). Despite the name, the family covers more than contests between teams, players or models: it also holds choices between two fixed things, such as essays judged against each other or votes between two named options, where the same named entities are compared again and again. When the things compared are instead put together at random from a set of attributes for each comparison, the data come from a conjoint experiment and belong to the conjoint family.

  • agent_a name/id of first competitor
  • agent_b name/id of second competitor
  • date Time of the data point in UNIX format.
  • homefield Indicator of agent that had advantage based on game features (e.g., where game was played, who played first, etc).
  • score_a Score of agent_a.
  • score_b Score of agent_b.
  • winner Winner of the competition (typically based on a comparison of scores). Values will be agent_a, agent_b or draw.

Additional information that may be predictive of the outcome can be included as additional columns.

Which agent is listed first

In some tables the two agents are listed in outcome order: agent_a is the winner by construction, so winner is agent_a in every row and the outcome is carried by the ordering rather than by the column. This is the native form of the source for dominance observations, where an interaction is recorded as a winner and a loser, and for comparative judgement, where it is recorded as the option chosen and the option passed over. As of October 2026 it is how 36 of the family’s 119 tables are built, among them every animal dominance table.

Elo and Bradley-Terry fits are unaffected, since a winner-loser dyad is what they take. Two other things do follow. Code that symmetrises or shuffles the pair before fitting will destroy the outcome, and winner is a constant column in these tables, so it cannot be used to split, filter or weight them. Most of them also carry no score_a/score_b, which leaves the ordering as the only record of who won; the Elo recipe below, keyed on score(score_a, score_b), does not apply to those tables.

Where an agent is never beaten, or never wins, its Bradley-Terry strength has no finite maximum-likelihood estimate. This is a property of the dominance structure rather than of the ordering convention, and BTm(..., br = TRUE) handles it; see the worked example below.

Before looping a model across the family, length(unique(df$winner)) == 1 identifies the tables that use this convention.

Accessing the competition data

The competitions data can be accessed from both the R and Python irw packages:

Code
# Install the package with `install.packages("irw")` (on CRAN; see the Get Started page for redivis)
library(irw)

# View available competition data
irw_list_tables(source="comp")

# Fetch competition data
df <- irw_fetch("collegefb_2021and2022", source="comp")
head(df)
Code
# Install package with `pip install irw`
import irw

# View available competition data
irw.list_tables(source="comp")

# Fetch competition data
df = irw.fetch("collegefb_2021and2022", source="comp")
head(df)

Documentation related to the tables (including table names as with collegefb_2021and2022) can be found here.

What the family holds

The family holds 121 tables and 120.5 million contests in all. Tables range widely in size: the median table has 11,650 contests between 121 competitors, while the largest, Kaggle simulation leaderboards drawn from Meta Kaggle (18 tables), hold millions of games each and account for 72% of all contests. Each table’s own counts are in irw_metadata(source = "comp") (columns n_responses and n_actors).

Figure 1: Competition tables by number of contests and number of competitors (both on a log scale).

Every table in the family

Each table links to its own page, with citation, licence and fetch snippets.

Table Contests Competitors Licence Source
acpc_poker_2010_2017 683 91 CC BY 4.0 link
aiide_starcraft_2017_2025 173,155 55 Custom link
amboseli_baboons_g1 4,118 61 CC0 1.0 link
amboseli_baboons_g2 1,667 28 CC0 1.0 link
amboseli_baboons_g3 2,387 36 CC0 1.0 link
amboseli_baboons_g4 4,464 53 CC0 1.0 link
amboseli_baboons_g5 3,281 52 CC0 1.0 link
bradleyterry2_cems 4,545 6 GPL-3.0 link
bramley_vitello_2019_gcse 2,356 150 CC BY 4.0 link
carlson_2017_human_rights 15,827 1,594 CC0 1.0 link
carlson_2017_immigration 6,720 336 CC0 1.0 link
carlson_2017_movie_reviews 9,927 497 CC0 1.0 link
carlson_2017_movie50 1,500 50 CC0 1.0 link
carlson_2017_treebank 9,996 504 CC0 1.0 link
carlson_2017_wiscads 9,528 935 CC0 1.0 link
clark_2018_strength_study2 7,835 82 CC BY 4.0 link
coertjens_2021_selfreflections 202 22 CC BY 4.0 link
cog_starcraft_2026 14,425 10 Custom link
collegefb_2021and2022 5,816 706 CC0 1.0 link
costa_gine_2023_wpt_matches 17,583 5,353 CC BY 4.0 link
cricsheet_domestic_men_2008_2026 10,374 245 ODC-By link
cricsheet_domestic_women_2015_2026 1,710 69 ODC-By link
cricsheet_intl_men_2001_2026 7,548 110 ODC-By link
cricsheet_intl_women_2003_2026 2,860 90 ODC-By link
elephant_seals_anonuevo_2009_2010 383 59 CC0 1.0 link
elephant_seals_anonuevo_2010_2011 1,170 127 CC0 1.0 link
elephant_seals_anonuevo_2011_2012 784 61 CC0 1.0 link
elephant_seals_anonuevo_2012_2013 480 115 CC0 1.0 link
elephant_seals_piedrasblancas_2012 398 45 CC0 1.0 link
elochoice_physical 4,592 82 GPL-3.0 link
eufootball_2010-2020 24,208 225 GPL-3.0 link
feederwatch_species_displacements 7,685 136 CC0 1.0 link
fivethirtyeight_nba_1946_2023 73,363 102 CC BY 4.0 link
fivethirtyeight_nfl_1920_2023 17,379 123 CC BY 4.0 link
fivethirtyeight_nhl_1917_2023 66,118 40 CC BY 4.0 link
fivethirtyeight_soccer_2016_2023 66,909 888 CC BY 4.0 link
footballcharts_2023_2026 76,988 1,818 CC BY 4.0 link
footbayes_england 203,956 146 GPL-2.0 link
footbayes_italy 27,684 76 GPL-2.0 link
friedman2019_risk_appropriate 20,595 100 CC BY 4.0 link
friedman2019_risk_disaster 19,920 100 CC BY 4.0 link
friedman2019_risk_fairness 21,060 100 CC BY 4.0 link
friedman2019_risk_harm 21,390 100 CC BY 4.0 link
friedman2019_risk_incidence 20,790 100 CC BY 4.0 link
friedman2019_risk_longterm 20,625 100 CC BY 4.0 link
friedman2019_risk_priority 19,770 100 CC BY 4.0 link
friedman2019_risk_worry 21,555 100 CC BY 4.0 link
genai_arena_edit 1,264 11 CC BY 4.0 link
genai_arena_t2i 8,094 28 CC BY 4.0 link
genai_arena_t2v 2,622 17 CC BY 4.0 link
gombe_chimpanzees_females_1969_2013 1,015 44 CC0 1.0 link
gombe_chimpanzees_males_1978_2011 2,741 22 CC0 1.0 link
guinaudeau2024_largechambers 11,453 723 CC0 1.0 link
happyzebra_hyenas 8,521 121 CC0 1.0 link
intlfootball_men_1872-2026 49,547 337 CC0 1.0 link
intlfootball_women_1956-2026 11,650 248 CC0 1.0 link
jones_2020_cme_complexity 409,889 1,111 CC BY 4.0 link
lichess_2013_blitz 1,313,542 46,808 CC0 1.0 link
lichess_2013_bullet 905,594 29,778 CC0 1.0 link
lichess_2013_classical 1,159,490 51,498 CC0 1.0 link
lmarena_text_2025 135,624 53 CC BY 4.0 link
lmarena_text_55k 57,477 64 Apache 2.0 link
makri_2026_mathtext_relevance 1,948 126 CC BY-NC 4.0 link
metakaggle_connect_4_2023_2024 45,292 82 Apache 2.0 link
metakaggle_connectx_2020_2026 18,330,867 33,933 Apache 2.0 link
metakaggle_fide_chess_2024_2025 13,045,530 13,670 Apache 2.0 link
metakaggle_google_football_2020_2020 1,725,462 14,067 Apache 2.0 link
metakaggle_halite_iv_playground_2020_2021 56,545 242 Apache 2.0 link
metakaggle_kore_2022_2022 7,101,989 12,199 Apache 2.0 link
metakaggle_kore_beta_2022_2022 31,356 936 Apache 2.0 link
metakaggle_lux_ai_s1_2021_2021 8,450,958 22,660 Apache 2.0 link
metakaggle_lux_ai_s2_2023_2023 4,722,883 9,665 Apache 2.0 link
metakaggle_lux_ai_s2_beta_2022_2022 211,832 667 Apache 2.0 link
metakaggle_lux_ai_s2_neurips_stage1_2023_2023 18,876 93 Apache 2.0 link
metakaggle_lux_ai_s2_neurips_stage2_2023_2023 127,402 401 Apache 2.0 link
metakaggle_lux_ai_s3_2024_2025 1,030,264 9,821 Apache 2.0 link
metakaggle_maze_crawler_2026_2026 169,805 4,927 Apache 2.0 link
metakaggle_orbit_wars_2026_2026 3,304,228 105,479 Apache 2.0 link
metakaggle_pokemon_tcg_2026_2026 15,882,262 189,461 Apache 2.0 link
metakaggle_rock_paper_scissors_2020_2021 7,523,108 48,844 Apache 2.0 link
metakaggle_santa_2020_2021 5,564,999 25,355 Apache 2.0 link
mlb_through2023 228,326 89 MIT link
mountain_chickadees_2019_2020 118,149 342 CC0 1.0 link
mtbench_human_2023 3,355 6 CC BY 4.0 link
nflverse_nfl_1999_2025 7,276 35 CC BY 4.0 link
ogs_go_2005_2021 25,492,142 690,746 Custom link
openfootball_argentina_2018_2025 2,435 34 CC0 1.0 link
openfootball_austria_2010_2027 3,039 21 CC0 1.0 link
openfootball_brasileirao_2018_2026 3,317 32 CC0 1.0 link
openfootball_concacafcl_2010_2025 708 100 CC0 1.0 link
openfootball_libertadores_2012_2026 2,209 162 CC0 1.0 link
openfootball_ligamx_2010_2025 4,985 28 CC0 1.0 link
openfootball_mls_2005_2025 7,063 34 CC0 1.0 link
openfootball_sudamericana_2012_2025 1,571 214 CC0 1.0 link
openfootball_uefacl_2011_2026 1,997 108 CC0 1.0 link
pklmart_pickleball_2021_2025 928 789 CC BY-NC-SA 4.0 link
placepulse2_beautiful 220,604 110,781 CC BY 4.0 link
placepulse2_boring 144,057 106,427 CC BY 4.0 link
placepulse2_depressing 149,350 105,548 CC BY 4.0 link
placepulse2_livelier 366,706 111,349 CC BY 4.0 link
placepulse2_safer 509,961 111,389 CC BY 4.0 link
placepulse2_wealthier 174,758 107,845 CC BY 4.0 link
quizbowl_acf_regionals_2018 736 143 ODbL 1.0 link
ramos_2021_proof_explanation 760 9 CC BY-NC 4.0 link
repochat_arena_2024_2025 3,844 13 CC BY 4.0 link
retrosheet_mlb_1871_2025 235,512 152 Custom link
rugby_union_tier1_1871_2026 2,892 10 CC BY-SA 4.0 link
sangwin_2021_proof_rigour_insight 3,969 15 MIT link
serena_n_hyenas 11,030 215 CC0 1.0 link
serena_s_hyenas 9,382 179 CC0 1.0 link
sscait_ladder_2021_2024 115,183 110 CC BY-NC 4.0 link
t20_hyper 633 13 GPL-3.0 link
talek_hyenas_females_1988_2015 9,096 151 CC0 1.0 link
talek_hyenas_males_1988_2014 2,339 98 CC0 1.0 link
tcec_engines_2010_2026 32,770 1,595 CC BY-SA 3.0 link
tonkean_macaques_2016_2024 57,465 38 CC BY 4.0 link
ufc_1993_2026 11,323 4,115 CC0 1.0 link
ukpconvarg1_convincingness_2016 84,445 1,052 CC BY 4.0 link
university_challenge_1994_2026 1,090 166 CC BY-SA 4.0 link
vervets_2015_2017 11,754 66 CC BY 4.0 link
zucco2019_portfoliosalience 3,661 37 CC0 1.0 link

Showing 121 of 121 tables. Fetch any of them with irw_fetch("<table>", source = "comp") or irw.fetch("<table>", source="comp").

An example

Here is a first example wherein we fit an Elo model to data from the NFL.

Code
library(elo)
library(BradleyTerry2)

# Fetch and prepare data
df <- irw::irw_fetch("fivethirtyeight_nfl_1920_2023", source = 'comp')
df <- df[df$season >= 2010 & df$season <= 2019, ]  # the 2010-2019 seasons, playoffs included
df <- df[order(df$date), ]

# ===== Elo ANALYSIS =====
er <- elo.run(score(score_a, score_b) ~ agent_a + agent_b, 
              data = df, k = 20)

# Convert Elo results to long format
elo_results <- as.data.frame(er)
elo_long <- lapply(seq_len(nrow(elo_results)), function(i) {
  data.frame(
    team = c(elo_results$team.A[i], elo_results$team.B[i]),
    elo = c(elo_results$elo.A[i], elo_results$elo.B[i]),
    date = df$date[i]
  )
})
elo_long <- do.call(rbind, elo_long)

# Convert dates to years since the start of the 2010 season
elo_long$year <- (elo_long$date - as.numeric(as.POSIXct("2010-09-01", tz = "UTC")))/(365.25*24*60*60)


elo_by_team <- split(elo_long, elo_long$team)

# ===== BRADLEY-TERRY ANALYSIS =====
# Prepare data for BT model
df_bt <- df[df$winner != 'draw', ]
df_bt$win <- as.numeric(df_bt$winner == 'agent_a')
df_bt$agent_a <- factor(df_bt$agent_a)
df_bt$agent_b <- factor(df_bt$agent_b)

# Fit BT models by season. br = TRUE uses bias-reduced estimation: a team that
# never won in a season (Cleveland in 2017) has no finite maximum-likelihood
# strength, and this keeps its estimate on the same scale as everyone else.
# Each season is a separate model with its own reference team, so the
# coefficients are centred within season to make them comparable across years.
bt_by_season <- lapply(split(df_bt, df_bt$season), function(season_df) {
  mod <- BTm(win, agent_a, agent_b, data = season_df, id = "team", br = TRUE)
  co <- coef(mod)
  names(co) <- gsub("team", "", names(co))
  co <- c(co, setNames(0, setdiff(levels(season_df$agent_a), names(co))))  # the reference team
  data.frame(
    season = unique(season_df$season),
    est = co - mean(co),
    team = names(co),
    row.names = NULL
  )
})
bt_results <- do.call(rbind, bt_by_season)
bt_by_team <- split(bt_results, bt_results$team)

# ===== PLOTTING =====
# Thirty-two labels at the right edge overwrite each other, so only the three
# strongest and three weakest teams at the end of the window are drawn dark and
# named; the rest are context. Labels are nudged apart where they would collide.
spread_labels <- function(y, min_gap) {
  o <- order(y); y_s <- y[o]
  for (k in seq_along(y_s)[-1]) y_s[k] <- max(y_s[k], y_s[k - 1] + min_gap)
  y[o] <- y_s; y
}
plot_teams <- function(by_team, xcol, ycol, min_gap, n_label = 3) {
  final <- sapply(by_team, function(d) d[[ycol]][nrow(d)])
  picked <- names(sort(final))[c(seq_len(n_label), length(final) - seq_len(n_label) + 1)]
  for (team_data in by_team[setdiff(names(by_team), picked)])
    lines(team_data[[xcol]], team_data[[ycol]], col = rgb(0, 0, 0, 0.15))
  for (team_data in by_team[picked])
    lines(team_data[[xcol]], team_data[[ycol]], col = rgb(0, 0, 0, 0.8), lwd = 1.5)
  y_lab <- spread_labels(final[picked], min_gap)
  x_lab <- sapply(by_team[picked], function(d) d[[xcol]][nrow(d)])
  text(x_lab, y_lab, picked, pos = 4, cex = 0.7, xpd = TRUE)
}

par(mfrow = c(2, 1), mgp = c(2.5, 0.7, 0), mar = c(4, 4, 2, 2))

# Plot 1: Elo ratings over time
plot(NULL,
     xlim = c(0, 10),
     ylim = c(1200, 1800),
     xlab = "Years since start of 2010 season",
     ylab = "Elo Rating",
     main = "NFL Team Elo Ratings (2010-2019)",
     xaxt = "n")
axis(1, at = 0:10)
plot_teams(elo_by_team, "year", "elo", min_gap = 40)

# Plot 2: Bradley-Terry strengths by season, centred within season
plot(NULL,
     xlim = c(2010, 2020),
     ylim = range(bt_results$est, na.rm = TRUE) + c(-0.3, 0.6),
     xlab = "Season",
     ylab = "Strength (season-centred)",
     main = "NFL Team Strength by Season (Bradley-Terry Model)",
     xaxt = "n")
axis(1, at = 2010:2019)
plot_teams(bt_by_team, "season", "est", min_gap = 0.4)