Generate a dummy-variable

前端 未结 17 1066
遇见更好的自我
遇见更好的自我 2020-11-21 11:41

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:

  1. <
相关标签:
17条回答
  • 2020-11-21 12:16

    What I normally do to work with this kind of dummy variables is:

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

    data$factor_year_1 <- factor ( with ( data, ifelse ( ( year == 1957 ), 1 , 0 ) ) )
    

    (2) how do I generate a dummy-variable which is zero before 1957 and takes the value 1 from 1957 and onwards to 2009?

    data$factor_year_2 <- factor ( with ( data, ifelse ( ( year < 1957 ), 0 , 1 ) ) )
    

    Then, I can introduce this factor as a dummy variable in my models. For example, to see whether there is a long-term trend in a varible y :

    summary ( lm ( y ~ t,  data = data ) )
    

    Hope this helps!

    0 讨论(0)
  • 2020-11-21 12:17

    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
    
    0 讨论(0)
  • 2020-11-21 12:18

    another way you can do it is use

    ifelse(year < 1965 , 1, 0)
    
    0 讨论(0)
  • 2020-11-21 12:19

    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.

    0 讨论(0)
  • 2020-11-21 12:24

    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
    
    0 讨论(0)
  • 2020-11-21 12:26

    The ifelse function is best for simple logic like this.

    > x <- seq(1950, 1960, 1)
    
        ifelse(x == 1957, 1, 0)
        ifelse(x <= 1957, 1, 0)
    
    >  [1] 0 0 0 0 0 0 0 1 0 0 0
    >  [1] 1 1 1 1 1 1 1 1 0 0 0
    

    Also, if you want it to return character data then you can do so.

    > x <- seq(1950, 1960, 1)
    
        ifelse(x == 1957, "foo", "bar")
        ifelse(x <= 1957, "foo", "bar")
    
    >  [1] "bar" "bar" "bar" "bar" "bar" "bar" "bar" "foo" "bar" "bar" "bar"
    >  [1] "foo" "foo" "foo" "foo" "foo" "foo" "foo" "foo" "bar" "bar" "bar"
    

    Categorical variables with nesting...

    > x <- seq(1950, 1960, 1)
    
        ifelse(x == 1957, "foo", ifelse(x == 1958, "bar","baz"))
    
    >  [1] "baz" "baz" "baz" "baz" "baz" "baz" "baz" "foo" "bar" "baz" "baz"
    

    This is the most straightforward option.

    0 讨论(0)
提交回复
热议问题