 »  Home »  Resources & support »  FAQs »  Chow tests
The following FAQ is based on an exchange that started on Statalist.

## Can you explain Chow tests?

 Title Chow tests Author William Gould, StataCorp

Privately I was asked yet another question on Chow tests. The question started out “Is a Chow test the correct test to determine whether data can be pooled together?” and went on from there.

In the past, I have always given in and cast my answer in Chow-test terms. In this reply, I try a different approach and, I think, the result is more useful.

This reply concerns linear regression (though the technique is really more general than that), and I gloss over the detail of pooling the residuals and whether the residual variances are really the same. For the last, I think I can be forgiven.

Here is what I wrote:

Is a Chow test the correct test to determine whether data can be pooled together?

A Chow test is simply a test of whether the coefficients estimated over one group of the data are equal to the coefficients estimated over another, and you would be better off to forget the word Chow and remember that definition.

 History: In the days when statistical packages were not as sophisticated as they are now, testing whether coefficients were equal was not so easy. You had to write your own program, typically in FORTRAN. Chow showed a way you could perform a Wald test based on statistics that were commonly reported, and that would produce the same result as if you performed the Wald test.

What does it mean “whether data can be pooled together”? Do you often meet nonprofessionals who say to you, “I was wondering whether the data could be pooled?” Forget that phrase, too: it is another piece of jargon for testing whether the behavior is the same, as measured by whether the coefficients are the same.

Let’s pretend that you have some model and two or more groups of data. Your model predicts something about the behavior within the group based on certain characteristics that vary within the group. Under the assumption that each group's behavior is unique, you have

        y_1 = X_1*b_1 + u_1                   (equation for group 1)
y_2 = X_2*b_2 + u_2                   (equation for group 2)


and so on. Now you want to test whether the behavior for one group is the same as for another, which means you want to test

        b_1 = b_2 = ...


How do you do that? Testing coefficients across separately fitted models is difficult to impossible, depending on things we need not go into right now. A trick is to “pool” the data to convert the multiple equations into one giant equation

        y   = d1*(X_1*b1 + u1) + d2*(X_2*b2 + u2) + ...


where y is the set of all outcomes (y_1, y_2, ...), and d1 is a variable that is 1 when the data are for group 1 and 0 otherwise, d2 is 1 when the data are for group 2 and 0 otherwise, ....

Notice that from the above I can retrieve the original equations. Setting d1=1 and d2=d3=...=0, I get the equation for group 1; setting d1=0 and d2=1 and d3=...=0, I get the equation for group 2; and so on.

        y   = d1*(X_1*b1 + u1) + d2*(X_2*b2 + u2) + ...


and rewrite it by a little algebraic manipulation:

        y   = d1*(X_1*b1 + u1) + d2*(X_2*b2 + u2) + ...
= d1*X_1*b1 + d1*u1 + d2*X_2*b2 + d2*u2 + ...
= d1*X_1*b1 + d2*X_2*b2 + ... + d1*u1 + d2*u2 + ...
= X_1*d1*b1 + X_2*d2*b2 + ... + d1*u1 + d2*u2 + ...
= (X_1*d1)*b1 + (X_2*d2)*b2 + ... + d1*u1 + d2*u2 + ...


By stacking the data, I can obtain estimates of b1, b2, ...

I include not X_1 in my model, but X_1*d1 (a set of variables equal to X_1 when group is 1 and 0 otherwise); I include not X_2 in my model, but X_2*d2 (a set of variables equal to X_2 when group is 2 and 0 otherwise); and so on.

Let’s use auto.dta and pretend that I have two groups.

. sysuse auto
. generate group1=rep78==3
. generate group2=group1==0


I could fit the models separately:

. regress price mpg weight if group1==1

Source         SS       df       MS              Number of obs =      30

F(  2,    27) =   16.20

Model     196545318     2  98272658.8           Prob > F      =  0.0000

Residual     163826398    27  6067644.36           R-squared     =  0.5454

Total     360371715    29  12426610.9           Root MSE      =  2463.3

price        Coef.   Std. Err.      t    P>|t|     [95% Conf. Interval]

mpg     13.14912   184.5661     0.07   0.944    -365.5492    391.8474

weight     3.517687   1.015855     3.46   0.002     1.433324     5.60205

_cons    -5431.147   6599.898    -0.82   0.418    -18973.02    8110.725

. regress price mpg weight if group2==1

Source         SS       df       MS              Number of obs =      44

F(  2,    41) =    5.16

Model    54562909.6     2  27281454.8           Prob > F      =  0.0100

Residual     216614915    41  5283290.61           R-squared     =  0.2012

Total     271177825    43  6306461.04           Root MSE      =  2298.5

price        Coef.   Std. Err.      t    P>|t|     [95% Conf. Interval]

mpg    -170.5474    93.3656    -1.83   0.075     -359.103     18.0083

weight     .0527381   .8064713     0.07   0.948    -1.575964     1.68144

_cons     9685.028   4190.693     2.31   0.026     1221.752     18148.3



I could fit the combined model:

. generate mpg1=mpg*group1
. generate weight1=weight*group1

. generate mpg2=mpg*group2
. generate weight2=weight*group2

. regress price group1 mpg1 weight1 group2 mpg2 weight2, noconstant

Source         SS       df       MS              Number of obs =      74

F(  6,    68) =   91.38

Model    3.0674e+09     6   511232168           Prob > F      =  0.0000

Residual     380441313    68  5594725.19           R-squared     =  0.8897

Total    3.4478e+09    74  46592355.7           Root MSE      =  2365.3

price        Coef.   Std. Err.      t    P>|t|     [95% Conf. Interval]

group1    -5431.147   6337.479    -0.86   0.394    -18077.39    7215.096

mpg1     13.14912   177.2275     0.07   0.941    -340.5029    366.8012

weight1     3.517687   .9754638     3.61   0.001     1.571179    5.464194

group2     9685.028   4312.439     2.25   0.028      1079.69    18290.37

mpg2    -170.5474   96.07802    -1.78   0.080    -362.2681    21.17334

weight2     .0527381   .8299005     0.06   0.950    -1.603303    1.708779



What is this noconstant option? We must remember that when we fit the separate models, each has its own intercept. There was an intercept in X_1, X_2, and so on. What I have done above is literally translate

        y   = (X_1*d1)*b1 + (X_2*d2)*b2 + d1*u1 + d2*u2


and included the variables group1 and group2 (variables equal to 1 for their respective groups) and told Stata to omit the overall intercept.

I do not recommend you fit the model the way I have just illustrated because of numerical concerns—we will get to that later. Fit the models separately or jointly, and you will get the same estimates for b_1 and b_2.

Now we can test whether the coefficients are the same for the two groups:

 . test _b[mpg1]=_b[mpg2], notest

( 1)  mpg1 - mpg2 = 0

. test _b[weight1]=_b[weight2], accum

( 1)  mpg1 - mpg2 = 0
( 2)  weight1 - weight2 = 0

F(  2,    68) =    5.61
Prob > F =    0.0056



That is the Chow test. Something was omitted: the intercept. If we really wanted to test whether the two groups were the same, we would would test

 . test _b[mpg1]=_b[mpg2], notest

( 1)  mpg1 - mpg2 = 0

. test _b[weight1]=_b[weight2], accum notest

( 1)  mpg1 - mpg2 = 0
( 2)  weight1 - weight2 = 0

. test _b[group1]=_b[group2], accum

( 1)  mpg1 - mpg2 = 0
( 2)  weight1 - weight2 = 0
( 3)  group1 - group2 = 0

F(  3,    68) =    4.07
Prob > F =    0.0102


Using this approach, however, we are not tied down by what the “Chow test” can test. We can formulate any hypothesis we want. We might think that mpg works the same way in both groups but that weight works differently, and each group has its own intercept. Then we could test

 . test _b[mpg1]=_b[mpg2]

( 1)  mpg1 - mpg2 = 0

F(  1,    68) =    0.83
Prob > F =    0.3654


by itself. If we had more variables, we could test any subset of variables.

Is “pooling the data” justified? Of course it is: we just established that pooling the data is just another way of fitting separate models and that fitting separate models is certainly justified—we got the same coefficients. That’s why I told you to forget the phrase about whether pooling the data is justified. People who ask that do not really mean to ask what they are saying; they mean to ask whether the coefficients are the same. In that case, they should say that. Pooling is always justified, and it corresponds to nothing more than the mathematical trick of writing separate equations,

        y_1 = X_1*b_1 + u_1                   (equation for group 1)
y_2 = X_2*b_2 + u_2                   (equation for group 2)


as one equation

        y   = (X_1*d1)*b1 + (X_2*d2)*b2 + d1*u1 + d2*u2


There are many ways I can write the above equation, and I want to write it a little differently because of numerical concerns. Starting with

        y   = (X_1*d1)*b1 + (X_2*d2)*b2 + d1*u1 + d2*u2


let’s do some algebra to obtain

        y   = X*b1 + d2*X_2*(b2-b1)     + d1*u1 + d2*u2


where X = (X_1, X_2). In this formulation, I measure not b1 and b2, but b1 and (b2−b1). This is numerically more stable, and I can still test that b2==b1 by testing whether (b2−b1)=0.

Let’s fit this model

. regress price mpg weight mpg2 weight2 group2

Source         SS       df       MS              Number of obs =      74

F(  5,    68) =    9.10

Model     254624083     5  50924816.7           Prob > F      =  0.0000

Residual     380441313    68  5594725.19           R-squared     =  0.4009

Total     635065396    73  8699525.97           Root MSE      =  2365.3

price        Coef.   Std. Err.      t    P>|t|     [95% Conf. Interval]

mpg     13.14912   177.2275     0.07   0.941    -340.5029    366.8012

weight     3.517687   .9754638     3.61   0.001     1.571179    5.464194

mpg2    -183.6965   201.5951    -0.91   0.365    -585.9733    218.5803

weight2    -3.464949   1.280728    -2.71   0.009    -6.020602   -.9092956

group2     15116.17   7665.557     1.97   0.053    -180.2075    30412.56

_cons    -5431.147   6337.479    -0.86   0.394    -18077.39    7215.096



and, if I want to test whether the coefficients are the same, I can do

 . test _b[mpg2]=0, notest

( 1)  mpg2 = 0

. test _b[weight2]=0, accum

( 1)  mpg2 = 0
( 2)  weight2 = 0

F(  2,    68) =    5.61
Prob > F =    0.0056


and that gives the same answer yet again. If I want to test whether *ALL* the coefficients are the same (including the intercept), I can type

 . test _b[mpg2]=0, notest

( 1)  mpg2 = 0

. test _b[weight2]=0, accum notest

( 1)  mpg2 = 0
( 2)  weight2 = 0

. test _b[group2]=0, accum

( 1)  mpg2 = 0
( 2)  weight2 = 0
( 3)  group2 = 0

F(  3,    68) =    4.07
Prob > F =    0.0102


Just as before, I can test any subset.

Using this difference formulation, if I had three groups, starting with

        y   = (X_1*d1)*b1 + (X_2*d2)*b2 + (X_3*d3)*b3 + d1*u1 + d2*u2 + d3*u3


as

        y   = X*b1 + (X_2*d2)*(b2-b1) + (X_3*d3)*(b3-b1) + d1*u1 + d2*u2 + d3*u3


Let’s create the group variables and fit this model:

. sysuse auto, clear

. generate group1=rep78==3
. generate group2=rep78==4
. generate group3=(group1+group2)==0

. generate mpg1=mpg*group1
. generate weight1=weight*group1

. generate mpg2=mpg*group2
. generate weight2=weight*group2

. generate mpg3=mpg*group3
. generate weight3=weight*group3

. regress price mpg weight mpg2 weight2 group2 mpg3 weight3 group3

Source         SS       df       MS              Number of obs =      74

F(  8,    65) =    5.80

Model     264415585     8  33051948.1           Prob > F      =  0.0000

Residual     370649811    65  5702304.78           R-squared     =  0.4164

Total     635065396    73  8699525.97           Root MSE      =  2387.9

price        Coef.   Std. Err.      t    P>|t|     [95% Conf. Interval]

mpg     13.14912   178.9234     0.07   0.942    -344.1855    370.4837

weight     3.517687   .9847976     3.57   0.001      1.55091    5.484463

mpg2     130.5261   336.6547     0.39   0.699    -541.8198     802.872

weight2     -2.18337   1.837314    -1.19   0.239     -5.85274       1.486

group2     4560.193   12222.22     0.37   0.710    -19849.27    28969.66

mpg3    -194.1974   216.3459    -0.90   0.373      -626.27    237.8752

weight3    -3.160952    1.73308    -1.82   0.073    -6.622152    .3002481

group3     14556.66   9167.998     1.59   0.117    -3753.101    32866.41

_cons    -5431.147    6398.12    -0.85   0.399    -18209.07    7346.781



If I want to test whether the three groups were the same in the Wald-test sense, I can type

. test (_b[mpg2]=0) (_b[weight2]=0) (_b[group2]=0) /*
>   */ (_b[mpg3]=0) (_b[weight3]=0) (_b[group3]=0)

( 1)  mpg2 = 0
( 2)  weight2 = 0
( 3)  group2 = 0
( 4)  mpg3 = 0
( 5)  weight3 = 0
( 6)  group3 = 0

F(  6,    65) =    2.28
Prob > F =    0.0463



I could more easily type the above command as

. testparm mpg2 weight2 group2 mpg3 weight3 group3

( 1)  mpg2 = 0
( 2)  weight2 = 0
( 3)  group2 = 0
( 4)  mpg3 = 0
( 5)  weight3 = 0
( 6)  group3 = 0

F(  6,    65) =    2.28
Prob > F =    0.0463


Alternatively, we can use factor variables and contrast to perform the same test:

. generate group=cond(rep78==3,1,cond(rep78==4,2,3))

. regress price c.mpg##i.group c.weight##i.group

Source         SS       df       MS              Number of obs =      74

F(  8,    65) =    5.80

Model     264415585     8  33051948.1           Prob > F      =  0.0000

Residual     370649811    65  5702304.78           R-squared     =  0.4164

Total     635065396    73  8699525.97           Root MSE      =  2387.9

price        Coef.   Std. Err.      t    P>|t|     [95% Conf. Interval]

mpg     13.14912   178.9234     0.07   0.942    -344.1855    370.4837

group

2      4560.193   12222.22     0.37   0.710    -19849.27    28969.66

3      14556.66   9167.998     1.59   0.117    -3753.101    32866.41

group#c.mpg

2      130.5261   336.6547     0.39   0.699    -541.8198     802.872

3     -194.1974   216.3459    -0.90   0.373      -626.27    237.8752

weight     3.517687   .9847976     3.57   0.001      1.55091    5.484463

group#c.weight

2      -2.18337   1.837314    -1.19   0.239     -5.85274       1.486

3     -3.160952    1.73308    -1.82   0.073    -6.622152    .3002481

_cons    -5431.147    6398.12    -0.85   0.399    -18209.07    7346.781

. contrast group group#c.mpg group#c.weight,  overall

Contrasts of marginal linear predictions

Margins      : asbalanced

df           F        P>F

group            2        1.29     0.2835

group#c.mpg            2        0.78     0.4617

group#c.weight            2        1.88     0.1602

Overall            6        2.28     0.0463

Residual           65