R: Expands formula macros

xpd {fixest} | R Documentation

## Expands formula macros

### Description

Create macros within formulas and expand them with character vectors or other formulas.

### Usage

    xpd(fml, ..., lhs, rhs, data = NULL)

### Arguments

`fml` | A formula containing macros variables. Each macro variable must start with two dots. The macro variables can be set globally using `setFixest_fml`, or can be defined in `...`. Special macros of the form `..("regex")` can be used to fetch, through a regular expression, variables directly in a character vector (or in column names) given in the argument `data`. square brackets have a special meaning: Values in them are evaluated and parsed accordingly. Example: `y~x.[1:2] + z.[i]` will lead to `y~x1+x2+z3` if `i==3`. See examples.
`...` | Definition of the macro variables. Each argument name corresponds to the name of the macro variable. It is required that each macro variable name starts with two dots (e.g. `..ctrl`). The value of each argument must be a one-sided formula or a character vector, it is the definition of the macro variable. Example of a valid call: `setFixest_fml(..ctrl = ~ var1 + var2)`. In the function `xpd`, the default macro variables are taken from `getFixest_fml`, any variable in `...` will replace these values. You can enclose values in `.[]`, if so they will be evaluated from the current environment. For example `..ctrl = ~ x.[1:2] + .[z]` will lead to `~x1 + x2 + var` if `z` is equal to `"var"`.
`lhs` | If present then a formula will be constructed with `lhs` as the full left-hand-side. The value of `lhs` can be a one-sided formula, a call, or a character vector. Note that the macro variables wont be applied. You can use it in combination with the argument `rhs`. Note that if `fml` is not missing, its LHS will be replaced by `lhs`.
`rhs` | If present, then a formula will be constructed with `rhs` as the full right-hand-side. The value of `rhs` can be a one-sided formula, a call, or a character vector. Note that the macro variables wont be applied. You can use it in combination with the argument `lhs`. Note that if `fml` is not missing, its RHS will be replaced by `rhs`.
`data` | Either a character vector or a data.frame. This argument will only be used if a macro of the type `..("regex")` is used in the formula of the argument `fml`. If so, any variable name from `data` that matches the regular expression will be added to the formula.

### Details

In `xpd`, the default macro variables are taken from `getFixest_fml`. Any value in the `...` argument of `xpd` will replace these default values.

The definitions of the macro variables will replace in verbatim the macro variables. Therefore, you can include multi-part formulas if you wish but then beware of the order of the macros variable in the formula. For example, using the `airquality` data, say you want to set as controls the variable `Temp` and `Day` fixed-effects, you can do `setFixest_fml(..ctrl = ~Temp | Day)`, but then `feols(Ozone ~ Wind + ..ctrl, airquality)` will be quite different from `feols(Ozone ~ ..ctrl + Wind, airquality)`, so beware!

### Value

It returns a formula where all macros have been expanded.

### Dot square bracket operator in formulas

In a formula, the dot square bracket (DSB) operator can: i) create manifold variables at once, or ii) capture values from the current environment and put them verbatim in the formula.

Say you want to include the variables `x1` to `x3` in your formula. You can use `xpd(y ~ x.[1:3])` and you'll get `y ~ x1 + x2 + x3`.

To summon values from the environment, simply put the variable in square brackets. For example: `for(i in 1:3) xpd(y.[i] ~ x)` will create the formulas `y1 ~ x` to `y3 ~ x` depending on the value of `i`.

You can include a full variable from the environment in the same way: `for(y in c("a", "b")) xpd(.[y] ~ x)` will create the two formulas `a ~ x` and `b ~ x`.

The DSB can even be used within variable names, but then the variable must be nested in character form. For example `y ~ .["x.[1:2]_sq"]` will create `y ~ x1_sq + x2_sq`. Using the character form is important to avoid a formula parsing error.

In all `fixest` estimations, this special parsing is enabled, so you don't need to use `xpd`.

Limitations: the use of multiple square brackets within a single variable is not implemented. For example, the following will not work `xpd(y ~ ..x, ..x = x.[1:3]_.[1:3])`.

### Regular expressions

You can catch several variable names at once by using regular expressions. To use regular expressions, you need to enclose it in the dot-dot function: `..("regex")`. For example, `..("Sepal")` will catch both the variables `Sepal.Length` and `Sepal.Width` from the `iris` data set. In a `fixest` estimation, the variables names from which the regex will be applied come from the data set. If you use `xpd`, you need to provide either a data set or a vector of names in the argument `data`.

Note that the dot square bracket operator (DSB, see before) is applied before the regular expression is evaluated. This means that `..("x.[3:4]_sq")` will lead, after evaluation of the DSB, to `..("x3_sq|x4_sq")`. It is a handy way to insert range of numbers in a regular expression.

### See Also

`setFixest_fml` to set formula macros.

### Examples

    # Small examples with airquality data
    data(airquality)
    # we set two macro variables
    setFixest_fml(..ctrl = ~ Temp + Day,
                  ..ctrl_long = ~ poly(Temp, 2) + poly(Day, 2))

    # Using the macro in lm with xpd:
    lm(xpd(Ozone ~ Wind + ..ctrl), airquality)
    lm(xpd(Ozone ~ Wind + ..ctrl_long), airquality)

    # You can use the macros without xpd() in fixest estimations
    a = feols(Ozone ~ Wind + ..ctrl, airquality)
    b = feols(Ozone ~ Wind + ..ctrl_long, airquality)
    etable(a, b, keep = "Int|Win")

    # Using .[]

    base = setNames(iris, c("y", "x1", "x2", "x3", "species"))
    i = 2:3
    z = "species"
    lm(xpd(y ~ x.[2:3] + .[z]), base)

    # No xpd() needed in feols
    feols(y ~ x.[2:3] + .[z], base)

    #
    # You can use xpd for stepwise estimations
    #

    # Note that for stepwise estimations in fixest, you can use
    # the stepwise functions: sw, sw0, csw, csw0
    # -> see help in feols or in the dedicated vignette

    # we want to look at the effect of x1 on y
    # controlling for different variables

    base = iris
    names(base) = c("y", "x1", "x2", "x3", "species")

    # We first create a matrix with all possible combinations of variables
    my_args = lapply(names(base)[-(1:2)], function(x) c("", x))
    (all_combs = as.matrix(do.call("expand.grid", my_args)))

    res_all = list()
    for(i in 1:nrow(all_combs)){
      res_all[[i]] = feols(xpd(y ~ x1 + ..v, ..v = all_combs[i, ]), base)
    }

    etable(res_all)
    coefplot(res_all, group = list(Species = "^^species"))

    #
    # You can use macros to grep variables in your data set
    #

    # Example 1: setting a macro variable globally

    data(longley)
    setFixest_fml(..many_vars = grep("GNP|ployed", names(longley), value = TRUE))
    feols(Armed.Forces ~ Population + ..many_vars, longley)

    # Example 2: using ..("regex") to grep the variables "live"

    feols(Armed.Forces ~ Population + ..("GNP|ployed"), longley)

    # Example 3: same as Ex.2 but without using a fixest estimation

    # Here we need to use xpd():
    lm(xpd(Armed.Forces ~ Population + ..("GNP|ployed"), data = longley), longley)

    #
    # You can also put numbers in macros
    #

    res_all = list()
    for(p in 1:3){
      res_all[[p]] = feols(xpd(Ozone ~ Wind + poly(Temp, ..p), ..p = p), airquality)
    }

    etable(res_all)

    #
    # lhs and rhs arguments
    #

    # to create a one sided formula from a character vector
    vars = letters[1:5]
    xpd(rhs = vars)

    # Alternatively, to replace the RHS
    xpd(y ~ 1, rhs = vars)

    # To create a two sided formula
    xpd(lhs = "y", rhs = vars)

    #
    # Dot square bracket operator
    #

    # You can create multiple variables at once
    xpd(y ~ x.[1:5] + z.[2:3])

    # You can summon variables from the environment
    var = "a"
    xpd(y ~ x.[var])

    # ... the variables can be multiple
    vars = LETTERS[1:3]
    xpd(y ~ x.[vars])

    # You can have "complex" variable names but they must be nested in character form
    xpd(y ~ .["x.[vars]_sq"])

    # DSB can be used within regular expressions
    re = c("GNP", "Pop")
    xpd(Unemployed ~ ..(".[re]"), data = longley)

    # => equivalent to ..("GNP|Pop")

[Package fixest version 0.10.0 Index]