Fama French type summary tables


Eugene Fama and Kenneth French popularized the use of summary tables in empirical asset pricing research. For example, in their influential 2015 paper “A Five-Factor Asset Pricing Model”, they present Table 2 showing the average returns of portfolios formed on size, book-to-market equity (B/M), profitability, and investment.

Fama-French form these portfolios by sorting stocks into groups based on characteristics like size and B/M. The table shows the average monthly returns of the portfolios over the sample period, allowing analysis of how returns vary across sorts. This helps identify patterns like the size effect, value effect, profitability effect, and investment effect documented by Fama-French.

We can replicate similar portfolio sorting and return analysis in Stata using the  crosstab command, that is part of the asdocx package. The syntax for crosstab is simple:

  Syntax


asdocx crosstab row col, returns(varname) [weight(varname) time(varname)

         rowtotal coltotal rept]

The main program is asdocx which handles exporting Stata tables to Word or Excel formats.

The first argument to asdocx is the crosstab command that generates the table to export. After crosstab, the first word is the row variable. This variable must be grouped into categories like tertiles, quartiles, quintiles etc. The second word after crosstab is the column variable. Like the row variable, this must also be grouped into categories.

The ret() option specifies which variable contains the stock returns to calculate statistics on. For example, ret(mret) calculates statistics like the mean on the mret variable.

The last four options are optional. The time() option takes a date variable that identifies the time period like month or year. For example, time(mdate) would calculate monthly period returns based on the mdate variable. The weight() option allows weighting the calculated statistics like the mean. For example, weight(MCAP) would take a variable MCAP containing market capitalization values to calculate value-weighted mean returns.

Options rowtotal and coltotal can be used to report row and column totals.

Use of value labels


It is recommended to assign value labels to the different categories of the row and column variables before creating the table. This will make the table more readable and understandable for the reader. The following code snippet shows how to create quintiles of the BEME and MCAP variables and assign value labels to them. The size quintiles are labeled as Small, 2, 3, 4, Large, and the book-to-market quintiles are labeled as Low, 2, 3, 4, High.

* Load an example dataset

use https://fintechprofessor.com/portfolios.dta, clear

‏‏‎ ‎

* First create 5 groups of size and book-to-market in each year
bys year: astile bm5 = BEME, nq(5)
bys year: astile sz5 = MCAP, nq(5)

‏‏‎ ‎

* Assign value and variable labels for better readability
label define bmlabel 1 "Low" 2 "2" 3 "3" 4 "4" 5 "High"
label values bm5 bmlabel
label var bm5 "Book-to-market"

‏‏‎ ‎

* similarly assign labels to the size variable
label define szlabel 1 "Small" 2 "2" 3 "3" 4 "4" 5 "Large"
label values sz5 szlabel
label var sz5 "Size"

 

* Multiply mret variable by 100

replace mret = mret * 100

  Example 1: Weighted means in crosstabs


In the following examples, we shall create 5 groups of book-to-market and 5 groups of size in each year using the astile program, which can be downloaded from the SSC by typing: ssc install astile

* Report size in rows and BEME in rows, use MCAP as a weighting variable
* mdate is the monthly date and mret are monthly returns

asdocx crosstab sz5 bm5, ret(mret) time(mdate) weight(MCAP) ///

title(Table 1: Average Returns of Portfolios, by size and book-to-market)

\text{Table\; 1:\; Average\; returns\; of\; portfolios,\; by\; size\; and\; book\; to\; market}
\text{Book-to-market}
\text{Size} Low 2 3 4 \text{ High} \text{ High-Low}
\text{ Small } 1.762 0.935 0.818 0.104 1.101 -0.304
2 0.546 0.886 0.677 0.357 0.556 0.044
3 0.699 0.646 0.276 0.314 0.591 -0.108
4 0.217 0.499 0.510 0.402 0.420 0.242
\text{ Large} 0.488 0.651 0.403 0.400 1.179 0.5860**
\text{High-Low} -0.8211** 0.144 -0.6408*** 0.216 0.069
  *** p<0.01, ** p<.05, * p<00.1

  Formulas


Average of averages by time

The timevar() option can be utilized to weight reported averages by a time variable. For instance, if we have monthly data and our monthly date variable is named mdate, the timevar(mdate) option will calculate a weighted average of the statistics variable for each month. It will then report the average of these monthly averages in a table at the intersection of the specified row and column variables. Thus, the results presented in Table 1 are based on the following equation:

\bar R = \dfrac{1}{m}\sum_{t=1}^m \dfrac{\sum_{j,k=1}^{n} W_{jkt} \cdot R_{jkt}}{n},

where \bar R refers to the weighted average of the monthly averages of stock returns.  The outermost summation runs over all months from 1 to m. Each corresponds to a specific month within the time period under consideration. The innermost summation runs over all observations within a particular month, where two characteristics are considered:

  • j represents the book-to-market ratio for an observation.
  • k represents the size for an observation.

R_{jk,t} denotes the stock return for the particular observation with the given j and k in month t. W_{jk,t} is the weight for observation j,k in month t.
n represents the number of stocks in a given month for a given pair of j and k.
m is the total number of months.

When to use the timevar() option?

The timevar() option is used to indicate that the data is at the stock level (just like the portfolios.dta dataset that we used in Example 1 above). If you have already calculated the weighted portfolio returns for each pair of j and k, then you should drop the timevar() option. However, if your data is still at the stock level, you should use the timevar() option.

  Example 2: Equal weighted returns

To calculate returns where each stock contributes equally regardless of its weight in the portfolio, you can omit the weight() option. This will calculate returns for each portfolio by giving equal weight to all stocks.

* Equally-weighted portfolio returns

asdocx crosstab sz5 bm5, ret(mret) time(mdate) ///

title(Table 2: Average Returns of Portfolios, by size and book-to-market)

 

 \text{Table 2: Equally-weighted portfolio returns by size and book-to-market}
\text{Book-to-market}
 \text{Size}   \text{ Low}   2   3   4   \text{ High}  \text{ High-Low}
\text{Small} 1.748 0.870 0.706 0.187 1.158 -0.224
2 0.616 0.910 0.676 0.326 0.610 0.018
3 0.700 0.665 0.353 0.304 0.624 -0.101
4 0.281 0.556 0.423 0.451 0.405 0.168
Large 0.483 0.557 0.322 0.523 1.151 0.5851
\text{High-Low} -0.7980 0.028 -0.5688 0.214 0.011
*** p<0.01, ** p<0.05, * p<0.10

 

  Example 3: Report row and column totals

The rowtotal and coltotal options can be used to add row and column totals to a table. These options are useful for summarizing data and identifying trends, such as total returns across rows and columns.

* Add row total and column totals

asdocx crosstab sz5 bm5, ret(mret) time(mdate) rowtal coltotal w(MCAP)

 \text{Table 3: Report row and column totals}
\text{Book-to-market}
 \text{Size}   \text{ Low}   2   3   4   \text{ High}  \text{ High-Low}
\text{Small} 1.748 0.870 0.706 0.187 1.158 -0.224
2 0.616 0.910 0.676 0.326 0.610 0.018
3 0.700 0.665 0.353 0.304 0.624 -0.101
4 0.281 0.556 0.423 0.451 0.405 0.168
\text{Large} 0.483 0.557 0.322 0.523 1.151 0.5851
\text{Total} 0.544 0.675 0.540 0.337 0.788
\text{High-Low} -0.7980 0.028 -0.5688 0.214 0.011
*** p<0.01, ** p<0.05, * p<0.10

 

  Example 4: Report t-values below means

The rept option can be used to report t-values below the means.

* Report t-values

asdocx crosstab sz5 bm5, ret(mret) time(mdate) weight(MCAP) rept w(MCAP)

 \text{Table 4: Report t-values}
\text{Book-to-market}
 \text{Size}   \text{ Low}   2   3   4   \text{ High}  \text{ High-Low}
\text{Small} 1.762 0.935 0.818 0.104 1.101 -0.304
2.438 1.826 1.681 0.184 1.741 -0.456
2 0.546 0.886 0.677 0.357 0.556 0.044
1.310 2.437 1.468 0.627 1.067 0.150
3 0.699 0.646 0.276 0.314 0.591 -0.108
1.844 1.443 0.579 0.591 1.567 -0.557
4 0.217 0.499 0.510 0.402 0.420 0.242
0.510 1.324 1.192 1.022 1.244 1.317
Large 0.488 0.651 0.403 0.400 1.179 0.5860
1.400 1.854 1.111 0.992 2.820 2.076
\text{High-Low} -0.8211 0.144 -0.6408 0.216 0.069
-2.181 0.612 -3.080 0.850 0.137
*** p<0.01, ** p<0.05, * p<0.10

  See also


  • tabulate, tab1, tab2 – Stata official tabulation commands
  • tabmany – Table of multiple coded answers
  • mrtab – One- and two-way tables of multiple responses
  • tabcount – tabulates frequencies for up to 7 variables
  • fre – univariate tabulations
  • tab3way – Three way table of frequencies and percentages
  • missings – Various utilities for managing missing values
  • pctab – report percentages in cross-tabulations

 

  Order asdocx


Yearly license of asdocx is available at $9.99. Its life-time license is available at $49.99. With the asdocx membership, you get :

  • Life-time license to use
  • All future updates
  • All premium templates / plugins.

 

Order asdocx