Empirical Research in Accounting: Tools and Methods

Course book for accounting research
Authors
Affiliations

Ian D. Gow

Unaffiliated

Tongqing Ding

University of Melbourne

Published

13 Oct 2026

Preface

Note

This is the published R edition of the book. A Python version of the book is available at era_pl_book.

Welcome

This is the on-line version of Empirical Research in Accounting: Tools and Methods by Ian D. Gow and Tony Ding, which was published by CRC Press in December 2024.

This book provides a course on financial accounting research that begins at an upper-undergraduate (“honours”) or introductory PhD level. One goal of the course, like most PhD courses, is to prepare PhD students to take further research courses and to go on to do their own research. Another goal of the course is to provide students with a set of skills that is useful in other domains, such as consulting or finance. This second goal stems from the origins of parts of this course in a joint honours-PhD course at the University of Melbourne, where the honours students are undergraduates completing an additional year of study with a focus on research. While some honours students progress to PhD studies, most elect to take jobs in industry, such as consulting, auditing, or public service.

Features of this book

Some features of this book mean that a course based on it will be distinguished from a more traditional PhD-level course in a number of respects that we discuss here.

Pedagogically driven selection of papers

Many syllabuses for PhD courses in accounting focus on recent papers with a view to giving students a sense of the current themes and trends in research to help students spot gaps in the literature that they can fill with their own research. We view such courses as complementary to this course, but take a different approach.

Aiming to provide a more fundamental understanding of accounting research, the selection of papers in this course is driven more by pedagogical goals than an attempt to represent the current state of play in accounting research. In some cases, this means covering older papers (e.g., Ball and Brown, 1968), but in other cases we use a recent paper that features a core idea or approach.

Incorporation of data analysis skills

A second feature that distinguishes this course from most PhD courses in accounting is an emphasis on data analysis skills, which are woven into the course throughout. While it might have been possible to make this a course focused exclusively on such skills, it is our view that these skills are best learned through applying them to real research questions. Conversely, we believe that being able to pull data, run simulations, and get more involved with critical elements of the research process engenders a better understanding of research.

We build data analysis and computing skills into the course at each step in a systematic way. In practice, research computing skills are the bread and butter of a researcher’s toolkit but are generally neglected in PhD programs’ formal curricula. The prevailing ethos seems to be that research computing skills are acquired informally from other students, through research assistantships and collaboration with faculty members, and so on.

In some doctoral programs, this approach may work to a degree. But in many doctoral programs, such informal learning fails to prepare students adequately. For example, if students’ collaboration with faculty members is informal and related to collaboration on papers where the students do the data analysis with limited or no hands-on guidance from the faculty member, then the opportunity for clear and comprehensive guidance is limited.

Greater emphasis on research design and methods

Accounting research is overwhelmingly an empirical discipline seeking to draw causal inferences and, as such, significant research training should be focused on research design issues. Part III of the book examines causal inference in depth, including natural experiments, regression discontinuity designs, instrumental variables, and fixed effects. However, we will see that there are flaws in the common belief that it is these techniques that offer hope for warranted causal inference, rather than the settings in which they can be deployed. Throughout the course, we will offer a broader set of tools for making inferences about real-world phenomena.

In this course, we strive to give students the skills that are needed to conduct the analyses that we cover. We believe that understanding of statistical and econometric techniques by accounting researchers is more likely to be enhanced by hands-on simulation analysis than by analysis of consistency and asymptotic variance of estimators. By building in the data analysis skills needed to perform such simulations, we hope that this course provides a platform for accounting researchers to think more carefully about the properties of their estimators. A core commitment we make in this book is that every analysis we present can be conducted by the reader using the code found herein.

Prerequisites

We presume prior knowledge of some topics and access to certain computing resources. We have endeavoured to keep these requirements to a minimum.

  1. Knowledge of accounting and business. In terms of accounting, we assume a solid understanding of the content of an introductory financial accounting course and enough understanding of business to make sense of accounting.

  2. Prior exposure to statistics and econometrics. Some familiarity with the elements of statistical inference and ordinary least-squares (OLS) regression will be helpful. While we do provide some introductory material on elements of these in Chapters 3  Regression fundamentals–5  Statistical inference, this is selective and it may help to use a textbook to brush up on these topics as you work through the book.

  3. Access to academic journals. The course makes extensive use of papers in academic journals. If you are a faculty member, researcher, or student at an academic institution, then you should be able to access the papers we use through your library. Some universities provide a service (perhaps for a fee) for alumni access to academic journals. Unfortunately, if you cannot access the papers, it will be difficult to make full use of this course book beyond Part I.

  4. Access to a computer and the internet. To accommodate a broader audience and minimize set-up costs, we assume nothing of the reader other than access to a computer and the internet and basic proficiency in using these.

  5. Ability to install R and RStudio. In this course, while we focus on R, a popular open-source programming language for statistics and data science, we do not assume any knowledge of R in this course. 2  Describing data provides an introductory tutorial on R and RStudio. We hope that this provides the required platform for later chapters whether you are a complete novice or coming to R from another statistical software system. Throughout the book, we direct the reader to additional resources for learning more detail than we can fit in this book. With the occasional detour to resources like R for Data Science, working through this book should provide the reader with a strong set of data science skills.1 Our hope is that these skills will prove useful whether you continue down the path of academic research or pursue a position in practice.

  6. Access to WRDS data. Because it is difficult to go very far in accounting research without WRDS data, this book is targeted at the reader who has a WRDS account. If you do not have a WRDS account but are eligible for one (e.g., you are a graduate student, researcher, or faculty member at a WRDS-subscribing institution), then you should apply for such an account.2

A guide for readers

The book is written so as to be fairly accessible to a novice reading independently (subject to the prerequisites outlined above). We recommend that such readers work through the first few chapters in order, including running the code, completing the exercises, and thinking about the discussion questions. That said, some elements of the exercises and discussion questions are subtle and having an instructor or someone to discuss these with will help you to get the full value from this material.

We hope that this book will be useful to a variety of readers, learners, and instructors beyond the novices. Below we discuss possible approaches for some hypothetical readers.

  • I am interested in learning more about issues related to research design and causal inference. You might find you can dive into Chapters 2  Describing data and 4  Causal inference, then move to 17  Natural experiments and subsequent chapters.

  • I am interested in learning more about issues related to research design and causal inference, but I don’t really want to learn R. The plan for the hypothetical reader in the previous bullet point likely works. Even if you aren’t interested in learning R, we think that running the code helps solidify understanding and that what the code is doing is sufficiently clear that copy-pasting the code into your own computer should be enough to get the gist of what is going on.

  • I have heard about R and would like to learn more about it. Chapters 2  Describing data and 3  Regression fundamentals cover some of the basics. But if you’re already proficient in something like SAS or Stata, you may find it pretty easy to skip those chapters (after meeting the prerequisites above) and go to a chapter that aligns with your research interests, and see if you can figure out what the code is doing as you work through it. We have deliberately written the book so that, apart from initial set-up in Setting up your computer, code in each chapter is independent of that in the others.

Acknowledgements

While this book draws on materials we have been using for many years, writing this book began in earnest in early 2021. Since then we have received help from many others, ranging from supplying code and data, suggestions on content, feedback on drafts, and simply encouragement to persist with the project. We would like to recognize the help of Ulrich Atz, Andrew Baker, Ray Ball, Jeremy Bertomeu, Stu Black, Mark Bradshaw, Philip Brown, Jade Shizhe Chen, Patty Dechow, Jenny Zha Giedt, Lucy Gow, Amy Hutton, Rohit Kattamuri, James Kavourakis, David Larcker, Changju Lee, Andy Leone, Ying Liang, Christian Leuz, Miguel Minutti-Meza, Casey Mulligan, Matt Pinnuck, Steve O’Byrne, Shiva Rajgopal, Mario Schabus, Stefan Schantl, Richard Sloan, Dan Taylor, Jake Thomas, Jake Thornock, Stephen Walker, Charlie Wang, Yihong Wang, Eddie Watts, and Anastasia Zakolyukina.

We also thank the many students who suffered through earlier versions of the materials here, including students at Deakin, Harvard, Melbourne, Michigan, and Wharton. Quinn Swanquist taught a PhD class at the University of Alabama using an earlier version of the book. We thank Quinn and his students—Susan Rykowski, Amy Mathews, and Jack Archer—for providing detailed feedback.

Some notes on style

We follow British (hence Australian) conventions for the most part. Reflecting the enduring influence of a Pocket Oxford Dictionary one of us received at age seven, we tend to use “-ize” spellings instead of “-ise” spellings (in any case, these are more familiar to American readers). Also we likely use the Oxford comma more often than not. One benefit of our choice is that we do not have to follow the prescription of American English that commas and full stops (periods) always go inside quotes and can instead put them where they naturally belong (i.e., where speakers of languages other than American English put them) even if this produces sentences that may look odd to some American readers. (It’s hard to disagree with Hadley Wickham—the lead author of the Tidyverse—on this point: “That is literally the stupidest rule in American English and I refuse to follow it.”)

For code, we largely follow the Tidyverse style guide for R code, except that we often put the first item after the assignment operator (<-) on a new line.

Timeline of updates

  • January 2025
    • Added errata section to this page
  • October 2024
    • Many corrections in advance of publication
  • March 2024
    • Finalized chapter on matching
    • Replaced discussion of history of econometrics in 4  Causal inference
    • Extensive proofreading
    • More discussion of code
    • Added “alt text” for most figures
  • February 2024
    • Many changes to increase consistency of code
    • Switch to use of stringr functions throughout
    • Improved adherence to R style guidelines
    • Added many index entries (PDF version)
  • January 2024
  • November 2023
    • Added chapter on GLMs
    • Added appendix on parquet data
  • October 2023
    • Added material on extreme values and matching
    • Prepared templates for Part III
  • July 2023
    • Converted source code from bookdown to Quarto. One benefit is a much better search engine for this site
    • Switched from the magrittr pipe (%>%) to the native pipe (|>).
    • Updated references to R for Data Science given recent release of the second edition of that book
    • Switched to native form of anonymous functions (\(x))
    • Migrated from stargazer to modelsummary
    • Migrated from lfe to fixest
  • April 2023
    • Prepared templates for most of Part I and Part II
    • Polished material on the efficient markets hypothesis
    • Polished chapter on event studies
  • February 2023
  • January 2023
  • September 2022
    • Added material on Zhang (2007) to 13  Event studies (event studies)
    • Refined chapter on matching
  • August 2022
    • Added material on Beaver (1968).
  • July 2022
    • Added more material to SQL primer (appendix)
  • June 2022
  • April 2022
    • Filled out chapter on accrual anomaly (Sloan, 1996)
    • Added chapter on earnings management mostly focused on DSS (1995)
  • January 2022
    • Added separate chapter on FFJR (1969)
    • Added separate chapter on Ball and Brown (1968)
  • November 2021
    • Added chapter on RDD
    • Added simulation from Leone et al. (2019)
  • October 2021
    • Added chapter on natural experiments
  • July 2021
    • Added chapter on panel data
    • Extensive revisions to material on IV

If you have comments or requests, please feel free to contact either Ian or Tony. Alternatively, you may create a new issue describing your suggestion in the repository for the companion package for this course here.

Errata

The errata below cover typos, typesetting issues and other corrections. Code fixes and updates are listed separately. Page numbers refer to the hardback version of the book. All of these errata have been fixed in the online version.

Typos, typesetting issues and other corrections

  • p. 4 (correction): The Part IV overview should name generalized linear models rather than selection models.
  • p. 27 (typesetting): Add space to mutate(roe = ib / ceq).
  • p. 47 (typo): In “if you highlight the text from test_scores |>”, reference to test_scores should be to camp_scores.
  • p. 54 (typo): In the first full paragraph, the two references to size should be to cfo to match the code below.
  • p. 55 (typo): Replace size with cfo in “there is no visually discernible relation between size…”.
  • p. 59 (typesetting): Extra space after paragraph that begins with “Making causal inferences …”.
  • p. 60 (typo): Add apostrophe to get “researchers’ focus”.
  • p. 60 (typo): Remove comma from \(\mathbb{E}[X, \epsilon] \neq 0\).
  • p. 61 (typo): Change “of” to “off” to get “read off an estimate”.
  • p. 63 (typesetting): Remove space from “text book” for consistency.
  • p. 63 (typo): Change \(\alpha := \left(\alpha_0, \alpha_1, \alpha_2 \right)\) to \(\alpha := \left(\alpha_0, \alpha_2, \alpha_3 \right)\).
  • p. 64 (typo): In Q1 of the Section 4.1 exercises, \(\alpha\) should be \((\alpha_0, \alpha_2, \alpha_3)\), matching the corrected definition on p. 63. In Q5, industry corresponds to \(x_{i2}\), not \(x_{i3}\).
  • p. 64 (typo): Change “The section provides” to “This section provides”.
  • p. 64 (typo): Replace “either \(X\) and \(Z\), or \(Y\) and \(Z\)” with “\(Z\) with \(X\) or \(Y\)”.
  • p. 66 (typo): Replace “but that we” with “but we”.
  • p. 68 (typesetting): Add comma after “That is” before “regress”.
  • p. 69 (typo): Change “generalization of linear model” to “generalization of a linear model”.
  • p. 70 (typo): In Q2 of the Section 4.3 exercises, the reference should be to Table 4.1 (income regressions), not Table 4.2 (admissions regressions).
  • p. 71 (typesetting): Paragraph at bottom of page should be indented to make it clearer that it’s part of Q2.
  • p. 72 (typesetting): Paragraph below Figure 4.7 should go before it to make it clearer that it’s part of Q3.
  • p. 74 (typo): Word should be “causal” not “casual”.
  • p. 79 (typo): get_hgt_sample” should be get_hgt_sample() to be consistent with other code in the book (i.e., function references always include ()).
  • p. 95 (typo): Remove word “is” before “addresses concerns”.
  • p. 95 (typo): Replace words “cross-section than” with “cross-sectional dependence than”.
  • p. 95 (typo): Replace word “warrant” with “justify”.
  • p. 96 (typo): Replace “use” in “We first estimate use nest() …” with word “using”.
  • p. 101 (typo): Replace “cross-section than” with “cross-sectional dependence than”.
  • p. 103 (typo): Replace “paper” with “papers”.
  • p. 105 (typo): References to pg should be to db.
  • p. 105 (typo): Replace “onto” with “on”.
  • p. 120 (typo): In Q5, floor_date("month", date) should be floor_date(date, "month") to match code below.
  • p. 122 (typo): Add the words “is that” after “The basic idea of crsp.ccmxpf_lnkhist”.
  • p. 125 (typo): Remove the unnecessary comma after lead(linkdt) in code counting the number of overlapping rows.
  • p. 125 (typo): In footnote, replace “actually already use” with “actually already used”.
  • p. 127 (typo): Add by = before join_by() in code creating rdq_permnos. Change has no effect, but maintains consistency with other nearby queries.
  • p. 131 (typo): Reference to gkvey should be to gvkey.
  • p. 133 (typesetting): The question beginning “General Motors Corporation declared bankruptcy in June 2009” was omitted from the end-of-chapter exercises. It has been added as the final exercise in the online version.
  • p. 138 (typo): Remove (unhelpful) hint from Q6.
  • p. 146 (typo): In footnote 9, replace Siccodes12.zip with Siccodes48.zip in the URL for the 48-industry definitions.
  • p. 160 (typesetting): In Q2 amount/amount_left_on_table should be amount / amount_left_on_table to be consistent with other code in the book.
  • p. 161: Use mode = "wb" with download.file().
  • p. 177 (typo): In footnote, “backed” should be “backend”.
  • p. 182 (typo): Add the word “for” after “accounting income” to get “accounting income for a period”.
  • p. 184 (typo): Sentence beginning with “Does this also mean …” should end with “?” not “.”.
  • p. 185 (typo): Q5 should end with “?” not “.”.
  • p. 192: Add full stop after crsp.msf (just before assignment to me_values).
  • p. 193 (correction): Attribute the return-accumulation method to Nichols and Wahlen (2004), not Ball and Brown (1968).
  • p. 195 (typo): In Q6, “the function pivot_wider” should be “pivot_wider()” to be consistent with other code in the book (i.e., function references always include ()).
  • p. 197 (typo): Delete the word “the” (fourth word on page).
  • p. 197 (typo): Add word “you” after “Why do” in Q6.
  • p. 203 (typo): The single-event figure plots trading volume. Its caption should be “Trading volume around earnings announcement: Single event,” not “Return volatility around earnings announcement: Single event.”
  • p. 204 (typo): In the exchange-code footnote, the header variable is hexcd, not the historical exchcd in crsp.stocknames. The code uses the historical records over namedt–nameenddt to check NYSE membership at the announcement date; it does not ignore exchange history.
  • p. 213 (typo): Replace “Inspired by , see 12” with “Inspired by Beaver (1968) (see Chapter 12)”.
  • p. 216 (clarification): Add a footnote describing Zhang (2007)’s additional US-trading and low-price screens and care with mismatched market closures. The illustration retains its Toronto composite benchmark and existing calculations. The data query covers 2000–2002, rather than only 2001 and 2002.
  • pp. 217–218 (typo): The two references to “Panel D of Table 1” in the Zhang (2007) illustration should be to “Panel D of Table 2”.
  • p. 221 (correction): Replace “Fedex” with “Toyo Denki Seizo” in the fiscal-year example.
  • p. 225 (typo): Replace year and month with year() and month() respectively to be consistent with the rest of the book.
  • p. 227 (typo): In the sentence beginning “Presumably the idea …”, the second comp.funda should be comp.fundq.
  • p. 245 (typo): Changed footnote to: “This is one definition that can be tightened and that varies by context.”
  • p. 246 (typo): Formula for accruals comes from p. 107 of Hribar and Collins (2002), not p. 10.
  • p. 246 (typo): Change \(\Delta \mathit{DEP}\) to \(\mathit{DEP}\).
  • p. 247 (typo): Change “cash flow from operations” to “cash flows from operations” in Q3.
  • p. 253 (typo): Replaced last sentence discussion finance indicator variable. Note that the way this variable is used in code is less than ideal (filter should be applied earlier) and this could be a discussion point in class. I retained existing code to avoid creating an inconsistency between the print and online books.
  • p. 255 (typesetting): Fixed indentation for code creating ccm_link.
  • p. 255 (typo): Replaced “permnos” with “permno values”.
  • p. 257 (typo): Sentence starting “Some degree of …” should have “… similarity of the values seen in Table 15.2 …”.
  • p. 263 (typo): Change “cash flow from operating” to “cash flows from operating” in Q5.
  • p. 268 (typesetting): Added page reference for Green et al. (2011) quotation in Q2. Also added citations in the quote to references list for the book.
  • p. 268 (typo): Reference to Q1 in Q3 should be to Q2.
  • p. 268 (typesetting): Word “Hint” is not italicized to match other chapters.
  • p. 269 (typo): Replace ‘just one form a wide class of “discretionary behaviour”’ with ‘just one form in a wide class of “discretionary behaviours”’.
  • p. 277 (typo): References to the variable type in results should be to the variable measure.
  • p. 278 (typo): Replace “earning management” with “earnings management” in table caption.
  • p. 285 (typo): Replace “earning management” with “earnings management”.
  • p. 286 (typo): Output from the final system_time() call, creating power_plot_data, was omitted. The earlier timing output for manip_df is present.
  • p. 286 (typesetting): Fixed spacing in function h_test_5().
  • p. 295 (typo): Replace “their seriousness” with “the seriousness”.
  • p. 304 (typo): Move comma from after “analysis” to after “above”.
  • p. 307 (correction): New text clarifies that Snow conducted two separate investigations.
  • p. 311 (typo): Add the word “the” before “MSHA website”.
  • p. 315 (typo): Q3 should start with “According to the …” not “According the …”.
  • p. 340 (correction): Distinguish Kothari et al.’s Modified Jones estimation from FHK’s coefficient substitution and correct the FHK citations.
  • p. 346 (typo): In FHK: Data steps Q7, replace controls_fyear with controls_filled.
  • p. 349 (typesetting): The filter in Q8 should be filter() to be consistent with other code in the book.
  • p. 352 (correction): Use firm fixed effects in the observed models as specified in the prose and in the randomization draws.
  • p. 352 (typesetting): Added explanatory sentence: “An alternative approach uses future_map() from furrr to run a variant of this code in parallel.”
  • p. 359 (correction): In the canonical-diagram paragraph beginning “Our reasoning”, the causal effect is that of \(X\) on \(Y\), not \(Y\) on \(X\).
  • p. 359 (typo): In the draft-lottery paragraph, replace “determinate” with “determine”.
  • p. 360 (correction): In the projection-matrix paragraph, symmetry is \(P_W^{\mathsf{T}} = P_W\).
  • pp. 364–365 (correction): In the generated-instruments example, the independent noise terms \(\eta_j\), not their standard deviations, follow \(N(0, \sigma_{\eta}^2)\). Also close the code formatting around generate_ivs() in the following paragraph.
  • p. 370 (correction): In discussion question 4, cite Ahern and Dittmar (2012), not (2016).
  • pp. 371–372 (correction): In the Sneetches scenario, the error has variance \(\sigma_{\epsilon}^2\), and the code generates \(z_i\) (z) rather than \(\gamma_i\) (gamma).
  • p. 373 (typo): Replace “namely means” with “i.e.,”.
  • p. 380 (typo): Replace “perhaps help us” with “perhaps helps us”.
  • p. 380 (correction): In the AMD example, sales for “4 Customers” are $1,250 million.
  • p. 383 (typesetting): Code creating disclosure was indented by four spaces. Should be two spaces.
  • p. 386 (clarification): Add words “the first two columns of” to “The results reported in”. Also add clarifying footnote.
  • p. 386 (typo): Replace “year related to adoption” with “year relative to the year of adoption”.
  • p. 386 (clarification): Omitted time-varying controls and state effects for firms that move can affect estimates despite firm fixed effects. The teaching regressions use IID standard errors; the paper clusters by state.
  • pp. 388–389 (typesetting): Footnote on p. 389 about align argument belongs on p. 388.
  • p. 389 (typo): First sentence of Q1 should end with “.” not with “?”.
  • p. 394 (typo): “\(\gamma_2 D_i x_i\)” should be “\(\gamma_1 D_i x_i\)”.
  • p. 394 (correction): Center the running variable at the cutoff in the polynomial equation. The criticism concerns high-order global polynomials.
  • p. 395 (correction): In the fuzzy-RDD derivation, the instrument is the threshold indicator and the treated outcome includes \(\rho\). The outcome jump is \(\pi\rho\); divide by the treatment-probability jump \(\pi\) to recover the treatment effect.
  • p. 396 (typo): “In response to such concerns.” should be “In response to such concerns,”.
  • pp. 396–397 (correction): The initial SOX 404 requirement applied to accelerated filers, generally with public float of at least $75 million. Non-accelerated filers began management reporting for fiscal years ending on or after 15 December 2007 and were exempted from auditor attestation in 2010.
  • p. 397 (typo): Add word “not” to get “did not require auditor attestation”.
  • p. 398 (typo): “Use the firm …” should be “Using the firm …”.
  • p. 398 (clarification): In the filing example, accelerated-filer status depends on the public-float measurement date and other eligibility criteria, including small-business reporting-form eligibility.
  • p. 402 (clarification): The joint treated/post contrast is unadjusted. Distinguish it from a complete difference-in-differences specification and clarify how the teaching regressions differ from Bloomfield’s time effects and inference.
  • p. 403 (typo): Reference to auopin should be to auopic.
  • p. 403 (typo): Sentence ending with “each” should end with “each side of the cutoff”.
  • p. 404 (typo): In caption for Figure 22.2, add word “indicator” to say “SOX 404 report indicator” to make caption consistent with that for Figure 22.1.
  • p. 409 (typo): “inherently estimated” should be “inherently estimates”.
  • p. 411 (typesetting): Removed extra space in fyr < 11.
  • p. 419 (typo): Denominator in expression at the bottom of the page should be \(x_j\), not \(x_i\).
  • p. 420 (typo): Should be “… density function and the coefficient \(\beta_j\)” (i.e., not \(\beta_i\)).
  • p. 427 (typo): Remove word “below” from “following line of code below”.
  • p. 427 (typo): Replace “you many not need” with “you may not need”.
  • p. 431 (typo): Remove word “named” from sentence ending “above named”.
  • p. 431 (typo): Add word “function” after load_parquet() in footnote 13. Delete word “function” after read_parquet() in the same footnote.
  • p. 433 (typo): “increase from 1994 to 1995” should be “a significant increase from 1994 to 1995”.
  • p. 444 (typo): Replace “filings” with “filing” in “… around 10-K filings dates”.
  • p. 445 (typo): Remove word “use” from “can use collect”.
  • p. 448 (typo): “we saw winsorization in Chapter 25” should refer to Chapters 19 and 22.
  • p. 449: Remove all references to company, which was not used in the code.
  • p. 449 (typo): Remove words “fixed effects and” (code does not include fixed effects).
  • p. 452 (typo): “left half of Table 5 … (i.e., \(\beta_1 = 0\))” should be “left half of Table 5 … (i.e., \(\beta_1 = 0.8\))”.
  • p. 455 (typo): Change “assumed the independent of regressors” to “assumed to be independent of the regressors”.
  • p. 455 (typo): “strikingly difference estimates” should be “strikingly different estimates”.
  • p. 458 (typo): Add word “the” to “claim that Poisson regression”.
  • p. 459 (typo): Add missing left-quote around “misunderstanding” in Q5.
  • p. 459 (typo): “versions of the confounding variable” should be “versions of the dependent variables”.
  • p. 463 (typo): “the impact of” should be “the impacts of”.
  • p. 466 (typo): Delete “different” from “consider different two”.
  • p. 474 (typo): Replace “use matchit() function the” with “use the matchit() function from the”.
  • p. 476 (typo): Delete second of two commas in “as, , respectively”.
  • p. 482 (typo): Delete word “of” after “Equation (1)” in question 2.
  • p. 482: For clarity’s sake, replace “results presented above” in Q1 with “results presented in Table 25.7”.
  • p. 493 (correction): Bao et al. (2020) use fiscal 2000–2001 for validation, rather than fiscal 2001 alone.
  • p. 500 (typo): In the investigation-budget example, the regulator can investigate \(k\) cases, rather than \(k\) known frauds.
  • p. 504 (typesetting): Change auc in Q4 to auc() to be consistent with other code in the book.
  • p. 514 (typo): In Q3 of the Section 26.9 exercises, the AUC of 0.7228 in Panel B of Table 1 of Bao et al. (2022) is for RUSBoost, not the all-features logit model. Q4 correctly reports the all-features logit AUC of 0.6842.
  • p. 519 (typo): In the vector example, “This \(y_i\) is an \(n\)-tuple” should refer to the vector \(y\).
  • p. 519 (correction): Include \(\beta_0\) in each row of the opening regression system and use \(x_{1n}\), \(x_{2n}\), …, \(x_{kn}\) in the final row.
  • p. 522 (typo): In the matrix-multiplication paragraph, replace “Not that” with “Note that” and correct the bold formatting of “conformable”.
  • p. 522 (correction): In the transpose definition, \(i\) ranges from \(1\) to \(n\) and \(j\) from \(1\) to \(m\). The product-transpose identity requires conformable matrices and a sum over their shared dimension.
  • p. 522 (clarification): The inverse-based projection formula requires full column rank. In the symmetry proof, remove the repeated line and write \(\left((X^{\mathsf{T}}X)^{-1}\right)^{\mathsf{T}}\) for the transpose of the inverse.
  • p. 522 (clarification): With \(k\) explanatory variables and an intercept, \(X\) has \(k+1\) columns and \(\beta\) has \(k+1\) elements. Individual errors have variance \(\sigma^2\); the error-vector covariance matrix is \(\sigma^2 I\).
  • p. 523 (correction): Derive \(\mathbb{E}[\hat{\beta} \mid X] = \beta\), then use iterated expectations to obtain \(\mathbb{E}[\hat{\beta}] = \beta\).
  • p. 525 (typo): In the SQL/dplyr translation table, replace “used-defined” with “user-defined”.
  • p. 529 (correction): The earlier arrange() call does not update apple. The joined query has no ORDER BY clause and does not guarantee row order.
  • p. 539 (correction): Stata stores dates and times numerically with display formats; millisecond datetimes require double precision. Apache Parquet defines the file format; Apache Arrow supplies libraries for reading and writing it.
  • p. 546 (correction): Changing listen_addresses requires restarting PostgreSQL; changing pg_hba.conf normally requires only a reload.
  • p. 547 (correction): PostgreSQL stores a hashed password verifier.
  • p. 559 (typesetting): Replace the two-line comment beginning with # The segment data with # compseg. The WRDS database changed since that comment was written and the comment is obsolete.
  • p. 562 (correction): Bebchuk, Cohen and Hirst (2017) page range is 89–112.
  • p. 563 (correction): Call, Sharp and Wilde (2019) page range is 35–36.
  • multiple pages (typesetting): Made spelling of “cutoff” consistent (no longer a mix of “cutoffs” and “cut-offs”).

Fixes

These entries cover code corrections and updates for changes in data, R or packages.

  • p. 6 (correction): In the literal .Renviron example, use PGPORT = 9737, without the R integer suffix L. The separate Sys.setenv(PGPORT = 9737L) example on p. 5 is valid R.
  • p. 63 (cosmetic): In the second and third income regressions, list industry before intelligence to match the order of \(x_{i2}\) and \(x_{i3}\) in the structural model. This changes the order of displayed coefficients but not the fitted models or estimates.
  • p. 86: In get_means(), calculate the standard error as sd(x) / sqrt(length(x)), not sd(x) / sqrt(length(x) - 1). The sample-variance divisor is already included in sd().
  • p. 132: In the Dell PERMNO exercise, replaced filter(str_detect(comnam, '^DELL ')) with filter(ticker == "DELL") to match the question. The query now returns the two intended PERMNOs, 11081 and 18267.
  • p. 148: Replace http in URLs with https. Use mode = "wb" with download.file().
  • p. 152: Use mode = "wb" with download.file().
  • p. 154: In the footnote URL for Ritter’s IPO data and the url <- assignment constructing the download URL, replace money-left-on-the-table.pdf with money-left-on-the-table-in-IPOs.pdf. The full download URL is now https://site.warrington.ufl.edu/ritter/files/money-left-on-the-table-in-IPOs.pdf.
  • p. 172: In the code creating split_returns, replace by = "permno" with by = c("permno", "exdt") in semi_join() so that eligibility is matched by split event.
  • p. 174: In the code creating nyse_splits_join, insert semi_join(split_sample, by = c("permno", "exdt")) |> between nyse_splits |> and mutate(...) to restrict the final event join to qualifying splits. Both this correction and the one on p. 172 are needed to keep ineligible splits out of the analysis.
  • p. 188 (performance): Code producing rets_all was too slow on WRDS PostgreSQL server. See online book for replacement code. Result of code is unchanged.
  • p. 189: In the code creating full_panel, insert filter(!is.na(ret)) |> before group_by(). The existing filter(n_obs == max(n_obs)) after ungroup() then identifies the full panel using the number of usable monthly returns, excluding firm-years with missing returns in the intended window.
  • p. 190: Changes in data on Ken French’s website broke the code here in two places. Code in the online version has been updated. In the first code block on this page, the word Average needed to be added to the the search strings. In the second block of code, the "^Dec " regular expression needed to become "-Dec" in the two places it was used.
  • p. 191: There should be a code block following the paragraph beginning “The second set of data …”, but this was omitted in the printed edition. This can now be found in the online version.
  • p. 191: Changes in data on Ken French’s website broke the code in the last code block in two places. First, skip = 1 needs to be skip = 2. Second, for the argument n_max, the - 3 needs to be replaced by - 4. The corrected code can now be found in the online version.
  • p. 194 (deprecated): Changed code for bs_coefs() to avoid superseded map_df(). Result of code is unchanged and previous code still works.
  • p. 239 (performance): Switched from list_rbind() to bind_rows() in calculation of results. Result of code is unchanged, but it seems that bind_rows() runs more reliably with plan(multisession).
  • p. 240: Updated the decile breakpoints used to create results_deciles so that values below the previous quarter’s minimum earnings surprise are assigned to Decile 1 and values above the previous quarter’s maximum earnings surprise are assigned to Decile 10. The online version now sets the lower bound to -Inf, the upper bound to Inf, and uses include.lowest = TRUE in cut().
  • p. 240 (compatibility): In the code creating results_deciles, insert filter(lengths(fe1_deciles_lag) > 1, lengths(fe2_deciles_lag) > 1) |> after inner_join(decile_cuts, by = "qtr") |>, before rowwise(). R 4.6.1 changed cut() to reject empty breakpoints (PR 19057), which occur for the first quarter because it has no previous-quarter cutoffs. Earlier R versions returned missing classifications for that quarter, which the existing later filter removed. This change preserves the reported results.
  • p. 249: The expression in the last line of the simulation should be df$se[i] <- df$se[i-1] + df$ni[i] - df$div[i], not df$se[i] <- df$se[i-1] + df$ni[i] - df$ni[i]. Because the dividend payout ratio is 100%, nothing in the book is affected by this issue.
  • p. 254 (reproducibility): Added arrange(gvkey, datadate) after collect() and before the four ntile() calculations in the acc_data pipeline. This gives tied values a consistent row order across database backends while retaining local R missing-value treatment.
  • p. 255 (performance): Added collect() |> copy_inline(db, df = _) at end of pipeline creating crsp_link to address abysmal performance with previous code.
  • p. 257: In crsp_link and cum_size_rets, calculate start_month as floor_date(datadate, "month") + months(4) and end_month as floor_date(datadate, "month") + months(16). Rounding to the start of the month before adding months avoids missing dates when a fiscal year ends on a day absent from the destination month, such as 31 December plus four months. In the cum_size_rets join, use end_month > month in place of end_month >= month so that the benchmark covers the same twelve months as the stock-return window. These changes restore fiscal year ends previously lost from the linked regression sample and affect the reported regressions and portfolio returns.
  • p. 268 (cosmetic): Split code calculating hedge_ret over two lines so that code does not go outside the box.
  • p. 274: Use at least 13 eligible observations in test_sample, choose event years in sample_1_firm_years only after the first two eligible observations, and apply these restrictions before random event selection. This leaves at least ten usable estimation observations for every model and prevents selected DeAngelo events from being lost.
  • p. 275: In get_nda(), construct two-digit SIC codes with str_pad(as.character(sic %/% 100), width = 2, pad = "0") and calculate acc_ind separately for each (sic2, fyear). The previous grouping pooled all years, and the previous string prefix did not preserve leading-zero industries. The teaching implementation retains selected-firm, non-event industry observations; unavailable predictions are reflected in the displayed test counts. A note also distinguishes the code’s all-period adjusted-revenue estimation from the event-period-only adjustment in the original Modified Jones specification.
  • p. 279 (cosmetic): Replaced h_test() function with clearer code, though code in printed book works fine.
  • p. 282: Calculate earnings scaled by lagged assets on the raw history before restricting to test_sample; determine event eligibility for sample_2_firm_years from the full eligible history rather than the first year within the extreme decile.
  • pp. 284–285: In manipulate(), use lag(manip_amt) or lag(manip_amt_gross) for the following year’s revenue subtraction so that the event-year amount is reversed. Retain the book’s existing positive-ratio restriction and additionally require a finite ratio. This convention is not explicitly specified in the original paper.
  • p. 286 (cosmetic): Replaced h_test_5() function with clearer code, though code in printed book works fine.
  • p. 286 (performance): The power calculation now processes one scenario per worker and retains only rejection-rate summaries, rather than retaining all scenarios’ accounting data and fitted models at once. This memory change preserves rejection frequencies for a fixed sample and model specification; the other Chapter 16 corrections also change the sample and Industry Model.
  • p. 330 (performance): Switched from list_rbind() to bind_rows() in calculation of results. Result of code is unchanged, but it seems that bind_rows() runs more reliably with plan(multisession).
  • pp. 342 and 345 (correction): Use the 49-industry Fama-French grouping in the FHK replication and FHK: Data steps Q1, matching the authors’ supplied code. The paper describes 48 industries, but the supplied code uses 49.
  • p. 342 (correction): In get_das(), calculate lags before filtering on positive lagged assets. Filtering first drops usable observations and can change the lagged values.
  • p. 342 (cosmetic): The use of .groups = "drop" with mutate() has no effect and can be eliminated.
  • p. 342 (deprecated): Replaced case_when() with if/else because drop_extreme is a single logical value selecting between entire vectors. This usage of case_when() in such cases is deprecated in dplyr 1.2.0. The calculated results should not change.
  • p. 343 (enhancement): Order tied performance matches by GVKEY before retaining the first row, making the existing tie rule reproducible across backends.
  • p. 343 (cosmetic): Remove unused das argument from get_pm().
  • pp. 343–344 (deprecated): Replaced the outer case_when() in get_pm() with if/else. The calculated results should not change (see discussion above for p. 342).
  • p. 343 (deprecated): Replaced group_by() |> do() with nest_by() |> summarize().
  • p. 345 (correction): Winsorize the final regression variables across sample years, following FHK’s supplied replication code. Apply the same convention in the alternative-sample code.
  • p. 346 (cosmetic): Wrapped feols() in the reg_year_fe() function inside suppressWarnings() to suppress warnings emitted by cov().
  • p. 346 (correction): Cluster two-way standard errors by firm and fiscal year, following FHK’s supplied replication code; year fixed effects remain based on calendar year. Use ssc(t.df = "conventional") to approximate the degrees-of-freedom convention in FHK’s supplied Stata code.
  • p. 349 (correction): In FHK: Regression analysis Q2, ask for winsorization within each fiscal year, as the updated main code now winsorizes across sample years.
  • p. 349 (cosmetic): Replace winsorize, prob = 0.01 with \(x) winsorize(x, prob = 0.01).
  • p. 349 (enhancement): Add a regression exercise comparing the explicit ssc(t.df = "conventional") setting with the default, including its effect on coefficients, standard errors and p-values.
  • p. 352 (performance): Switched from list_rbind() to bind_rows() in calculation of rand_results. Result of code is unchanged, but it seems that bind_rows() runs more reliably with plan(multisession).
  • p. 366 (reproducibility): Give the 1,000-run IV simulation its own seed, so its random draws do not depend on which preceding chunks execute or load from cache. This changes the realized simulation draws without changing the model or estimand.
  • p. 375 (reproducibility): Add set.seed(2022) before the 1,000-run simulation creating sim_results, so its realized draws do not depend on earlier execution choices. This changes the realized draws without changing the model or estimand.
  • p. 376 (reproducibility): Add set.seed(2023) before the 1,000-run simulation creating sim_results_wide, so its realized draws do not depend on earlier execution choices. This changes the realized draws without changing the model or estimand.
  • p. 377 (reproducibility): Add set.seed(2024) before the 1,000-run simulation creating sim_results_rand, so its realized draws do not depend on earlier execution choices. This changes the realized draws without changing the model or estimand.
  • p. 382: Code creating biggest_customers was incorrect resulting in duplicates. Corrected code is found in online chapter. Change only affects Figure 21.1.
  • p. 387 (enhancement): Changed factor_t() and year_diff() functions to add a ref argument. These changes have no effect on any analysis in the book, but facilitate answering questions in exercises. In the factor_t() footnote example, explicitly supply ref = -1 to retain the original reference under the updated function’s default.
  • pp. 388–389 (compatibility): Filter infinite event-time coefficient labels before converting the remaining labels to integers in plot_coefs().
  • p. 397 (correction): The management-report indicator in iliev_2010 is mr, not mf.
  • p. 398 (cosmetic): The use of .groups = "drop" with mutate() has no effect and can be eliminated.
  • p. 398 (deprecated): As top_n() is deprecated, replace with slice_max().
  • p. 403 (reproducibility): Order the post-policy sample by PERMCO and fiscal-year-end date before the RD calculations, so automatic plotting bins for tied public floats do not depend on database row order.
  • p. 407 (correction): In the intent-to-treat footnote, replace the nonexistent names fuzzy2004 and fuzzy2002 with float2004 and float2002.
  • p. 420 (deprecated): Replaced case_when() with if/else if/else. The calculated results should not change (see discussion above for p. 342).
  • p. 421 (deprecated): Replaced case_when() with if/else if/else. The calculated results should not change (see discussion above for p. 342).
  • p. 430: Changes to numbers: (63, 74) becomes (63, 77); (75, 86) becomes (78, 89); (87, 98) becomes (90, 101); (99, 150) becomes (102, NA).
  • p. 432: Changes to numbers: (63, 74) becomes (63, 77); (75, 86) becomes (78, 89); (87, 98) becomes (90, 101); (99, 150) becomes (102, NA).
  • p. 437 (correction): Construct 8-K counts with a left join and convert empty sums to zero, so 10-K observations without matching 8-K filings are retained. When several CIKs map to a filing/security, retain one using the largest subsequent-year count and break ties by CIK.
  • p. 441 (reproducibility): Order equal complexity values by filing/security identifiers before splitting them into quintiles. This retains the rank-bucket definition while making tie assignments independent of database row order.
  • p. 442 (reproducibility): Order equal spread and illiquidity values by filing/security identifiers before splitting them into deciles. This retains the rank-bucket definitions while making tie assignments independent of database row order.
  • p. 445 (correction): In Chapter 23 Exercise 6, the supplied marginal-effect helper is get_mfx(), not mfx().
  • p. 449 (correction): In the extreme-values replication, form lags on the raw history, require consecutive fiscal years, then apply the industry and auditor-availability restrictions. This avoids using a nonconsecutive or previously filtered observation as the lag and avoids treating unknown auditor codes as non-Big N observations.
  • p. 450 (cosmetic): In first code chunk, big_n appears twice in select(). Delete second appearance.
  • p. 465 (correction): In fit_models(), include x1 + x2 + x3 in the first model, so the raw, Cook’s-distance and robust-regression approaches use the same three-covariate specification as the other simulation methods.
  • p. 465 (deprecated): Replaced case_when() with if/else if/else. The calculated results should not change (see discussion above for p. 342).
  • p. 474 (correction): In the simulation’s matchit() call, add std.caliper = FALSE so that the caliper of 0.03 is a difference in predicted probabilities, following Lawrence et al. The default uses standard-deviation units; this correction changes the matched sample and reported simulation regressions.
  • p. 477 (correction): In the matching replication, calculate lags on the raw history before applying the final sample restrictions, retain the prior years needed for 1988 observations, require consecutive fiscal years, and exclude unknown auditor codes. The implementation also handles SIC as an integer when defining two-digit industries.
  • p. 478 (correction): Count at least ten usable first-stage observations per industry/year and choose one nearest-ROA match per firm/year, breaking ties by GVKEY. Retaining all equally near matches could duplicate firm-year observations in the outcome regression.
  • p. 489 (correction): Do not impute the earliest observed AAER date when a release date is missing. The as-of training label uses recorded releases; the latent test label keeps all listed affected firm-years. Unknown release dates remain a data limitation, and a zero as-of label does not establish that no earlier release or fraud existed. Aggregate overlapping AAER records to one firm-year label to avoid duplicated test observations.
  • p. 506 (correction): Initialize the tree controls in fit_rus_model() when both optional arguments are absent, and retain both maxdepth and minbucket when both are supplied.
  • p. 545 (enhancement): Use SCRAM authentication with a rule restricted to the intended database, user and client addresses, and reset existing MD5 password verifiers before requiring SCRAM. For remote access, use a VPN or configure TLS and address restrictions.
  • pp. 552–560 (deprecated): Updated to incorporate new db2pq R package. The larger-file example downloads crsp.dsf, and the library-building instructions consistently use the R-based approach and script.
  • p. 555 (enhancement): Altered code to handle missing values in a way that matches code in the 21  Panel data.

  1. R for Data Science is available at https://r4ds.hadley.nz/↩︎

  2. Go to https://wrds-www.wharton.upenn.edu/register to do so.↩︎