## Generate a dummy-variable

### Question

I have trouble generating the following dummy-variables in R:

I'm analyzing yearly time series data (time period 1948-2009). I have two questions:

How do I generate a dummy variable for observation #10, i.e. for year 1957 (value = 1 at 1957 and zero otherwise)?

How do I generate a dummy variable which is zero before 1957 and takes the value 1 from 1957 and onwards to 2009?

### Popular Answer

Another option that can work better if you have many variables is `factor`

and `model.matrix`

.

```
> year.f = factor(year)
> dummies = model.matrix(~year.f)
```

This will include an intercept column (all ones) and one column for each of the years in your data set except one, which will be the "default" or intercept value.

You can change how the "default" is chosen by messing with `contrasts.arg`

in `model.matrix`

.

Also, if you want to omit the intercept, you can just drop the first column or add `+0`

to the end of the formula.

Hope this is useful.

Read more... Read less...

The simplest way to produce these dummy variables is something like the following:

```
> print(year)
[1] 1956 1957 1957 1958 1958 1959
> dummy <- as.numeric(year == 1957)
> print(dummy)
[1] 0 1 1 0 0 0
> dummy2 <- as.numeric(year >= 1957)
> print(dummy2)
[1] 0 1 1 1 1 1
```

More generally, you can use `ifelse`

to choose between two values depending on a condition. So if instead of a 0-1 dummy variable, for some reason you wanted to use, say, 4 and 7, you could use `ifelse(year == 1957, 4, 7)`

.

Using dummies::dummy():

```
library(dummies)
# example data
df1 <- data.frame(id = 1:4, year = 1991:1994)
df1 <- cbind(df1, dummy(df1$year, sep = "_"))
df1
# id year df1_1991 df1_1992 df1_1993 df1_1994
# 1 1 1991 1 0 0 0
# 2 2 1992 0 1 0 0
# 3 3 1993 0 0 1 0
# 4 4 1994 0 0 0 1
```

Package `mlr`

includes `createDummyFeatures`

for this purpose:

```
library(mlr)
df <- data.frame(var = sample(c("A", "B", "C"), 10, replace = TRUE))
df
# var
# 1 B
# 2 A
# 3 C
# 4 B
# 5 C
# 6 A
# 7 C
# 8 A
# 9 B
# 10 C
createDummyFeatures(df, cols = "var")
# var.A var.B var.C
# 1 0 1 0
# 2 1 0 0
# 3 0 0 1
# 4 0 1 0
# 5 0 0 1
# 6 1 0 0
# 7 0 0 1
# 8 1 0 0
# 9 0 1 0
# 10 0 0 1
```

`createDummyFeatures`

drops original variable.

https://www.rdocumentation.org/packages/mlr/versions/2.9/topics/createDummyFeatures

.....

The other answers here offer direct routes to accomplish this task—one that many models (e.g. `lm`

) will do for you internally anyway. Nonetheless, here are ways to make dummy variables with Max Kuhn's popular `caret`

and `recipes`

packages. While somewhat more verbose, they both scale easily to more complicated situations, and fit neatly into their respective frameworks.

`caret::dummyVars`

With `caret`

, the relevant function is `dummyVars`

, which has a `predict`

method to apply it on a data frame:

```
df <- data.frame(letter = rep(c('a', 'b', 'c'), each = 2),
y = 1:6)
library(caret)
dummy <- dummyVars(~ ., data = df, fullRank = TRUE)
dummy
#> Dummy Variable Object
#>
#> Formula: ~.
#> 2 variables, 1 factors
#> Variables and levels will be separated by '.'
#> A full rank encoding is used
predict(dummy, df)
#> letter.b letter.c y
#> 1 0 0 1
#> 2 0 0 2
#> 3 1 0 3
#> 4 1 0 4
#> 5 0 1 5
#> 6 0 1 6
```

`recipes::step_dummy`

With `recipes`

, the relevant function is `step_dummy`

:

```
library(recipes)
dummy_recipe <- recipe(y ~ letter, df) %>%
step_dummy(letter)
dummy_recipe
#> Data Recipe
#>
#> Inputs:
#>
#> role #variables
#> outcome 1
#> predictor 1
#>
#> Steps:
#>
#> Dummy variables from letter
```

Depending on context, extract the data with `prep`

and either `bake`

or `juice`

:

```
# Prep and bake on new data...
dummy_recipe %>%
prep() %>%
bake(df)
#> # A tibble: 6 x 3
#> y letter_b letter_c
#> <int> <dbl> <dbl>
#> 1 1 0 0
#> 2 2 0 0
#> 3 3 1 0
#> 4 4 1 0
#> 5 5 0 1
#> 6 6 0 1
# ...or use `retain = TRUE` and `juice` to extract training data
dummy_recipe %>%
prep(retain = TRUE) %>%
juice()
#> # A tibble: 6 x 3
#> y letter_b letter_c
#> <int> <dbl> <dbl>
#> 1 1 0 0
#> 2 2 0 0
#> 3 3 1 0
#> 4 4 1 0
#> 5 5 0 1
#> 6 6 0 1
```

For the usecase as presented in the question, you can also just multiply the logical condition with `1`

(or maybe even better, with `1L`

):

```
# example data
df1 <- data.frame(yr = 1951:1960)
# create the dummies
df1$is.1957 <- 1L * (df1$yr == 1957)
df1$after.1957 <- 1L * (df1$yr >= 1957)
```

which gives:

`> df1 yr is.1957 after.1957 1 1951 0 0 2 1952 0 0 3 1953 0 0 4 1954 0 0 5 1955 0 0 6 1956 0 0 7 1957 1 1 8 1958 0 1 9 1959 0 1 10 1960 0 1`

For the usecases as presented in for example the answers of @zx8754 and @Sotos, there are still some other options which haven't been covered yet imo.

**1) Make your own make_dummies-function**

```
# example data
df2 <- data.frame(id = 1:5, year = c(1991:1994,1992))
# create a function
make_dummies <- function(v, prefix = '') {
s <- sort(unique(v))
d <- outer(v, s, function(v, s) 1L * (v == s))
colnames(d) <- paste0(prefix, s)
d
}
# bind the dummies to the original dataframe
cbind(df2, make_dummies(df2$year, prefix = 'y'))
```

which gives:

`id year y1991 y1992 y1993 y1994 1 1 1991 1 0 0 0 2 2 1992 0 1 0 0 3 3 1993 0 0 1 0 4 4 1994 0 0 0 1 5 5 1992 0 1 0 0`

**2) use the dcast-function from either data.table or reshape2**

```
dcast(df2, id + year ~ year, fun.aggregate = length)
```

which gives:

`id year 1991 1992 1993 1994 1 1 1991 1 0 0 0 2 2 1992 0 1 0 0 3 3 1993 0 0 1 0 4 4 1994 0 0 0 1 5 5 1992 0 1 0 0`

However, this will not work when there are duplicate values in the column for which the dummies have to be created. In the case a specific aggregation function is needed for `dcast`

and the result of of `dcast`

need to be merged back to the original:

```
# example data
df3 <- data.frame(var = c("B", "C", "A", "B", "C"))
# aggregation function to get dummy values
f <- function(x) as.integer(length(x) > 0)
# reshape to wide with the cumstom aggregation function and merge back to the original
merge(df3, dcast(df3, var ~ var, fun.aggregate = f), by = 'var', all.x = TRUE)
```

which gives (note that the result is ordered according to the `by`

column):

`var A B C 1 A 1 0 0 2 B 0 1 0 3 B 0 1 0 4 C 0 0 1 5 C 0 0 1`

**3) use the spread-function from tidyr (with mutate from dplyr)**

```
library(dplyr)
library(tidyr)
df2 %>%
mutate(v = 1, yr = year) %>%
spread(yr, v, fill = 0)
```

which gives:

`id year 1991 1992 1993 1994 1 1 1991 1 0 0 0 2 2 1992 0 1 0 0 3 3 1993 0 0 1 0 4 4 1994 0 0 0 1 5 5 1992 0 1 0 0`