Best Time of Day for Rank Progression in Marvel Rivals
Overview
Marvel Rivals is an objective-based competitive hero shooter, where one team of 6 battles to win an objective over the opposing team. Rivals features three roles that each have different characters to choose from: Strategist, Duelist, and Vanguard. The game offers casual game play as well as competitive, with new season and half-season updates every couple of months.
My dataset includes over 500 of my own matches and tracks a wide variety of variables through each, including: competitive or casual match status, win/loss, points gained/lost (competitive), total points (competitive), current rank (competitive), rank up games (competitive), KDA (kills/deaths/assists) ratio, mvp or svp earned, hero/heroes played, main role played, type of match, map, duration in minutes, bots, and platform.
In this project, I will utilize this data to analyze how time of day affects general win rate and rank progression in competitive gameplay. Split into 4 sections of the day (morning, afternoon, evening, night), this analysis will help me to understand if there is a certain region of the day where I can play to maximize my win rate and rank progression. Additionally, this could be applied to other players’ data to see whether these time-of-day patterns can be generalized.
Data Wrangling
The dataset was manually created by tracking my own gameplay over multiple seasons using match data from tracker.gg/marvel-rivals. While the site provided raw statistics, I selected which variables to record, structured the dataset, and compiled it for analysis. Each row represents a single completed match, distinguished by their specific date and time stamp.
To analyze time-based performance, I created a new variable called time_of_day using the hour from the datetimevariable. Match data were grouped into four categories:
Morning (6:00 - 12:00)
Afternoon (12:00 - 18:00)
Evening (18:00 - 24:00)
Night (00:00 - 6:00)
Additionally, missing values in the rank_up variable (which occur for non-competitive matches) were handled using na.rm = TRUEduring summary calculations to prevent errors and ensure rank-up percentages were calculated using only competitive games.
Variables
datetime - Date and time the match was played
season - Current game season during the match
competitive - Indicates whether the match was competitive (TRUE/FALSE)
won - Indicates whether the match was won (TRUE/FALSE)
points_change - Change in rank points after the match
total_points - Total rank points after the match
current_rank - Player’s rank at the end of the match
rank_up - Indicates whether the match resulted in a rank increase (TRUE/FALSE)
kda_ratio - Kill/Death/Assist ratio recorded for the match
mvp_or_svp - Indicates whether the player received MVP or SVP recognition (TRUE/FALSE)
heroes_played - Hero or heroes used during the match
main_role - Role played during the match (DPS = Duelist, Tank = Vanguard, Support = Strategist)
match_type - Type of match played
map - Map where the match took place
match_duration - Length of the match in minutes
bots - Indicates whether bots were present in the match (TRUE/FALSE)
xbox_or_pc - Platform used to play the match
time_of_day - The time of day in which the match started (Morning, Afternoon, Evening, Night)
# Setup datalibrary(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.2.0 ✔ readr 2.1.6
✔ forcats 1.0.1 ✔ stringr 1.6.0
✔ ggplot2 4.0.2 ✔ tibble 3.3.1
✔ lubridate 1.9.5 ✔ tidyr 1.3.2
✔ purrr 1.2.1
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(ggplot2)library(gt)library(dplyr)library(lubridate)rivals_data <-read_csv("rivals.csv", na =c("", "null"))
Rows: 516 Columns: 17
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (8): datetime, current_rank, heroes_played, main_role, match_type, map, ...
dbl (4): season, points_change, total_points, kda_ratio
lgl (5): competitive, won, rank_up, mvp_or_svp, bots
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Add time of day columndata_w_tod <- rivals_data |>mutate(datetime =mdy_hm(datetime),hour =hour(datetime),time_of_day =case_when( hour >=6& hour <12~"Morning", hour >=12& hour <18~"Afternoon", hour >=18& hour <24~"Evening", hour >=0& hour <6~"Night", ) )
Visualization
I have created two visualizations to compare performance across time-of-day groups.
# Create win percentage bar chartdata_w_tod |>group_by(time_of_day) |>summarize(win_rate =mean(won)*100) |>ggplot(aes(x = time_of_day, y = win_rate, fill = time_of_day)) +geom_col() +labs(title ="Win Percentage by Time of Day",x ="Time of Day",y ="Win %" )
This visualization shows the average win percentage by time of day. It was chosen to identify patterns in overall performance across different time periods.
# Create rank-up percentage bar chartdata_w_tod |>filter(competitive ==TRUE) |>group_by(time_of_day) |>summarize(rankup_rate =mean(rank_up, na.rm =TRUE)*100) |>ggplot(aes(x = time_of_day, y = rankup_rate, fill = time_of_day)) +geom_col() +labs(title ="Competitive Rank-Up Percentage by Time of Day",x ="Time of Day",y ="Rank-Up %" )
This visualization shows the rank-up percentage by time of day for competitive matches. It highlights when rank progression is most likely to occur.
This table focuses on competitive matches, showing rank-up percentage and the number of competitive games for each time period.
Conclusion
This analysis shows that Evening is the most effective time of day for both overall win percentage and competitive rank-up percentage. It has the highest win percentage at 54.44% (n = 248) and the highest rank-up percentage at 11.54% (n = 104), so on the surface, it looks like the most effective time to play for both performance and rank progression.
However, it is important to note that Evening also has significantly more data than the other time periods, which could be acting as a confounding factor. With a larger number of games, the results are likely more stable, but it also makes it harder to directly compare to time periods with much smaller sample sizes. Morning especially stands out, with zero competitive games (n = 0), meaning there is no rank-up data at all for that time. Afternoon (n = 65) and Night (n = 46) have some competitive data, but still not enough to confidently compare against Evening.
Overall, while Evening appears to be the best time to play for win percentage, when it comes to rank-up percentage, the uneven distribution of games across time periods limits how strong that conclusion can be. More competitive data, particularly in the Morning and Afternoon, would be needed to make a more confident and balanced analysis.