<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>R Studio &#8211; Hardball Retro</title>
	<atom:link href="https://www.tuatarasoftware.com/tag/r-studio/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.tuatarasoftware.com</link>
	<description>dedicated to the enrichment of casual and serious enthusiasts in all aspects of professional baseball</description>
	<lastBuildDate>Sun, 12 Jul 2026 13:34:47 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.10</generator>

<image>
	<url>https://www.tuatarasoftware.com/wp-content/uploads/2024/01/cropped-hardball_retro_icon-1-32x32.jpg</url>
	<title>R Studio &#8211; Hardball Retro</title>
	<link>https://www.tuatarasoftware.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Modern Season Disk Generation for Earl Weaver Baseball 1.5 &#8211; Lahman, R, and SeasonTool Integration</title>
		<link>https://www.tuatarasoftware.com/2026/06/14/modern-season-disk-generation-for-earl-weaver-baseball-1-5-lahman-r-and-seasontool-integration/</link>
					<comments>https://www.tuatarasoftware.com/2026/06/14/modern-season-disk-generation-for-earl-weaver-baseball-1-5-lahman-r-and-seasontool-integration/#respond</comments>
		
		<dc:creator><![CDATA[Derek Bain]]></dc:creator>
		<pubDate>Mon, 15 Jun 2026 00:59:34 +0000</pubDate>
				<category><![CDATA[Simulations]]></category>
		<category><![CDATA[batting]]></category>
		<category><![CDATA[CoPilot]]></category>
		<category><![CDATA[Daniel Guenther]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[Don Daglow]]></category>
		<category><![CDATA[draft]]></category>
		<category><![CDATA[earl weaver]]></category>
		<category><![CDATA[Earl Weaver Baseball]]></category>
		<category><![CDATA[Eddie Dombrower]]></category>
		<category><![CDATA[Electronic Arts]]></category>
		<category><![CDATA[export]]></category>
		<category><![CDATA[fielding]]></category>
		<category><![CDATA[IBM PC]]></category>
		<category><![CDATA[import]]></category>
		<category><![CDATA[Lahman]]></category>
		<category><![CDATA[master]]></category>
		<category><![CDATA[Mirage Graphics]]></category>
		<category><![CDATA[modern]]></category>
		<category><![CDATA[pitching]]></category>
		<category><![CDATA[R Studio]]></category>
		<category><![CDATA[roster]]></category>
		<category><![CDATA[SABR]]></category>
		<category><![CDATA[season disk]]></category>
		<category><![CDATA[SeasonTool]]></category>
		<category><![CDATA[simulation]]></category>
		<category><![CDATA[teams]]></category>
		<guid isPermaLink="false">https://www.tuatarasoftware.com/?p=21199</guid>

					<description><![CDATA[The SeasonTool utility was created by Daniel Guenther in the late-1990&#8217;s to facilitate the creation of season disks for Earl Weaver Baseball 1.5 for the IBM PC (EWB). SeasonTool relies on CSV files derived from the Lahman baseball database. However, modern Lahman releases (including SABR Lahman 2025) differ significantly from the Lahman 5.1 schema that ... <a title="Modern Season Disk Generation for Earl Weaver Baseball 1.5 &#8211; Lahman, R, and SeasonTool Integration" class="read-more" href="https://www.tuatarasoftware.com/2026/06/14/modern-season-disk-generation-for-earl-weaver-baseball-1-5-lahman-r-and-seasontool-integration/" aria-label="Read more about Modern Season Disk Generation for Earl Weaver Baseball 1.5 &#8211; Lahman, R, and SeasonTool Integration">Read more</a>]]></description>
										<content:encoded><![CDATA[
<p></p>



<p>The SeasonTool utility was created by Daniel Guenther in the late-1990&#8217;s to facilitate the creation of season disks for Earl Weaver Baseball 1.5 for the IBM PC (EWB). SeasonTool relies on CSV files derived from the Lahman baseball database. However, modern Lahman releases (including <a href="https://sabr.org/lahman-database/">SABR Lahman 2025</a>) differ significantly from the Lahman 5.1 schema that SeasonTool’s DOS-era executables were hard-coded to parse.</p>



<p>Attempting to use the current Lahman database files results in schema mismatches which cause SeasonTool to:<br>•  Misread player and team records<br>•  Generate corrupted MASTER files<br>•  Produce empty ROS files<br>•  Crash in STEP2REM and BATTINGR modules<br>•  Fail to import seasons</p>



<p>This project reconstructed the exact, byte-level schemas SeasonTool expects and produced a modern R-based converter that transforms Lahman 2025 data into fully SeasonTool-compatible CSVs.</p>



<p>I developed the initial script using <a href="https://posit.co/downloads">R Studio</a> to import the Lahman csv files and clean up some known issues (playerID and stintID errors). </p>



<p>Here&#8217;s a step-by-step video tutorial that outlines the process. </p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="Modern Season Disk Generation for Earl Weaver Baseball 1.5 - Lahman, R, and SeasonTool Integration" width="900" height="506" src="https://www.youtube.com/embed/KMneZFenGjY?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>For a deeper dive, keep reading!</p>



<p></p>



<h3 class="wp-block-heading">Identifying the Problem</h3>



<p>I opened a session in <a href="https://copilot.microsoft.com">Microsoft CoPilot</a> to assist me in the troubleshooting. CoPilot proved to be very beneficial in analyzing the various text files that SeasonTool generates, pinning down the potential causes for a number of issues encountered along the way, and suggesting fixes to implement in my R script. It was necessary to &#8220;rein in&#8221; CoPilot at times. After being led on a few wild-goose chases, you become more familiar with CoPilot&#8217;s limitations and in turn, adjust your responses accordingly. The majority of the  SeasonTool’s failures were traced to several incompatibilities between modern Lahman CSVs and the legacy Lahman 5.1 format:<br>•  Missing fields (e.g., managerID, hofID, nameNote, college, lahman40ID, lahman45ID, holtzID, ZR)<br>•  Reordered or renamed fields<br>•  Additional fields in modern Lahman (e.g., WP/SB/CS in Fielding)<br>•  UTF-8 encoding and accented characters<br>•  Incorrect quoting and NA handling<br>•  Incorrect column counts<br>Because SeasonTool’s executables use fixed-position parsing, even a single missing or shifted field caused cascading corruption.</p>



<p></p>



<h3 class="wp-block-heading">Reconstructing the Correct Schemas</h3>



<p>Using my working SeasonTool installation (circa 2003) as the authoritative reference, I worked with CoPilot to reverse-engineer the exact schemas SeasonTool expects:<br>•  MASTER.csv — 32 columns<br>•  TEAMS.csv — 48 columns<br>•  BATTING.csv — 22 columns<br>•  PITCHING.csv — 27 columns<br>•  FIELDING.csv — 15 columns<br>•  FIELDINGOF.csv — 6 columns<br>These schemas differed from both Lahman 5.1 and Lahman 2025; SeasonTool uses a custom hybrid that must be matched exactly.</p>



<p></p>



<h3 class="wp-block-heading">Handling the Missing Fields</h3>



<p>The modern <a href="https://sabr.org/lahman-database/">Lahman Baseball Database</a> omits several fields SeasonTool requires. We added them back as blank columns to preserve the correct structure:<br>•  managerID<br>•  hofID<br>•  nameNote<br>•  college<br>•  lahman40ID<br>•  lahman45ID<br>•  holtzID<br>•  ZR (Zone Rating)<br>This ensured that every CSV matched the expected column count and order.</p>



<p></p>



<h3 class="wp-block-heading">Enforcing ASCII-Only Text</h3>



<p>SeasonTool and EWB cannot handle accented characters or extended Unicode. As a workaround, I  implemented a sanitization step in the R script to convert all player names and city names to pure ASCII.</p>



<p></p>



<h3 class="wp-block-heading">Enforcing Correct Quoting and NA Handling</h3>



<p>SeasonTool requires:<br>•  Text fields quoted<br>•  Numeric fields unquoted<br>•  Empty numeric fields as blank (&#8220;&#8221;)<br>•  CRLF line endings<br>•  No UTF-8 BOM<br>The final writer function enforces all of these.</p>



<p></p>



<h3 class="wp-block-heading">Final Result</h3>



<p>After applying all of the schema corrections and sanitization:<br>1893 imported successfully<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br>2005 imported successfully<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br>2025 imported successfully<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br>This confirms the pipeline is now fully SeasonTool-compatible.</p>



<p></p>



<h3 class="wp-block-heading">The Final SeasonTool-Compatible R Script</h3>



<pre class="wp-block-preformatted"><br>library(dplyr)<br>library(stringi)<br>library(readr)<br>library(dplyr)<br>library(stringr)<br>library(purrr)</pre>



<ol class="wp-block-list">
<li></li>
</ol>



<h4 class="wp-block-heading">CONFIG</h4>



<pre class="wp-block-preformatted">src_dir &lt;- "C:/stats/baseballdatabank-master/core"<br>out_dir &lt;- "C:/ewb15/seasonTool/lahman"<br>if (!dir.exists(out_dir)) { <br>dir.create(out_dir, recursive = TRUE, showWarnings = FALSE) }<br></pre>



<h4 class="wp-block-heading">LOGGING</h4>



<pre class="wp-block-preformatted">log_msg &lt;- function(…) { ts &lt;- format(Sys.time(), "%Y-%m-%d %H:%M:%S") <br>cat(ts, " ", paste0(…, collapse=" "), "\n") }</pre>



<pre class="wp-block-preformatted">log_msg("=== START LAHMAN 2025 → 5.1 CONVERSION ===")<br></pre>



<h4 class="wp-block-heading">SAFE CSV READER</h4>



<pre class="wp-block-preformatted">safe_read_csv &lt;- function(path, …) {<br>if (!file.exists(path)) {<br>log_msg("WARNING: file not found: ", path) return(NULL) }<br>log_msg("Reading: ", path) tryCatch( readr::read_csv(path, show_col_types = FALSE, progress = FALSE, …), error = function(e) {  <br>log_msg("ERROR reading ", path, ": ", conditionMessage(e)) NULL } ) }<br><br></pre>



<h4 class="wp-block-heading">SeasonTool TeamID Mapping Module</h4>



<p># Handles post-2003 Lahman teamID changes:</p>



<pre class="wp-block-preformatted"># ATH → OAK<br># LAA → ANA<br># MIA → FLO<br># WAS → MON<br># Applies to all tables: Teams, Batting, Pitching, Fielding<br># Includes validation + logging<br># ============================================================<br><br><br><strong>Mapping function</strong><br><br>map_teamid_seasontool &lt;- function(teamID, yearID) { <br>if (is.na(teamID) || is.na(yearID)) return(teamID) <br>if (yearID &gt; 2003) { <br>if (teamID == "ATH") return("OAK") <br>if (teamID == "LAA") return("ANA") <br>if (teamID == "MIA") return("FLO") <br>if (teamID == "WAS") return("MON") } return(teamID)}<br></pre>



<pre class="wp-block-preformatted"><strong>Vectorized wrapper</strong></pre>



<pre class="wp-block-preformatted">map_teamid_vec &lt;- function(df) { <br>if (!("teamID" %in% names(df)) || !("yearID" %in% names(df))) { <br>stop("Data frame must contain teamID and yearID columns.") } <br>df$teamID_original &lt;- df$teamID <br>df$teamID &lt;- mapply(map_teamid_seasontool, df$teamID, df$yearID, USE.NAMES = FALSE) df}<br><br><br><br><strong>Validation function</strong><br><br>validate_teamid_mapping &lt;- function(df, table_name = "Unknown Table") { <br>unmapped &lt;- df[df$teamID_original != df$teamID, ] <br>if (nrow(unmapped) == 0) { message(paste0("[OK] No teamID replacements needed for ", table_name)) return(invisible(df)) } <br>message(paste0("[INFO] TeamID replacements in ", table_name, ":")) print(unique(unmapped[, c("yearID", "teamID_original", "teamID")])) <br>invisible(df)}<br><br><br><strong>Apply to all Lahman tables</strong><br><br>apply_teamid_mapping_all &lt;- function(teams, batting, pitching, fielding, fldOF_old = NULL, fldOF_split = NULL) { <br>teams &lt;- map_teamid_vec(teams) <br>batting &lt;- map_teamid_vec(batting) <br>pitching &lt;- map_teamid_vec(pitching) <br>fielding &lt;- map_teamid_vec(fielding) <br># if (!is.null(fldOF_old)) {# fldOF_old &lt;- map_teamid_vec(fldOF_old)# } <br>if (!is.null(fldOF_split)) { fldOF_split &lt;- map_teamid_vec(fldOF_split) } <br><br><br><strong>Validation logs </strong><br><br>validate_teamid_mapping(teams, "teams") <br>validate_teamid_mapping(batting, "batting") <br>validate_teamid_mapping(pitching, "pitching") <br>validate_teamid_mapping(fielding, "fielding")</pre>



<pre class="wp-block-preformatted"># if (!is.null(fldOF_old)) {# validate_teamid_mapping(fldOF_old, "fldOF_old")# } <br>if (!is.null(fldOF_split)) { validate_teamid_mapping(fldOF_split, "fldOF_split") } list( teams = teams, batting = batting, pitching = pitching, fielding = fielding, fldOF_old = fldOF_old, fldOF_split = fldOF_split )}<br></pre>



<h4 class="wp-block-heading">LOAD TABLES</h4>



<pre class="wp-block-preformatted">master &lt;- safe_read_csv(file.path(src_dir, "People.csv"))<br>batting &lt;- safe_read_csv(file.path(src_dir, "Batting.csv"))<br>pitching &lt;- safe_read_csv(file.path(src_dir, "Pitching.csv"))<br>fielding &lt;- safe_read_csv(file.path(src_dir, "Fielding.csv"))<br>fldOF_old &lt;- safe_read_csv(file.path(src_dir, "FieldingOF.csv"))<br>fldOF_split &lt;- safe_read_csv(file.path(src_dir, "FieldingOFsplit.csv"))<br>teams &lt;- safe_read_csv(file.path(src_dir, "Teams.csv"))<br>required &lt;- list( master=master, batting=batting, pitching=pitching, fielding=fielding, fldOF_old=fldOF_old, fldOF_split=fldOF_split, teams=teams )</pre>



<pre class="wp-block-preformatted">missing &lt;- names(required)[vapply(required, is.null, logical(1))] if (length(missing) &gt; 0) stop("Missing required tables: ", paste(missing, collapse=", "))<br></pre>



<h4 class="wp-block-heading">FIX TEAMID MAPPING FOR Team Changes post-2003</h4>



<pre class="wp-block-preformatted">mapped &lt;- apply_teamid_mapping_all( teams, batting, pitching, fielding,# fldOF_old, fldOF_split)</pre>



<pre class="wp-block-preformatted">teams &lt;- mapped$teams<br>batting &lt;- mapped$batting<br>pitching &lt;- mapped$pitching<br>fielding &lt;- mapped$fielding<br>fieldingOF &lt;- mapped$fieldingOF<br>fieldingOFsplit&lt;- mapped$fieldingOFsplit<br>required &lt;- list( master=master, batting=batting, pitching=pitching, fielding=fielding, fldOF_old=fldOF_old, fldOF_split=fldOF_split, teams=teams)<br>missing &lt;- names(required)[vapply(required, is.null, logical(1))]<br>if (length(missing) &gt; 0) stop("Missing required tables: ", paste(missing, collapse=", "))<br></pre>



<h4 class="wp-block-heading">FIXES: PLAYER ID CORRECTIONS + VENDITTE</h4>



<pre class="wp-block-preformatted"># There is an incorrect playerID for Yuli Gurriel<br><br>log_msg("Applying ID fixes…")<br>fix_id &lt;- function(tbl, from, to) { <br>if ("playerID" %in% names(tbl)) { <br>tbl$playerID &lt;- ifelse(tbl$playerID == from, to, tbl$playerID) } tbl }<br>master &lt;- fix_id(master, "gourryu01", "gurriyu01")<br>batting &lt;- fix_id(batting, "gourryu01", "gurriyu01")<br>pitching &lt;- fix_id(pitching, "gourryu01", "gurriyu01")<br>fielding &lt;- fix_id(fielding, "gourryu01", "gurriyu01")<br>fldOF_old&lt;- fix_id(fldOF_old,"gourryu01", "gurriyu01")<br>fldOF_split&lt;-fix_id(fldOF_split,"gourryu01","gurriyu01")<br></pre>



<h4 class="wp-block-heading">Pat Venditte: THROWS = &#8220;S&#8221; → &#8220;L&#8221;</h4>



<pre class="wp-block-preformatted"># Earl Weaver Baseball 1.5 (along with most computer baseball sims from that era)<br># only allow pitchers to be "R" (right-hander) or "L" (left-hander)<br># Since there is no option for a "switch-pitcher", I elected to assign an "L" for<br># Pat Venditte's throwing handedness. The code below is not specifically looking for<br># Venditte; however he is the only player assigned as "S" (switch-pitcher) in the <br># Lahman database as of the 2025 edition. <br> <br>if ("throws" %in% names(master)) { master$throws &lt;- ifelse(master$throws == "S", "L", master$throws) }<br></pre>



<h4 class="wp-block-heading">MLB-ONLY FILTER (AL/NL ONLY)</h4>



<pre class="wp-block-preformatted">log_msg("Filtering to MLB-only players (AL/NL)…")<br>mlb_leagues &lt;- c("AL","NL") <br>players_bat &lt;- batting %&gt;% filter(lgID %in% mlb_leagues) %&gt;% distinct(playerID) players_pit &lt;- pitching %&gt;% filter(lgID %in% mlb_leagues) %&gt;% distinct(playerID) players_fld &lt;- fielding %&gt;% filter(lgID %in% mlb_leagues) %&gt;% distinct(playerID)<br>mlb_players &lt;- bind_rows(players_bat, players_pit, players_fld) %&gt;% distinct(playerID) %&gt;% pull(playerID)<br>master &lt;- master %&gt;% filter(playerID %in% mlb_players)</pre>



<pre class="wp-block-preformatted">log_msg("Master rows after MLB filter: ", nrow(master))<br></pre>



<h4 class="wp-block-heading">FIELDINGOF: 1871–1955 FROM OLD FILE + 1956+ FROM FIELDINGOF_split</h4>



<pre class="wp-block-preformatted">log_msg("Building FieldingOF (1871–1955 old file, 1956+ split file)…")<br>stop_if_missing &lt;- function(tbl, cols, name) { <br>miss &lt;- setdiff(cols, names(tbl)) <br>if (length(miss) &gt; 0) stop("Missing columns in ", name, ": ", paste(miss, collapse=", ")) }<br>stop_if_missing(fldOF_old, c("playerID","yearID","stint","Glf","Gcf","Grf"), "FieldingOF") <br>stop_if_missing(fldOF_split, c("playerID","yearID","stint","POS","G"), "FieldingOFsplit")<br>fldOF_old_51 &lt;- fldOF_old %&gt;% filter(yearID &lt;= 1955) %&gt;% transmute(playerID, yearID, stint, Glf, Gcf, Grf)<br>fldOF_new_51 &lt;- fldOF_split %&gt;% filter(POS %in% c("LF","CF","RF"), yearID &gt;= 1956) %&gt;% mutate( Glf = if_else(POS=="LF", as.integer(G), 0L), Gcf = if_else(POS=="CF", as.integer(G), 0L), Grf = if_else(POS=="RF", as.integer(G), 0L) ) %&gt;% group_by(playerID, yearID, stint) %&gt;% summarise( Glf=sum(Glf), Gcf=sum(Gcf), Grf=sum(Grf), .groups="drop" )<br>fldOF_51 &lt;- bind_rows(fldOF_old_51, fldOF_new_51) %&gt;% arrange(yearID, playerID, stint)</pre>



<pre class="wp-block-preformatted">log_msg("FieldingOF rows: ", nrow(fldOF_51))<br></pre>



<h4 class="wp-block-heading">NORMALIZE TO STRICT LAHMAN 5.1 SCHEMAS</h4>



<pre class="wp-block-preformatted">log_msg("Normalizing tables to Lahman 5.1 schemas…")<br>master_51 &lt;- master %&gt;% transmute(<br>ID = as.integer(ID),<br>playerID = as.character(playerID),</pre>



<pre class="wp-block-preformatted"># Missing in 2025 → must be blank</pre>



<pre class="wp-block-preformatted">managerID = "",<br>hofID = "",<br>birthYear = as.integer(birthYear),<br>birthMonth = as.integer(birthMonth),<br>birthDay = as.integer(birthDay),<br>birthCountry = as.character(birthCountry),<br>birthState = as.character(birthState),<br>birthCity = as.character(birthCity),<br>deathYear = as.integer(deathYear),</pre>



<pre class="wp-block-preformatted">deathMonth = as.integer(deathMonth),
deathDay = as.integer(deathDay),
deathCountry = as.character(deathCountry),
deathState = as.character(deathState),
deathCity = as.character(deathCity),
nameFirst = as.character(nameFirst),
nameLast = as.character(nameLast),
# Missing in 2025 → must be blank
nameNote = "",
nameGiven = as.character(nameGiven),
# Missing in 2025 → must be blank
nameNick = "",
weight = as.numeric(weight),
height = as.numeric(height),
bats = as.character(bats),
throws = as.character(throws),
debut = as.character(debut),
# Missing in 2025 → must be blank
college = "",
lahman40ID = "",
lahman45ID = "",
retroID = as.character(retroID),
# Missing in 2025 → must be blank
holtzID = "",
bbrefID = as.character(bbrefID))

batting_51 &lt;- batting %&gt;% transmute(
playerID = as.character(playerID),
yearID = as.integer(yearID),
stintID = as.integer(stint),
teamID = as.character(teamID),
lgID = as.character(lgID),
G = as.integer(G),
AB = as.integer(AB),
R = as.integer(R),
H = as.integer(H),
<code>2B</code> = as.integer(<code>2B</code>),
<code>3B</code> = as.integer(<code>3B</code>),
HR = as.integer(HR),
RBI = as.integer(RBI),
SB = as.integer(SB),
CS = as.integer(CS),
BB = as.integer(BB),
SO = as.integer(SO),
IBB = as.integer(IBB),
HBP = as.integer(HBP),
SH = as.integer(SH),
SF = as.integer(SF),
GIDP = as.integer(GIDP))

pitching_51 &lt;- pitching %&gt;% transmute(
playerID = as.character(playerID),
yearID = as.integer(yearID),
stintID = as.integer(stint),
teamID = as.character(teamID),
lgID = as.character(lgID),
W = as.integer(W),L = as.integer(L),G = as.integer(G),GS = as.integer(GS),CG = as.integer(CG),SHO = as.integer(SHO),SV = as.integer(SV),
IPOuts = as.integer(IPouts),H = as.integer(H),ER = as.integer(ER),HR = as.integer(HR),BB = as.integer(BB),SO = as.integer(SO),
BAOpp = as.numeric(BAOpp), # may be blank for early yearsERA = as.numeric(ERA),IBB = as.integer(IBB),WP = as.integer(WP),HBP = as.integer(HBP),BK = as.integer(BK),BFP = as.integer(BFP),GF = as.integer(GF),R = as.integer(R))
fielding_51 &lt;- fielding %&gt;% transmute(
playerID = as.character(playerID),
yearID = as.integer(yearID),
stintID = as.integer(stint),
teamID = as.character(teamID),
lgID = as.character(lgID),
POS = as.character(POS),
G = as.integer(G),
GS = as.integer(GS),
InnOuts = as.integer(InnOuts),
PO = as.integer(PO),
A = as.integer(A),
E = as.integer(E),
DP = as.integer(DP),
PB = as.integer(PB),
# ZR removed from modern Lahman → must be synthesized
ZR = 0L )</pre>



<pre class="wp-block-preformatted">teams_51 &lt;- teams %&gt;% filter(lgID %in% mlb_leagues) %&gt;% transmute(<br>yearID = as.integer(yearID),<br>lgID = as.character(lgID),<br>teamID = as.character(teamID),<br>franchID = as.character(franchID),<br>divID = as.character(divID),<br>Rank = as.integer(Rank),<br>G = as.integer(G),<br>Ghome = na_if(as.integer(Ghome), 0),<br>W = as.integer(W),<br>L = as.integer(L),<br>DivWin = as.character(DivWin),<br>WCWin = as.character(WCWin),<br>LgWin = as.character(LgWin),<br>WSWin = as.character(WSWin),</pre>



<pre class="wp-block-preformatted">#Batting totals (SeasonTool order)<br><br>R = as.integer(R),<br>AB = as.integer(AB),<br>H = as.integer(H),<br><code>2B</code> = as.integer(<code>2B</code>),<br><code>3B</code> = as.integer(<code>3B</code>),<br>HR = as.integer(HR),<br>BB = as.integer(BB),<br>SO = as.integer(SO),<br>SB = na_if(as.integer(SB), 0),<br>CS = na_if(as.integer(CS), 0),<br>HBP = na_if(as.integer(HBP), 0),<br>SF = na_if(as.integer(SF), 0),<br><br># Pitching totals<br><br>RA = as.integer(RA),<br>ER = as.integer(ER),<br>ERA = as.numeric(ERA),<br>CG = as.integer(CG),<br>SHO = as.integer(SHO),<br>SV = as.integer(SV),<br>IPOuts = as.integer(IPouts),<br>HA = as.integer(HA),<br>HRA = as.integer(HRA),<br>BBA = as.integer(BBA),<br>SOA = as.integer(SOA),<br><br># Fielding totals<br><br>E = as.integer(E),<br>DP = na_if(as.integer(DP), 0),<br>FP = as.numeric(FP),<br><br># Metadata<br><br>name = as.character(name),<br>park = as.character(park),<br>attendance = na_if(as.integer(attendance), 0),<br>BPF = as.integer(BPF),<br>PPF = as.integer(PPF),<br>teamIDBR = as.character(teamIDBR),<br>teamIDlahman45= as.character(teamIDlahman45),<br>teamIDretro = as.character(teamIDretro))</pre>



<pre class="wp-block-preformatted">fieldingOF_51 &lt;- fldOF_51 %&gt;% transmute(<br>playerID = as.character(playerID),<br>yearID = as.integer(yearID),<br>stintID = as.integer(stintID),<br>Glf = as.integer(Glf),<br>Gcf = as.integer(Gcf),<br>Grf = as.integer(Grf) )<br></pre>



<p><strong>Willard Brown (brownwi02) stintID correction</strong></p>



<p>#Negro League data introduced a mismatch:</p>



<p>#batting_51: stintID = 2<br>#fldOF_51: stintID = 1<br>#MLB stint for 1947 St. Louis Browns should be stintID = 1</p>



<pre class="wp-block-preformatted">batting_51$stintID &lt;- ifelse( batting_51$playerID == "brownwi02" &amp; batting_51$yearID == 1947, 1, batting_51$stintID )<br>fielding_51$stintID &lt;- ifelse( fielding_51$playerID == "brownwi02" &amp; fielding_51$yearID == 1947, 1, fielding_51$stintID )</pre>



<pre class="wp-block-preformatted">fieldingOF_51$stintID &lt;- ifelse( fieldingOF_51$playerID == "brownwi02" &amp; fieldingOF_51$yearID == 1947, 1, fieldingOF_51$stintID )<br></pre>



<h4 class="wp-block-heading">FIX NUMERIC NA VALUES FOR SEASONTOOL COMPATIBILITY</h4>



<pre class="wp-block-preformatted">fix_numeric_na &lt;- function(df) { <br>df %&gt;% mutate(across(where(is.numeric), ~ ifelse(is.na(.x), 0, .x))) }<br>#Special rule: ERA must be 99.99 instead of 0<br>pitching_51 &lt;- pitching_51 %&gt;% mutate( ERA = ifelse(is.na(ERA) | IPOuts == 0, 99.99, ERA), IPOuts = ifelse(IPOuts == 0 &amp; ER == 0, 1, IPOuts) )<br>batting_51 &lt;- fix_numeric_na(batting_51) pitching_51 &lt;- fix_numeric_na(pitching_51) fielding_51 &lt;- fix_numeric_na(fielding_51) fieldingOF_51 &lt;- fix_numeric_na(fieldingOF_51) <br>teams_51 &lt;- fix_numeric_na(teams_51) <br><br>ascii_sanitize &lt;- function(x) { <br>x &lt;- stri_trans_general(x, "Latin-ASCII") <br># remove accents <br>x &lt;- gsub("[^ -~]", "", x) <br># remove any remaining non-ASCII x } <br>master_51 &lt;- master_51 %&gt;% mutate( nameFirst = ascii_sanitize(nameFirst), nameLast = ascii_sanitize(nameLast), nameGiven = ascii_sanitize(nameGiven), nameNick = ascii_sanitize(nameNick), birthCity = ascii_sanitize(birthCity), deathCity = ascii_sanitize(deathCity), college = ascii_sanitize(college) )<br></pre>



<h4 class="wp-block-heading">WRITE CSV (QUOTES AROUND TEXT FIELDS ONLY!)</h4>



<pre class="wp-block-preformatted">write_seasontool_csv &lt;- function(df, path) {<br>write.table(<br>df,<br>file = path,<br>sep = ",",<br>row.names = FALSE,<br>col.names = FALSE,<br>quote = TRUE, # let R quote character fields normally<br>na = "" # empty fields become ,, not "" ) }<br><br>write_seasontool_csv(master_51, file.path(out_dir,"Master.csv"))<br>write_seasontool_csv(batting_51, file.path(out_dir,"Batting.csv"))<br>write_seasontool_csv(pitching_51, file.path(out_dir,"Pitching.csv"))<br>write_seasontool_csv(fielding_51, file.path(out_dir,"Fielding.csv"))<br>write_seasontool_csv(fieldingOF_51, file.path(out_dir,"FieldingOF.csv"))<br>write_seasontool_csv(teams_51, file.path(out_dir,"Teams.csv"))<br><br>log_msg("=== SEASON-SPECIFIC EXPORT COMPLETE ===")<br></pre>



<h3 class="wp-block-heading">Generating a Season Disk with SeasonTool</h3>



<p>Extract the SeasonTool files to a subfolder of your Earl Weaver Baseball 1.5 directory. </p>



<p>Open a DosBox session and change the directory to your EWB15\SeasonTool subfolder. </p>



<p>Type:    <strong>GETMASTR</strong>          This parses the newly-created Lahman MASTER.CSV file for use with SeasonTool.</p>



<p>Type:    <strong>IMPORT [YYYY]</strong>        where YYYY is the year of the season that you wish to import.</p>



<p>The import process takes a while to complete. You can increase the CPU cycles in DosBox by holding the CTRL key and repeatedly pressing the F12 key. You will see the CPU cycles increase at the top of the DosBox window. Use CTRL-F11 to decrease the cycles. I usually bump my DosBox session up to 40000 during the Import, but your mileage will vary depending on your computer&#8217;s processing power. When the Import is complete, you&#8217;ll see a &#8220;success&#8221; message and the command prompt will be visible. </p>



<p>Type:     <strong>DRAFT</strong>     </p>



<p>The draft process allows you to select or deselect players to be included on each team&#8217;s roster. You have a 25-man roster per team. I usually take care to select a minimum of 2 catchers. For current teams (2000-present) I go with a mix of 12 batters / 13 pitchers or 13 batters / 12 pitchers. Teams from 1920 through late 1990&#8217;s &#8211; depending on the team, maybe go with 15 batters / 10 pitchers, 14/11, etc. Deadball era teams usually have less than 25 players total, so you&#8217;re selecting nearly every player in most instances. There is a built-in help function to see the various keyboard shortcuts. Primarily I&#8217;m using A to move up or Z to move down one player at a time. S skips up 15 players at a clip while X skips down by 15. Select a player to be added to the roster with the space bar. You&#8217;ll see an &#8220;X&#8221; to the left of their name. Use the space bar to select or deselect players. Once you select 25 players on a given team, press R and wait a few seconds. A box will appear mid-screen, allowing you to specify the primary and secondary position for players appearing at multiple positions during that season. Use the A and Z keys to move up/down, then press the space bar to mark the currently selected position as the primary. Repeat this step to select the secondary position, at which time the next multiple-position player will appear in the box. If you accidentally select the incorrect position, make a note of it and cycle through the remaining players. Once you return to the main draft screen, move up or down to the player whose position needs to be adjusted, then press P. You can select the primary and secondary position for that player. </p>



<p>When you have all of the 25-man rosters configured and fielding positions assigned, press E to export. This process will run for several minutes. Assuming it is successfully completed, SeasonTool will respond that you need to run EXPORT.EXE at the command prompt. </p>



<p>Type:  <strong>EXPORT </strong>    </p>



<p>SeasonTool should respond that it created 3 files:   PLAYERS.DAT, LEAGNAME.DAT, PARKS.DAT</p>



<p>Use Windows Explorer (or the DOS command prompt if you prefer) to browse to your Earl Weaver Baseball 1.5 main program folder. Make a backup copy of any .DAT files to a subfolder. </p>



<p>Return to your SeasonTool subfolder and copy the 3 .DAT files into your Earl Weaver Baseball 1.5 main program folder. </p>



<p>At this point, I recommend running the Commissioner&#8217;s Disk (STATTOOL from the command prompt). Review the league structure in League/Division Editor:</p>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="480" height="238" src="https://www.tuatarasoftware.com/wp-content/uploads/2026/06/image-480x238.png" alt="" class="wp-image-21204" srcset="https://www.tuatarasoftware.com/wp-content/uploads/2026/06/image-480x238.png 480w, https://www.tuatarasoftware.com/wp-content/uploads/2026/06/image-300x149.png 300w, https://www.tuatarasoftware.com/wp-content/uploads/2026/06/image-768x381.png 768w, https://www.tuatarasoftware.com/wp-content/uploads/2026/06/image.png 1153w" sizes="(max-width: 480px) 100vw, 480px" /></figure>



<figure class="wp-block-image size-large"><img decoding="async" width="480" height="307" src="https://www.tuatarasoftware.com/wp-content/uploads/2026/06/image-1-480x307.png" alt="" class="wp-image-21206" srcset="https://www.tuatarasoftware.com/wp-content/uploads/2026/06/image-1-480x307.png 480w, https://www.tuatarasoftware.com/wp-content/uploads/2026/06/image-1-300x192.png 300w, https://www.tuatarasoftware.com/wp-content/uploads/2026/06/image-1-768x492.png 768w, https://www.tuatarasoftware.com/wp-content/uploads/2026/06/image-1.png 1003w" sizes="(max-width: 480px) 100vw, 480px" /></figure>



<p>You&#8217;ll notice 14 teams in the American League and 16 teams in the National League. Earl Weaver Baseball 1.5 pre-dates the MLB expansion in the mid-1990&#8217;s along with the switch to 3 divisions per league. Another issue that you&#8217;ll need to workaround &#8211; you can only create a schedule (Schedule A League) with an even number of teams in a league. In this case, I&#8217;ve left Houston in the National League. You may recall that the script renames several team ID&#8217;s (ATH, LAA, MIA, WAS) that did not exist prior to SeasonTool&#8217;s creation. Here, you can edit those team names with the city, abbreviation or team nickname. I recommend  using the Advanced Ball Park Editor in conjunction with the <a href="https://www.seamheads.com/ballparks/">Seamheads Ballparks Database</a> to modify the ballparks to reflect the modern-day field names and dimensions. </p>



<p></p>



<h3 class="wp-block-heading">Future State</h3>



<p>There were 30 MLB teams when Daniel Guenther created the SeasonTool utility. If and when MLB expands to 32 teams, I&#8217;m not sure if SeasonTool will be able to accommodate them. It may be necessary to modify the R script in order to exclude the new teams from the CSV files. Earl Weaver Baseball 1.5 can accommodate up to 32 teams, so it would at least be possible to import data for the 30 franchises that exist as of 2026, then manually create/edit the two expansion teams using the Commissioner&#8217;s Disk. We&#8217;ll leave that issue for another day.</p>



<p></p>



<h3 class="wp-block-heading">Wrap-Up</h3>



<p>This project successfully restored full compatibility between modern Lahman data and SeasonTool’s legacy import pipeline. The final R script produces CSVs that match SeasonTool’s expected schemas exactly, enabling successful imports for seasons from 1871 through 2025. We can extend the life of Earl Weaver Baseball 1.5 with a stable, future-proof workflow (well, at least until the next round of expansion) for generating SeasonTool-ready data.</p>



<p></p>



<h3 class="wp-block-heading">Resources</h3>



<p>SeasonTool is no longer available on the Internet (at least I wasn&#8217;t able to locate it). The software was freely available and I&#8217;m sharing it <a href="https://www.dropbox.com/scl/fo/lopntzi27fv195iefoenn/ANwd4CD9oPZjg9KDqrbnX3Q?rlkey=cbyj06djfd99olvbrfxd0l4ss&amp;st=y7afvlxg&amp;dl=0">here</a> for the handful of individuals that might be interested in using this program (the filename is SeasonTool1901-2003.zip). I will be periodically creating season disks for Earl Weaver Baseball 1.5 and uploading them here.</p>



<p><a href="https://www.dropbox.com/scl/fo/lopntzi27fv195iefoenn/ANwd4CD9oPZjg9KDqrbnX3Q?rlkey=cbyj06djfd99olvbrfxd0l4ss&amp;st=y7afvlxg&amp;dl=0">EWB 1.5 Season Disks</a></p>



<p>Many thanks to Daniel Guenther for creating SeasonTool, and of course to Don Daglow, Eddie Dombrower, Earl Weaver and the teams at Electronic Arts and Mirage Graphics (see the <a href="https://www.mobygames.com/game/3367/earl-weaver-baseball/credits/dos/?autoplatform=true">full list of credits</a> here) for the ground-breaking Earl Weaver Baseball game.</p>



<p>Don Daglow &#8211; SABR G&amp;S Virtual</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Stay Home With SABR: Don Daglow, baseball video game designer" width="900" height="506" src="https://www.youtube.com/embed/9Z0sdJDEeGE?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>Eddie Dombrower &#8211; SABR G&amp;S Virtual</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-4-3 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Stay Home With SABR: Eddie Dombrower" width="900" height="675" src="https://www.youtube.com/embed/XEhreQZwOmQ?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>
<p><a class="a2a_button_facebook" href="https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fwww.tuatarasoftware.com%2F2026%2F06%2F14%2Fmodern-season-disk-generation-for-earl-weaver-baseball-1-5-lahman-r-and-seasontool-integration%2F&amp;linkname=Modern%20Season%20Disk%20Generation%20for%20Earl%20Weaver%20Baseball%201.5%20%E2%80%93%20Lahman%2C%20R%2C%20and%20SeasonTool%20Integration" title="Facebook" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_linkedin" href="https://www.addtoany.com/add_to/linkedin?linkurl=https%3A%2F%2Fwww.tuatarasoftware.com%2F2026%2F06%2F14%2Fmodern-season-disk-generation-for-earl-weaver-baseball-1-5-lahman-r-and-seasontool-integration%2F&amp;linkname=Modern%20Season%20Disk%20Generation%20for%20Earl%20Weaver%20Baseball%201.5%20%E2%80%93%20Lahman%2C%20R%2C%20and%20SeasonTool%20Integration" title="LinkedIn" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_bluesky" href="https://www.addtoany.com/add_to/bluesky?linkurl=https%3A%2F%2Fwww.tuatarasoftware.com%2F2026%2F06%2F14%2Fmodern-season-disk-generation-for-earl-weaver-baseball-1-5-lahman-r-and-seasontool-integration%2F&amp;linkname=Modern%20Season%20Disk%20Generation%20for%20Earl%20Weaver%20Baseball%201.5%20%E2%80%93%20Lahman%2C%20R%2C%20and%20SeasonTool%20Integration" title="Bluesky" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd a2a_counter addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Fwww.tuatarasoftware.com%2F2026%2F06%2F14%2Fmodern-season-disk-generation-for-earl-weaver-baseball-1-5-lahman-r-and-seasontool-integration%2F&#038;title=Modern%20Season%20Disk%20Generation%20for%20Earl%20Weaver%20Baseball%201.5%20%E2%80%93%20Lahman%2C%20R%2C%20and%20SeasonTool%20Integration" data-a2a-url="https://www.tuatarasoftware.com/2026/06/14/modern-season-disk-generation-for-earl-weaver-baseball-1-5-lahman-r-and-seasontool-integration/" data-a2a-title="Modern Season Disk Generation for Earl Weaver Baseball 1.5 – Lahman, R, and SeasonTool Integration"></a></p>]]></content:encoded>
					
					<wfw:commentRss>https://www.tuatarasoftware.com/2026/06/14/modern-season-disk-generation-for-earl-weaver-baseball-1-5-lahman-r-and-seasontool-integration/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Generating Opening Day Rosters from Retrosheet Event Files Using R</title>
		<link>https://www.tuatarasoftware.com/2023/05/31/generating-opening-day-rosters-from-retrosheet-event-files-using-r/</link>
					<comments>https://www.tuatarasoftware.com/2023/05/31/generating-opening-day-rosters-from-retrosheet-event-files-using-r/#respond</comments>
		
		<dc:creator><![CDATA[Derek Bain]]></dc:creator>
		<pubDate>Wed, 31 May 2023 16:08:26 +0000</pubDate>
				<category><![CDATA[Around The Horn]]></category>
		<category><![CDATA[Event Files]]></category>
		<category><![CDATA[Lineups]]></category>
		<category><![CDATA[R Programming]]></category>
		<category><![CDATA[R Studio]]></category>
		<category><![CDATA[Retrosheet]]></category>
		<category><![CDATA[script]]></category>
		<guid isPermaLink="false">https://www.tuatarasoftware.com/?p=14551</guid>

					<description><![CDATA[I wanted to utilize the Opening Day MLB rosters for various season replays in my computer-based simulations, but I wasn’t able to locate this information in the usual places (Baseball-Reference, Retrosheet, etc.) I belatedly found out that a number of individuals and volunteers in the sabermetric community have already done this work, scouring box scores ... <a title="Generating Opening Day Rosters from Retrosheet Event Files Using R" class="read-more" href="https://www.tuatarasoftware.com/2023/05/31/generating-opening-day-rosters-from-retrosheet-event-files-using-r/" aria-label="Read more about Generating Opening Day Rosters from Retrosheet Event Files Using R">Read more</a>]]></description>
										<content:encoded><![CDATA[
<p>I wanted to utilize the Opening Day MLB rosters for various season replays in my computer-based simulations, but I wasn’t able to locate this information in the usual places (Baseball-Reference, Retrosheet, etc.) I belatedly found out that a number of individuals and volunteers in the sabermetric community have already done this work, scouring box scores and transaction pages to cobble together this data. Additionally, some of the current computer baseball simulations such as Out of the Park, Action! PC and Digital Diamond Baseball include built-in functionality or utilities that provide users with the option to incorporate Opening Day Rosters, As-Played Lineups and Real-Life Transactions into their replays. I discovered the <a href="mailto:ATMgrforBBW@groups.io">ATMgrforBBW@groups.io</a> website which supports the Automatic Transaction Manager (ATMgr) developed by Gary Leven for APBA’s Baseball for Windows (BBW).</p>



<p>However, since I went to the trouble of writing an R script to facilitate my needs, I figured that I’d share the results with the community. The script essentially imports one or more years’ worth of Retrosheet event files and iterates through the data to extract the starters and substitutes from every game in the file. The code will also gather the game dates and relevant team information. Once the data is extracted, the resulting data table can be further sorted and manipulated to remove all but the first game in a given season for every player. You can export the results and take the first 25 players for each team as their Opening Day Roster. Individuals who do not wish to go through the entire process outlined below can still acquire the data as I’ve shared it via Google Sheets here -&gt;</p>



<p><a href="https://docs.google.com/spreadsheets/d/e/2PACX-1vRrSOoOTDuTYYrd9jfwNj7Tt4WLWrJBIwu-ASxDCuYc9035HOW2cB7V-91dhu_YWmbPeuzH55kYHR9P/pubhtml">https://docs.google.com/spreadsheets/d/e/2PACX-1vRrSOoOTDuTYYrd9jfwNj7Tt4WLWrJBIwu-ASxDCuYc9035HOW2cB7V-91dhu_YWmbPeuzH55kYHR9P/pubhtml</a></p>



<h2 class="wp-block-heading"><strong>What is R?</strong></h2>



<p>The definition of the R programming language, as it relates to baseball data, was articulated in the book “Analyzing Baseball Data with R” by Max Marchi and Jim Albert. Quoting from the Preface of the first edition: “R is a system for statistical computation and graphics, and it is a computer language designed for typical and possibly specialized statistical and graphical applications.. The public availability of baseball data and the open-source R software is an attractive marriage. R provides a large range of tools for importing, arranging and organizing large datasets. By the use of built-in functions and collections of packages from the R user-community, one can perform various data and graphical analyses, and communicate this work easily to other baseball enthusiasts.”</p>



<h2 class="wp-block-heading"><strong>Requirements:</strong></h2>



<p>You’ll need to download and install R 3.3.0+ and R Studio Desktop for Windows from the following site:</p>



<p><a href="https://posit.co/download/rstudio-desktop/">https://posit.co/download/rstudio-desktop/</a></p>



<p>The installation process for R and R Studio are beyond the scope of this article.</p>



<p>You will need to download the Retrosheet event files and extract them into a folder.</p>



<p><a href="https://www.retrosheet.org/game.htm">https://www.retrosheet.org/game.htm</a></p>



<p>You can choose to download the event files for individual seasons or, if you scroll down on the page, look for the section “<strong>Regular season event files by decade</strong>”. If you have ample available disk space, I suggest downloading the decade event files.</p>



<p>I extract the event files into C:\Retrosheet\Events on my computer. You can change the folder/subfolder location if you wish, but you’ll need to update any references to that folder in the R script.</p>



<p>The resulting files are exported to a folder called C:\OpeningDayRosters. Again, you can export to any folder that you choose, but you’ll need to modify that line of code in the R script.</p>



<p>Optional &#8211; merge the event files. Open a command prompt and execute the following commands:</p>



<pre class="wp-block-code"><code>       copy 191*.ev* events_1910.csv

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; copy 192*.ev* events_1920.csv&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; copy 193*.ev* events_1930.csv

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; copy 194*.ev* events_1940.csv

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; copy 195*.ev* events_1950.csv&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; copy 196*.ev* events_1960.csv

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; copy 197*.ev* events_1970.csv

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; copy 198*.ev* events_1980.csv&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; copy 199*.ev* events_1990.csv

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; copy 200*.ev* events_2000.csv

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; copy 201*.ev* events_2010.csv&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; copy 202*.ev* events_2020.csv</code></pre>



<p>You’ll need the R script – extract the <a href="https://www.tuatarasoftware.com/wp-content/uploads/2023/05/OpeningDayRosters.zip">.zip file</a> into a C:\R_Scripts folder or alternate directory if you have another location that you’d prefer to house your R script files.</p>



<h2 class="wp-block-heading"><strong>A closer look at Retrosheet Event Files</strong></h2>



<p>Please check out the following link for a detailed description of the Retrosheet event file contents and scoring system. <a href="https://www.retrosheet.org/eventfile.htm">https://www.retrosheet.org/eventfile.htm</a></p>



<p>Each game in an event file consists of multiple record types including:</p>



<p>id, version, info, start, sub, badj, padj, ladj, radj, presadj, data, com</p>



<p>We will use Jackie Robinson’s MLB debut for the Brooklyn Dodgers on April 15, 1947 as our sample event file.&nbsp; As you’ll see in my explanation of the script that I wrote to determine the Opening Day Rosters, I drop all of the record types except for id, info, start and sub very early in the process. However, you may wish to examine the Event files for play-by-play or other information. In that case, you’ll need to determine which records are pertinent to your project.</p>



<p>The ‘id’ row is fairly self-explanatory. The entry consists of a three-letter abbreviation for the home team followed by the year, month, day and game number (single game (0), first game (1) or second game (2) if a double-header was played on that date).</p>



<pre class="wp-block-code"><code>id,BRO194704150</code></pre>



<p>You may safely ignore the ‘version’ row.</p>



<pre class="wp-block-code"><code>version,1</code></pre>



<p>The ‘info’ records encompass approximately 30 rows of data but only a handful of rows are germane to the Opening Day Rosters script. I’m only interested in visteam, hometeam, date and number – the remaining rows will be discarded.</p>



<pre class="wp-block-code"><code>info,inputprogvers,"version 7RS(19) of 07/07/92"

info,visteam,BSN

info,hometeam,BRO

info,date,1947/04/15

info,site,NYC15

info,number,0

info,starttime,0:00PM

info,daynight,day

info,usedh,false

info,umphome,pineb101

info,ump1b,barla901

info,ump2b,(none)

info,ump3b,gorea901

info,scorer,"27,32"

info,translator,"Smith"

info,inputter,"Smith"

info,inputtime,1993/05/15 8:54PM

info,howscored,unknown

info,pitches,none

info,temp,0

info,winddir,unknown

info,windspeed,-1

info,fieldcond,unknown

info,precip,unknown

info,sky,unknown

info,timeofgame,146

info,attendance,26623

info,wp,gregh102

info,lp,sainj101

info,save,caseh101

info,gwrbi,</code></pre>



<p>The ‘start’ rows consist of 18 to 20 lines of data depending on whether the designated hitter is present in the lineup for the particular game. Each row contains the player’s unique Retrosheet ID, full name, team designation (either ‘0’ for visiting or ‘1’ for home team), batting order position and fielding position. Substitutions or ‘sub’ entries are comprised of similar fields and they appear chronologically within the play-by-play rows.</p>



<pre class="wp-block-code"><code>start,culld101,"Dick Culler",0,1,6

start,hoppj102,"Johnny Hopp",0,2,8

start,mccom101,"Mike McCormick",0,3,9

start,ellib103,"Bob Elliott",0,4,5

start,litwd101,"Danny Litwhiler",0,5,7

start,torge101,"Earl Torgeson",0,6,3

start,masip101,"Phil Masi",0,7,2

start,ryanc102,"Connie Ryan",0,8,4

start,sainj101,"Johnny Sain",0,9,1

start,stane101,"Eddie Stanky",1,1,4

start,robij103,"Jackie Robinson",1,2,3

start,reisp101,"Pete Reiser",1,3,8

start,walkd101,"Dixie Walker",1,4,9

start,hermg101,"Gene Hermanski",1,5,7

start,edwab101,"Bruce Edwards",1,6,2

start,jorgs101,"Spider Jorgensen",1,7,5

start,reesp101,"Peewee Reese",1,8,6

start,hattj101,"Joe Hatten",1,9,1</code></pre>



<p>Noteworthy information regarding the game is registered via the ‘com’ (comment) field.</p>



<pre class="wp-block-code"><code>com,"$Dodgers manager Leo Durocher suspended for the 1947 season for associating"

com,"with known gamblers; coach Clyde Sukeforth managed the team for the first"

com,"two games; debut for Jackie Robinson; debut for umpire Artie Gore"</code></pre>



<p>Play-by-play events are registered in the order in which they occur during the contest.&nbsp; This data features the inning, team (visitor or home), Retrosheet player ID, the ball-strike count when the event occurred, pitch-by-pitch description (when available) and the play/event record such as a ‘K’ for a strikeout, ‘W’ for a walk or a ‘S7’ for a single to left field.</p>



<pre class="wp-block-code"><code>play,1,0,culld101,??,,53

play,1,0,hoppj102,??,,K

play,1,0,mccom101,??,,S8

play,1,0,ellib103,??,,WP.1-2

play,1,0,ellib103,??,,W

play,1,0,litwd101,??,,8/F8D

play,1,1,stane101,??,,43

play,1,1,robij103,??,,53

play,1,1,reisp101,??,,W

play,1,1,walkd101,??,,13

play,2,0,torge101,??,,W

play,2,0,masip101,??,,6

play,2,0,ryanc102,??,,46(1)3/GDP

play,2,1,hermg101,??,,4/P

play,2,1,edwab101,??,,8/F8D

play,2,1,jorgs101,??,,W

play,2,1,reesp101,??,,9/P

play,3,0,sainj101,??,,53

play,3,0,culld101,??,,63

play,3,0,hoppj102,??,,43

play,3,1,hattj101,??,,K

play,3,1,stane101,??,,43

play,3,1,robij103,??,,7

play,4,0,mccom101,??,,S7

play,4,0,ellib103,??,,S8.1-3

play,4,0,litwd101,??,,FC1.3XH(1);1-2;B-1

play,4,0,torge101,??,,K/C

play,4,0,masip101,??,,7/L78

play,4,1,reisp101,??,,W

play,4,1,walkd101,??,,43.1-2

play,4,1,hermg101,??,,S8.2-3

play,4,1,edwab101,??,,54(1)/FO.3-H

play,4,1,jorgs101,??,,43

play,5,0,ryanc102,??,,S8

play,5,0,sainj101,??,,3/SH.1-2

play,5,0,culld101,??,,53/SH.2-3

play,5,0,hoppj102,??,,S7.3-H

play,5,0,mccom101,??,,W.1-2

play,5,0,ellib103,??,,8/P

play,5,1,reesp101,??,,D7

play,5,1,hattj101,??,,S/BG.2-3

play,5,1,stane101,??,,4/L

play,5,1,robij103,??,,64(1)3/GDP

play,6,0,litwd101,??,,HP

play,6,0,torge101,??,,E2/TH/BG.1-2

play,6,0,masip101,??,,53/SH.1-2;2-3

play,6,0,ryanc102,??,,S7.3-H(UR);2-H(UR)

play,6,0,sainj101,??,,13/SH.1-2

play,6,0,culld101,??,,3/FL

play,6,1,reisp101,??,,S7

play,6,1,walkd101,??,,S9.1-3

play,6,1,hermg101,??,,NP

sub,tatut101,"Tommy Tatum",1,4,12

play,6,1,hermg101,??,,9

play,6,1,edwab101,??,,HP.1-2

play,6,1,jorgs101,??,,NP

sub,rackm101,"Marv Rackley",1,6,12

play,6,1,jorgs101,??,,43.1-2;2-3;3-H

play,6,1,reesp101,??,,IW

play,6,1,hattj101,??,,NP

sub,steve101,"Ed Stevens",1,9,11

play,6,1,steve101,??,,K

play,7,0,hoppj102,??,,NP

sub,tatut101,"Tommy Tatum",1,4,9

play,7,0,hoppj102,??,,NP

sub,bragb101,"Bobby Bragan",1,6,2

play,7,0,hoppj102,??,,NP

sub,gregh102,"Hal Gregg",1,9,1

play,7,0,hoppj102,??,,7

play,7,0,mccom101,??,,41

play,7,0,ellib103,??,,W

play,7,0,litwd101,??,,K

play,7,1,stane101,??,,NP

sub,roweb101,"Bama Rowell",0,5,7

play,7,1,stane101,??,,W

play,7,1,robij103,??,,E3/TH1/SH.1-3;B-2

com,"$the throw hit Jackie Robinson and caromed into RF"

play,7,1,reisp101,??,,D9.3-H;2-H(UR)

play,7,1,tatut101,??,,NP

sub,coopm101,"Mort Cooper",0,9,1

play,7,1,tatut101,??,,NP

sub,vauga101,"Arky Vaughan",1,4,11

play,7,1,vauga101,??,,13.2-3

play,7,1,hermg101,??,,8.3-H(UR)

play,7,1,bragb101,??,,63

play,8,0,torge101,??,,NP

sub,furic101,"Carl Furillo",1,4,9

play,8,0,torge101,??,,K

play,8,0,masip101,??,,3/P

play,8,0,ryanc102,??,,S7

play,8,0,coopm101,??,,NP

sub,neilt101,"Tommy Neill",0,9,11

play,8,0,neilt101,??,,HP.1-2

play,8,0,culld101,??,,NP

sub,holmt101,"Tommy Holmes",0,1,11

play,8,0,holmt101,??,,7

play,8,1,jorgs101,??,,NP

sub,sists101,"Sibby Sisti",0,1,6

play,8,1,jorgs101,??,,NP

sub,lanfw101,"Walt Lanfranconi",0,9,1

play,8,1,jorgs101,??,,43

play,8,1,reesp101,??,,K/C

play,8,1,gregh102,??,,K

play,9,0,hoppj102,??,,NP

sub,schuh101,"Howie Schultz",1,2,3

play,9,0,hoppj102,??,,6/L

play,9,0,mccom101,??,,S9

play,9,0,ellib103,??,,W.1-2

play,9,0,roweb101,??,,NP

sub,caseh101,"Hugh Casey",1,9,1

play,9,0,roweb101,??,,3/FL

play,9,0,torge101,??,,K</code></pre>



<p>The ‘data’ record is currently used to track earned runs allowed for each pitcher in the game. These rows are discarded by the Opening Day Roster script.</p>



<pre class="wp-block-code"><code>data,er,sainj101,3

data,er,coopm101,0

data,er,lanfw101,0

data,er,hattj101,1

data,er,gregh102,0

data,er,caseh101,0</code></pre>



<h2 class="wp-block-heading"><strong>Walking through the process</strong></h2>



<p>Here’s the code with some commentary along the way:</p>



<p>We need to utilize two frequently-used packages containing commands that are not included in the base-R language – <strong>dplyr</strong> and <strong>sqldf</strong>.</p>



<pre class="wp-block-code"><code>install.packages("dplyr")

install.packages("sqldf")

library(dplyr)

library(sqldf)</code></pre>



<p>Next, we use the <strong>setwd </strong>to change the working directory within R Studio to the location where you extracted the Retrosheet Event files and merged them into .csv files.&nbsp;</p>



<pre class="wp-block-code"><code>setwd("C:/retrosheet/events")

# change the events_####.csv to reference the decade event file

# that you wish to import</code></pre>



<p>The <strong>read.csv</strong> command imports the designated .csv file into a dataframe named “lineups_subs”.</p>



<pre class="wp-block-code"><code>lineups_subs &lt;- read.csv("events_2020.csv", header = FALSE, sep = ",",

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;col.names = c("startsub", "retroID",

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "playerName", "visitorHome",

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "lineupPos", "fieldingPos",

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "unused1"), fill = TRUE, quote = "",

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stringsAsFactors = FALSE)</code></pre>



<p>As I noted earlier, the Retrosheet Event files include play-by-play and comments along with several other data points that are superfluous to this particular task. We’re using the <strong>subset</strong> command to remove the ‘play’, ‘com’ and ‘version’ data references first. Then we will perform another <strong>subset </strong>to remove references to umpires, weather, etc.</p>



<pre class="wp-block-code"><code>lineups_subs_filter2 &lt;- subset(lineups_subs, startsub == 'info' |

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; startsub == 'start' | startsub == 'sub' |

&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;startsub == 'id')

lineups_subs_filter &lt;- subset(lineups_subs_filter2,

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retroID != 'starttime' &amp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retroID != 'daynight' &amp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retroID != 'usedh' &amp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retroID != 'innings' &amp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retroID != 'tiebreaker' &amp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retroID != 'umphome' &amp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retroID != 'ump1b' &amp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;retroID != 'ump2b' &amp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retroID != 'ump3b' &amp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retroID != 'umplf' &amp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retroID != 'umprf' &amp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retroID != 'inputtime' &amp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;retroID != 'howscored' &amp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retroID != 'pitches' &amp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retroID != 'oscorer' &amp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retroID != 'temp' &amp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retroID != 'winddir' &amp;&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retroID != 'windspeed' &amp;&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retroID != 'fieldcon' &amp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retroID != 'precip' &amp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retroID != 'sky' &amp;&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;retroID != 'timeofgame' &amp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retroID != 'attendance' &amp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retroID != 'wp' &amp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retroID != 'lp' &amp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; retroID != 'save' )</code></pre>



<p>We’re going to iterate through the ‘lineups_sub_filter’ dataframe, but first we need to do some housekeeping and create several new variables to help us keep track of everything.</p>



<p>Let’s create a brand new dataframe called ‘lineups_subs_temp’ while retaining the same structure as ‘lineups_sub_filter’. Note: we’re renaming the ‘unused1’ column to ‘gameID’ and adding 5 new columns to the dataframe – visTeam, homeTeam, TeamYear, date and number.</p>



<pre class="wp-block-code"><code>lineups_subs_temp &lt;- lineups_subs_filter

names(lineups_subs_temp)&#91;names(lineups_subs_temp) == 'unused1'] &lt;- 'gameID'

lineups_subs_temp&#91;,'visTeam'] = NA

lineups_subs_temp&#91;,'HomeTeam'] = NA

lineups_subs_temp&#91;,'TeamYear'] = NA

lineups_subs_temp&#91;,'date'] = NA

lineups_subs_temp&#91;,'number'] = NA

lineups_subs_temp &lt;- lineups_subs_temp&#91;0, ]</code></pre>



<p>Here are the new variables for tracking information as the for-loop processes. We will track the number of rows in the new dataframe using ‘tempcounter’ . The other variables are updated when the loop processes a row in ‘lineups_subs_temp’ that matches exactly on the corresponding information.</p>



<pre class="wp-block-code"><code>tempcounter = 1

currentID &lt;- ""

currentVisTeam &lt;- ""

currentHomeTeam &lt;- ""

currentTeamYear &lt;- ""

currentDate &lt;- ""

currentNumber &lt;- "0"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # game number '0' first game

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # or first of a double-header,

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # '1' for second game of double-header</code></pre>



<p>This is where the majority of the magic happens! The variable ‘I’ counts the rows as we search through the lineups_sub_filter dataframe. Then we scan the contents of the current row (based on the value of ‘I’) using several <strong>ifelse</strong> statements to populate the currentID, currentVisTeam, currentHomeTeam, currentDate and currentNumber variables.</p>



<pre class="wp-block-code"><code>for(i in 1:nrow(lineups_subs_filter)) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # for-loop over columns

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; currentID &lt;- ifelse(lineups_subs_filter&#91;i,1] == "id", lineups_subs_filter&#91;i,2], currentID)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; currentVisTeam &lt;- ifelse(lineups_subs_filter&#91;i,1] == "info" &amp; lineups_subs_filter&#91;i,2] == "visteam", lineups_subs_filter&#91;i,3], currentVisTeam)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; currentHomeTeam &lt;- ifelse(lineups_subs_filter&#91;i,1] == "info" &amp; lineups_subs_filter&#91;i,2] == "hometeam", lineups_subs_filter&#91;i,3], currentHomeTeam)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; currentDate &lt;- ifelse(lineups_subs_filter&#91;i,1] == "info" &amp; lineups_subs_filter&#91;i,2] == "date", lineups_subs_filter&#91;i,3], currentDate)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; currentNumber &lt;- ifelse(lineups_subs_filter&#91;i,1] == "info" &amp; lineups_subs_filter&#91;i,2] == "number", lineups_subs_filter&#91;i,3], currentNumber)</code></pre>



<p>The next set of statements only fire if the value of the first column in the current row is equal to “start” or “sub”. When the statement is true, we create a record in new dataframe (lineups_subs_temp) containing the following fields:</p>



<p>date, number, visitor, home, player_Team (matching the player&#8217;s team based on status of visitorHome field &#8211; 0 or 1), startSub, retroID, playerName, lineupPos, fieldingPos</p>



<pre class="wp-block-code"><code>if(lineups_subs_filter&#91;i,1] == "start" | lineups_subs_filter&#91;i,1] == "sub") {

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lineups_subs_temp&#91;tempcounter , 1] &lt;- lineups_subs_filter&#91;i,1]

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lineups_subs_temp&#91;tempcounter , 2] &lt;- lineups_subs_filter&#91;i,2]

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lineups_subs_temp&#91;tempcounter , 3] &lt;- gsub('&#91;\"]', '',

lineups_subs_filter&#91;i,3])

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lineups_subs_temp&#91;tempcounter , 4] &lt;- lineups_subs_filter&#91;i,4]

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lineups_subs_temp&#91;tempcounter , 5] &lt;- lineups_subs_filter&#91;i,5]

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lineups_subs_temp&#91;tempcounter , 6] &lt;- lineups_subs_filter&#91;i,6]

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lineups_subs_temp&#91;tempcounter , 7] &lt;- currentID

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lineups_subs_temp&#91;tempcounter , 8] &lt;- currentVisTeam

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lineups_subs_temp&#91;tempcounter , 9] &lt;- currentHomeTeam</code></pre>



<p>We confirm whether the current player is a member of the visiting or home team and assign the &#8220;TeamYear&#8221; accordingly (i.e. NYY1983, SEA2001). Use the <strong>substr</strong> command to extract the year from the currentDate variable.</p>



<pre class="wp-block-code"><code>currentTeamYear &lt;- ifelse(lineups_subs_filter&#91;i,4] == "0",

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;paste(currentVisTeam,

substr(currentDate,1,4),sep="_"),

paste(currentHomeTeam,

substr(currentDate,1,4),sep="_"))

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lineups_subs_temp&#91;tempcounter , 10] &lt;- currentTeamYear

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lineups_subs_temp&#91;tempcounter , 11] &lt;- currentDate

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lineups_subs_temp&#91;tempcounter , 12] &lt;- currentNumber

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tempcounter &lt;- tempcounter + 1

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }

} # end of for..loop</code></pre>



<p>Once the loop completes (this can take several hours if you combined multiple event files as I did), we execute a <strong>sqldf </strong>statement to generate a new dataframe called OpeningDayRosters_temp. This dataframe will be sorted in ascending order by TeamYear, retroID, date, number.</p>



<pre class="wp-block-code"><code>OpeningDayRosters_temp &lt;- sqldf("SELECT * FROM lineups_subs_temp

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ORDER BY TeamYear ASC, retroID ASC,

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; date ASC, number ASC")</code></pre>



<p>Next, we create new columns for PlayerTeamYear and Year to assist with the sorting process.</p>



<pre class="wp-block-code"><code>OpeningDayRosters_temp$PlayerTeamYear &lt;-

paste(OpeningDayRosters_temp$retroID, 

&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OpeningDayRosters_temp$TeamYear, sep="_")

OpeningDayRosters_temp$year &lt;- substr(OpeningDayRosters_temp$gameID,4,7)</code></pre>



<p>This is where the <strong>dplyr </strong>library comes into play. We’re utilizing the <strong>group_by, mutate </strong>and <strong>slice</strong> commands.&nbsp; First, we group the rows by PlayerTeamYear. Then we use the <strong>mutate </strong>command to generate a new variable ‘gamenumber’ that contains each row’s rank based on the date. <strong>Slice</strong> using the 1:1 parameters will omit every row with the exception of those in which gameNumber is equal to 1. The resulting rows are placed into the OpeningDayRosters dataframe. In essence, we’re eliminating every game that a player participated in besides their first game of a given season.</p>



<pre class="wp-block-code"><code>OpeningDayRosters &lt;- OpeningDayRosters_temp %&gt;%

&nbsp; group_by(PlayerTeamYear) %&gt;%

&nbsp; mutate(gameNumber = rank(date)) %&gt;%

&nbsp; slice(1:1)</code></pre>



<p>Here we use <strong>sqldf</strong> again, creating a new dataframe called OpeningDayRosters25 which will be sorted by Team_Year and Date.</p>



<pre class="wp-block-code"><code>OpeningDayRosters25 &lt;- sqldf("SELECT * FROM OpeningDayRosters

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ORDER BY year ASC, TeamYear ASC, date ASC")</code></pre>



<p>Let’s change the working directory in R Studio to the C:\OpeningDayRosters subfolder. The final step is to write the dataframe out to a .csv (comma-separated values) file that you can view in a text editor or edit in a spreadsheet or database application such as Microsoft Excel, Microsoft Access, etc.</p>



<pre class="wp-block-code"><code>setwd("C:/OpeningDayRosters")

# uncomment the next line if you want to export all of the start/sub data for

# a given season or decade

# write.csv(OpeningDayRosters,"OpeningDayRosters_All_2020.csv")

write.csv(OpeningDayRosters25,"OpeningDayRosters_first25_2020.csv")</code></pre>



<p><strong>Results</strong></p>



<p>Here’s an example of the resulting output using the 1983 California Angels. The top 25 rows (from Juan Beniquez through Joe Ferguson) would be considered the Opening Day roster. </p>



<figure class="wp-block-table"><table><tbody><tr><td><strong>TeamYear</strong></td><td><strong>playerName</strong></td><td><strong>date</strong></td><td><strong>startsub</strong></td><td><strong>retroID</strong></td><td><strong>visHome</strong></td><td><strong>lineup</strong></td><td><strong>fieldPos</strong></td></tr><tr><td>CAL_1983</td><td>Juan Beniquez</td><td>4/5/1983</td><td>sub</td><td>benij001</td><td>1</td><td>1</td><td>7</td></tr><tr><td>CAL_1983</td><td>Bob Boone</td><td>4/5/1983</td><td>start</td><td>boonb001</td><td>1</td><td>9</td><td>2</td></tr><tr><td>CAL_1983</td><td>Bob Clark</td><td>4/5/1983</td><td>start</td><td>clarb002</td><td>1</td><td>2</td><td>9</td></tr><tr><td>CAL_1983</td><td>Doug DeCinces</td><td>4/5/1983</td><td>start</td><td>decid001</td><td>1</td><td>6</td><td>5</td></tr><tr><td>CAL_1983</td><td>Brian Downing</td><td>4/5/1983</td><td>start</td><td>downb001</td><td>1</td><td>1</td><td>7</td></tr><tr><td>CAL_1983</td><td>Tim Foli</td><td>4/5/1983</td><td>start</td><td>folit001</td><td>1</td><td>8</td><td>6</td></tr><tr><td>CAL_1983</td><td>Bobby Grich</td><td>4/5/1983</td><td>start</td><td>gricb001</td><td>1</td><td>7</td><td>4</td></tr><tr><td>CAL_1983</td><td>Andy Hassler</td><td>4/5/1983</td><td>sub</td><td>hassa001</td><td>1</td><td>0</td><td>1</td></tr><tr><td>CAL_1983</td><td>Reggie Jackson</td><td>4/5/1983</td><td>start</td><td>jackr001</td><td>1</td><td>4</td><td>10</td></tr><tr><td>CAL_1983</td><td>Bruce Kison</td><td>4/5/1983</td><td>start</td><td>kisob001</td><td>1</td><td>0</td><td>1</td></tr><tr><td>CAL_1983</td><td>Fred Lynn</td><td>4/5/1983</td><td>start</td><td>lynnf001</td><td>1</td><td>5</td><td>8</td></tr><tr><td>CAL_1983</td><td>Luis Sanchez</td><td>4/5/1983</td><td>sub</td><td>sancl001</td><td>1</td><td>0</td><td>1</td></tr><tr><td>CAL_1983</td><td>Daryl Sconiers</td><td>4/5/1983</td><td>start</td><td>scond001</td><td>1</td><td>3</td><td>3</td></tr><tr><td>CAL_1983</td><td>Ron Jackson</td><td>4/6/1983</td><td>start</td><td>jackr002</td><td>1</td><td>6</td><td>3</td></tr><tr><td>CAL_1983</td><td>Tommy John</td><td>4/6/1983</td><td>start</td><td>johnt001</td><td>1</td><td>0</td><td>1</td></tr><tr><td>CAL_1983</td><td>Ricky Adams</td><td>4/7/1983</td><td>sub</td><td>adamr001</td><td>1</td><td>4</td><td>5</td></tr><tr><td>CAL_1983</td><td>Rod Carew</td><td>4/7/1983</td><td>sub</td><td>carer001</td><td>1</td><td>8</td><td>11</td></tr><tr><td>CAL_1983</td><td>Dave Goltz</td><td>4/7/1983</td><td>sub</td><td>goltd101</td><td>1</td><td>0</td><td>1</td></tr><tr><td>CAL_1983</td><td>Rob Wilfong</td><td>4/7/1983</td><td>sub</td><td>wilfr001</td><td>1</td><td>8</td><td>12</td></tr><tr><td>CAL_1983</td><td>Mike Witt</td><td>4/7/1983</td><td>start</td><td>wittm001</td><td>1</td><td>0</td><td>1</td></tr><tr><td>CAL_1983</td><td>Doug Corbett</td><td>4/8/1983</td><td>sub</td><td>corbd001</td><td>0</td><td>0</td><td>1</td></tr><tr><td>CAL_1983</td><td>Geoff Zahn</td><td>4/8/1983</td><td>start</td><td>zahng001</td><td>0</td><td>0</td><td>1</td></tr><tr><td>CAL_1983</td><td>Ken Forsch</td><td>4/9/1983</td><td>start</td><td>forsk001</td><td>0</td><td>0</td><td>1</td></tr><tr><td>CAL_1983</td><td>Jack Curtis</td><td>4/10/1983</td><td>sub</td><td>curtj001</td><td>0</td><td>0</td><td>1</td></tr><tr><td>CAL_1983</td><td>Joe Ferguson</td><td>4/11/1983</td><td>start</td><td>fergj101</td><td>1</td><td>8</td><td>2</td></tr><tr><td>CAL_1983</td><td>Ellis Valentine</td><td>5/6/1983</td><td>sub</td><td>valee001</td><td>0</td><td>6</td><td>9</td></tr><tr><td>CAL_1983</td><td>Bill Travers</td><td>5/10/1983</td><td>start</td><td>travb101</td><td>0</td><td>0</td><td>1</td></tr><tr><td>CAL_1983</td><td>Byron McLaughlin</td><td>6/7/1983</td><td>sub</td><td>mclab102</td><td>1</td><td>0</td><td>1</td></tr><tr><td>CAL_1983</td><td>Curt Brown</td><td>6/10/1983</td><td>sub</td><td>browc001</td><td>1</td><td>0</td><td>1</td></tr><tr><td>CAL_1983</td><td>Mike O&#8217;Berry</td><td>6/22/1983</td><td>start</td><td>oberm001</td><td>0</td><td>9</td><td>2</td></tr><tr><td>CAL_1983</td><td>Rick Burleson</td><td>6/30/1983</td><td>start</td><td>burlr001</td><td>1</td><td>1</td><td>6</td></tr><tr><td>CAL_1983</td><td>Steve Lubratich</td><td>7/20/1983</td><td>start</td><td>lubrs101</td><td>1</td><td>2</td><td>5</td></tr><tr><td>CAL_1983</td><td>Mike Brown</td><td>7/21/1983</td><td>start</td><td>browm002</td><td>1</td><td>7</td><td>9</td></tr><tr><td>CAL_1983</td><td>Rick Steirer</td><td>7/22/1983</td><td>sub</td><td>steir001</td><td>1</td><td>0</td><td>1</td></tr><tr><td>CAL_1983</td><td>Steve Brown</td><td>8/1/1983</td><td>start</td><td>brows001</td><td>0</td><td>0</td><td>1</td></tr><tr><td>CAL_1983</td><td>Bob Lacey</td><td>9/8/1983</td><td>sub</td><td>laceb001</td><td>0</td><td>0</td><td>1</td></tr><tr><td>CAL_1983</td><td>Jerry Narron</td><td>9/8/1983</td><td>sub</td><td>narrj001</td><td>0</td><td>6</td><td>11</td></tr><tr><td>CAL_1983</td><td>Gary Pettis</td><td>9/8/1983</td><td>start</td><td>pettg001</td><td>0</td><td>1</td><td>9</td></tr><tr><td>CAL_1983</td><td>Dick Schofield</td><td>9/8/1983</td><td>sub</td><td>schod001</td><td>0</td><td>9</td><td>6</td></tr></tbody></table></figure>



<p>Again, the entire data set is available here:</p>



<p><a href="https://docs.google.com/spreadsheets/d/e/2PACX-1vRrSOoOTDuTYYrd9jfwNj7Tt4WLWrJBIwu-ASxDCuYc9035HOW2cB7V-91dhu_YWmbPeuzH55kYHR9P/pubhtml">https://docs.google.com/spreadsheets/d/e/2PACX-1vRrSOoOTDuTYYrd9jfwNj7Tt4WLWrJBIwu-ASxDCuYc9035HOW2cB7V-91dhu_YWmbPeuzH55kYHR9P/pubhtml</a></p>



<p>I would encourage you to venture forward with R or the programming language of your choice. You may wish to utilize this script in its original form or as a basis to mine the event files further as you seek answers within the play-by-play and other records contained in this amazing data set!</p>



<h2 class="wp-block-heading"><strong>References and Resources</strong></h2>



<p>Adler, Joseph. Baseball Hacks: Tips &amp; Tools for Analyzing and Winning with Statistics.</p>



<p>Sebastopol, CA: O’Reilly Media, 2006. Print.</p>



<p><em>Baseball-Reference. </em>Web. &lt; <a href="http://www.baseball-reference.com">http://www.baseball-reference.com</a> &gt;.</p>



<p>Marchi, Max and Albert, Jim. Analyzing Baseball Data with R. Boca Raton, FL: CRC Press, 2014. Print.</p>



<p><em>Retrosheet</em>. Web. &lt; <a href="http://www.retrosheet.org">http://www.retrosheet.org</a> &gt;.</p>



<p>The information used here was obtained free of charge from and is copyrighted by Retrosheet.&nbsp; Interested parties may contact Retrosheet at &#8220;www.retrosheet.org&#8221;.</p>



<h2 class="wp-block-heading">About the Author</h2>



<p>I am a New Jersey native with a passion for baseball, statistics, computers and video games who enjoys spending quality time with his family.</p>



<p>“<a href="https://www.amazon.com/Hardball-Architects-Construction-Performance-Acquisition/dp/1097334988/"><strong>Hardball Architects – Volume 1 (American League)</strong></a><strong>&#8220;, </strong>published in July 2020<strong> </strong>and<strong></strong><br>&#8220;<a href="https://www.amazon.com/Hardball-Architects-Construction-Performance-Acquisition/dp/B09YNH354F/"><strong>H</strong><strong>ardball Architects – Volume </strong><strong>2 (National League)</strong></a><strong>”, </strong>published in April 2022, examines the trades, free agent acquisitions, draft picks and other transactions for the 30 Major League Baseball franchises, divided into a 2-volume set. Both books are available in paperback and digital (Kindle) format at Amazon.com. All key moves are scrutinized for every team and Sabermetric principles are applied to the roster construction throughout the lifetime of the organization to encapsulate the hits and misses by front office executives. Team performances are analyzed based on transaction type with graphs depicting the WAR (Wins Above Replacement) in every decade. Individual results for each player-transaction is charted over the duration of their stint with the franchise. Every team chapter includes All-Time Rosters and Single-Season Leaders based on transaction type. The Team Trade Record chronicles the WAR and WS (Win Shares) accumulated by players acquired in comparison to those traded to opposing teams.&nbsp;The opening chapter is devoted to the Evolution of the General Manager and incorporates a discussion with former Dodgers GM Fred Claire (along with former Angels and Red Sox GM Mike Port and current Reds GM Nick Krall in Volume 2) on a variety of front office topics.</p>



<p>“<strong>Hardball Retroactive”, </strong>published in June 2018, is available in <a href="https://www.amazon.com/Hardball-Retroactive-Derek-J-Bain/dp/1979618720/">paperback</a> and digital (<a href="https://www.amazon.com/Hardball-Retroactive-Derek-Bain-ebook/dp/B07DZ1LBHX/">Kindle</a>) format at Amazon.com.<strong>&nbsp; <u>Hardball Retroactive</u> </strong>is a modest collection of selected articles that I have written for Seamheads.com along with my Baseball Analytics blog since 2010. Exclusive content includes the chapter on &#8220;Minors vs. Majors&#8221; which assesses every franchise&#8217;s minor league successes and failures in relation to their major league operations.</p>



<p><strong>“Hardball Retrospective”</strong> is available in <a href="http://www.amazon.com/Hardball-Retrospective-Evaluating-Development-Modern-Era/dp/150879099X/">paperback</a> and digital (<a href="http://www.amazon.com/Hardball-Retrospective-Evaluating-Development-Modern-Era-ebook/dp/B00RO4FC26">Kindle</a>) format at Amazon.com.<strong>&nbsp;</strong><a href="https://www.tuatarasoftware.com/statistics.html">Supplemental Statistics, Charts and Graphs</a> along with a discussion forum are offered at <a href="https://www.tuatarasoftware.com/">TuataraSoftware.com</a>. In Hardball Retrospective, I placed every ballplayer in the modern era (from 1901-present) on their original teams. Using a variety of advanced statistics and methods, I generated revised standings for each season based entirely on the performance of each team’s “original” players. I discuss every team’s “original” players and seasons at length along with organizational performance with respect to the Amateur Draft (or First-Year Player Draft), amateur free agent signings and other methods of player acquisition. Season standings, WAR and Win Shares totals for the “original” teams are compared against the real-time or “actual” team results to assess each franchise’s scouting, development and general management skills.</p>



<p>Don Daglow (Intellivision World Series Major League Baseball, Earl Weaver Baseball, Tony LaRussa Baseball) contributed the foreword for Hardball Retrospective. The foreword and preview of my book are accessible&nbsp;<a href="http://www.barnesandnoble.com/sample/read/2940149864263">here</a>.&nbsp;</p>



<p><strong>“Hardball Retrospective &#8211; Addendum 2014 to 2016” </strong>supplements my research for Hardball Retrospective, providing retroactive standings based on Wins Above Replacement (WAR) and Win Shares (WS) for each &#8220;original&#8221; team over the past three seasons (2014-2016). Team totals from 2010 &#8211; 2013 are included for reference purposes. “Addendum” is available in <a href="https://www.amazon.com/Hardball-Retrospective-Addendum-2014-2016/dp/1976503221/">paperback</a> and digital (<a href="https://www.amazon.com/gp/product/B075CG8MLT/">Kindle</a>) format at Amazon.com.<strong>&nbsp;</strong></p>
<p><a class="a2a_button_facebook" href="https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fwww.tuatarasoftware.com%2F2023%2F05%2F31%2Fgenerating-opening-day-rosters-from-retrosheet-event-files-using-r%2F&amp;linkname=Generating%20Opening%20Day%20Rosters%20from%20Retrosheet%20Event%20Files%20Using%20R" title="Facebook" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_linkedin" href="https://www.addtoany.com/add_to/linkedin?linkurl=https%3A%2F%2Fwww.tuatarasoftware.com%2F2023%2F05%2F31%2Fgenerating-opening-day-rosters-from-retrosheet-event-files-using-r%2F&amp;linkname=Generating%20Opening%20Day%20Rosters%20from%20Retrosheet%20Event%20Files%20Using%20R" title="LinkedIn" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_bluesky" href="https://www.addtoany.com/add_to/bluesky?linkurl=https%3A%2F%2Fwww.tuatarasoftware.com%2F2023%2F05%2F31%2Fgenerating-opening-day-rosters-from-retrosheet-event-files-using-r%2F&amp;linkname=Generating%20Opening%20Day%20Rosters%20from%20Retrosheet%20Event%20Files%20Using%20R" title="Bluesky" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd a2a_counter addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Fwww.tuatarasoftware.com%2F2023%2F05%2F31%2Fgenerating-opening-day-rosters-from-retrosheet-event-files-using-r%2F&#038;title=Generating%20Opening%20Day%20Rosters%20from%20Retrosheet%20Event%20Files%20Using%20R" data-a2a-url="https://www.tuatarasoftware.com/2023/05/31/generating-opening-day-rosters-from-retrosheet-event-files-using-r/" data-a2a-title="Generating Opening Day Rosters from Retrosheet Event Files Using R"></a></p>]]></content:encoded>
					
					<wfw:commentRss>https://www.tuatarasoftware.com/2023/05/31/generating-opening-day-rosters-from-retrosheet-event-files-using-r/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
