【问题标题】:Generate a dummy-variable生成一个虚拟变量
【发布时间】:2012-08-10 18:26:48
【问题描述】:

我无法在 R 中生成以下虚拟变量:

我正在分析年度时间序列数据(时间段 1948-2009)。我有两个问题:

  1. 如何为观察 #10 生成一个虚拟变量,即 1957 年(1957 年的值 = 1,否则为零)?

  2. 如何生成一个在 1957 年之前为零并从 1957 年及以后到 2009 年取值为 1 的虚拟变量?

【问题讨论】:

    标签: r r-faq


    【解决方案1】:

    如果您有很多变量,另一个可以更好地工作的选项是factormodel.matrix

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

    这将包括一个截距列(全为)和一列用于数据集中的每一年,除了一列,这将是“默认”或截距值。

    您可以通过在model.matrix 中混淆contrasts.arg 来更改“默认”的选择方式。

    另外,如果您想省略截距,您可以直接删除第一列或在公式末尾添加+0

    希望这是有用的。

    【讨论】:

    • 如果您想为所有(而不是 k-1)生成无截距的虚拟变量怎么办?
    • 请注意 model.matrix( ) 接受多个变量以转换为虚拟变量:model.matrix( ~ var1 + var2, data = df) 同样,请确保它们是因子。
    • @Synergist 表(1:n,因子)。其中factor是原始变量,n是它的长度
    • @Synergist 该表是一个 n x k 矩阵,其中包含所有 k 个指标变量(而不是 k-1)
    • @FernandoHocesDeLaGuardia 您可以使用+ 0- 1 从公式中删除截距。所以model.matrix(~ year.f + 0) 会给出一个没有参考水平的虚拟变量。
    【解决方案2】:

    基地R中的这一个班轮

    model.matrix( ~ iris$Species - 1)
    

    给予

        iris$Speciessetosa iris$Speciesversicolor iris$Speciesvirginica
    1                    1                      0                     0
    2                    1                      0                     0
    3                    1                      0                     0
    4                    1                      0                     0
    5                    1                      0                     0
    6                    1                      0                     0
    7                    1                      0                     0
    8                    1                      0                     0
    9                    1                      0                     0
    10                   1                      0                     0
    11                   1                      0                     0
    12                   1                      0                     0
    13                   1                      0                     0
    14                   1                      0                     0
    15                   1                      0                     0
    16                   1                      0                     0
    17                   1                      0                     0
    18                   1                      0                     0
    19                   1                      0                     0
    20                   1                      0                     0
    21                   1                      0                     0
    22                   1                      0                     0
    23                   1                      0                     0
    24                   1                      0                     0
    25                   1                      0                     0
    26                   1                      0                     0
    27                   1                      0                     0
    28                   1                      0                     0
    29                   1                      0                     0
    30                   1                      0                     0
    31                   1                      0                     0
    32                   1                      0                     0
    33                   1                      0                     0
    34                   1                      0                     0
    35                   1                      0                     0
    36                   1                      0                     0
    37                   1                      0                     0
    38                   1                      0                     0
    39                   1                      0                     0
    40                   1                      0                     0
    41                   1                      0                     0
    42                   1                      0                     0
    43                   1                      0                     0
    44                   1                      0                     0
    45                   1                      0                     0
    46                   1                      0                     0
    47                   1                      0                     0
    48                   1                      0                     0
    49                   1                      0                     0
    50                   1                      0                     0
    51                   0                      1                     0
    52                   0                      1                     0
    53                   0                      1                     0
    54                   0                      1                     0
    55                   0                      1                     0
    56                   0                      1                     0
    57                   0                      1                     0
    58                   0                      1                     0
    59                   0                      1                     0
    60                   0                      1                     0
    61                   0                      1                     0
    62                   0                      1                     0
    63                   0                      1                     0
    64                   0                      1                     0
    65                   0                      1                     0
    66                   0                      1                     0
    67                   0                      1                     0
    68                   0                      1                     0
    69                   0                      1                     0
    70                   0                      1                     0
    71                   0                      1                     0
    72                   0                      1                     0
    73                   0                      1                     0
    74                   0                      1                     0
    75                   0                      1                     0
    76                   0                      1                     0
    77                   0                      1                     0
    78                   0                      1                     0
    79                   0                      1                     0
    80                   0                      1                     0
    81                   0                      1                     0
    82                   0                      1                     0
    83                   0                      1                     0
    84                   0                      1                     0
    85                   0                      1                     0
    86                   0                      1                     0
    87                   0                      1                     0
    88                   0                      1                     0
    89                   0                      1                     0
    90                   0                      1                     0
    91                   0                      1                     0
    92                   0                      1                     0
    93                   0                      1                     0
    94                   0                      1                     0
    95                   0                      1                     0
    96                   0                      1                     0
    97                   0                      1                     0
    98                   0                      1                     0
    99                   0                      1                     0
    100                  0                      1                     0
    101                  0                      0                     1
    102                  0                      0                     1
    103                  0                      0                     1
    104                  0                      0                     1
    105                  0                      0                     1
    106                  0                      0                     1
    107                  0                      0                     1
    108                  0                      0                     1
    109                  0                      0                     1
    110                  0                      0                     1
    111                  0                      0                     1
    112                  0                      0                     1
    113                  0                      0                     1
    114                  0                      0                     1
    115                  0                      0                     1
    116                  0                      0                     1
    117                  0                      0                     1
    118                  0                      0                     1
    119                  0                      0                     1
    120                  0                      0                     1
    121                  0                      0                     1
    122                  0                      0                     1
    123                  0                      0                     1
    124                  0                      0                     1
    125                  0                      0                     1
    126                  0                      0                     1
    127                  0                      0                     1
    128                  0                      0                     1
    129                  0                      0                     1
    130                  0                      0                     1
    131                  0                      0                     1
    132                  0                      0                     1
    133                  0                      0                     1
    134                  0                      0                     1
    135                  0                      0                     1
    136                  0                      0                     1
    137                  0                      0                     1
    138                  0                      0                     1
    139                  0                      0                     1
    140                  0                      0                     1
    141                  0                      0                     1
    142                  0                      0                     1
    143                  0                      0                     1
    144                  0                      0                     1
    145                  0                      0                     1
    146                  0                      0                     1
    147                  0                      0                     1
    148                  0                      0                     1
    149                  0                      0                     1
    150                  0                      0                     1
    

    【讨论】:

      【解决方案3】:

      我们也可以使用splitstackshape 中的cSplit_e。使用@zx8754的数据

      df1 <- data.frame(id = 1:4, year = 1991:1994)
      splitstackshape::cSplit_e(df1, "year", fill = 0)
      
      #  id year year_1 year_2 year_3 year_4
      #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
      

      要使其适用于数字以外的数据,我们需要将type 明确指定为"character"

      df1 <- data.frame(id = 1:4, let = LETTERS[1:4])
      splitstackshape::cSplit_e(df1, "let", fill = 0, type = "character")
      
      #  id let let_A let_B let_C let_D
      #1  1   A     1     0     0     0
      #2  2   B     0     1     0     0
      #3  3   C     0     0     1     0
      #4  4   D     0     0     0     1
      

      【讨论】:

        【解决方案4】:

        对于问题中提出的用例,您也可以将逻辑条件与1 相乘(或者甚至更好,与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)
        

        给出:

        > 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
        

        对于例如@zx8754 和@Sotos 的答案中提供的用例,还有一些其他选项尚未涵盖。

        1) 制作自己的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'))
        

        给出:

          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) 使用 中的dcast 函数

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

        给出:

          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
        

        但是,当必须为其创建虚拟对象的列中存在重复值时,这将不起作用。如果dcast 需要特定的聚合函数并且dcast 的结果需要合并回原来的:

        # 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)
        

        给出(注意结果是根据by 列排序的):

          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) 使用来自spread 函数(与来自mutate

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

        给出:

          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
        

        【讨论】:

          【解决方案5】:

          mlr 包括createDummyFeatures 用于此目的:

          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 删除原始变量。

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

          【讨论】:

          • Enrique,我已尝试安装该软件包,但在执行 library(mlr) 后似乎无法正常工作。我收到以下错误:«LoadNamespace 中的错误(j
          • 你需要先安装'ggvis'
          【解决方案6】:

          此处的其他答案提供了完成此任务的直接途径 - 许多模型(例如lm)无论如何都会在内部为您完成。尽管如此,这里有一些方法可以使用 Max Kuhn 流行的 caretrecipes 包制作虚拟变量。虽然有些冗长,但它们都可以轻松扩展到更复杂的情况,并巧妙地融入各自的框架。


          caret::dummyVars

          使用caret,相关函数是dummyVars,它有一个predict 方法将其应用于数据框:

          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

          recipes,相关函数为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
          

          根据上下文,使用prepbakejuice 提取数据:

          # 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
          

          【讨论】:

            【解决方案7】:

            使用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
            

            【讨论】:

            • 如果这是变量的含义,也许在函数 dummy 中添加“fun= factor”会有所帮助。
            • @FilippoMazza 我更喜欢将它们保留为整数,是的,如果需要我们可以设置因子。
            • @mike colnames(df1)
            • @DonF 这只是一个选项,你看到上面投票最多的基本答案了吗?
            • 一个未维护的包,会导致某些命令出现问题。 不推荐
            【解决方案8】:

            另一种方法是使用

            ifelse(year < 1965 , 1, 0)
            

            【讨论】:

              【解决方案9】:

              将您的数据转换为 data.table 并使用 set by reference 和行过滤

              library(data.table)
              
              dt <- as.data.table(your.dataframe.or.whatever)
              dt[, is.1957 := 0]
              dt[year == 1957, is.1957 := 1]
              

              概念验证玩具示例:

              library(data.table)
              
              dt <- as.data.table(cbind(c(1, 1, 1), c(2, 2, 3)))
              dt[, is.3 := 0]
              dt[V2 == 3, is.3 := 1]
              

              【讨论】:

                【解决方案10】:

                另一种方法是使用qdapTools包中的mtabulate,即

                df <- data.frame(var = sample(c("A", "B", "C"), 5, replace = TRUE))
                  var
                #1   C
                #2   A
                #3   C
                #4   B
                #5   B
                
                library(qdapTools)
                mtabulate(df$var)
                

                给出,

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

                【讨论】:

                  【解决方案11】:

                  ifelse 函数最适合这样的简单逻辑。

                  > 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
                  

                  另外,如果你希望它返回字符数据,那么你可以这样做。

                  > 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"
                  

                  带有嵌套的分类变量...

                  > 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"
                  

                  这是最直接的选择。

                  【讨论】:

                    【解决方案12】:

                    我使用这样一个函数(用于data.table):

                    # Ta funkcja dla obiektu data.table i zmiennej var.name typu factor tworzy dummy variables o nazwach "var.name: (level1)"
                    factorToDummy <- function(dtable, var.name){
                      stopifnot(is.data.table(dtable))
                      stopifnot(var.name %in% names(dtable))
                      stopifnot(is.factor(dtable[, get(var.name)]))
                    
                      dtable[, paste0(var.name,": ",levels(get(var.name)))] -> new.names
                      dtable[, (new.names) := transpose(lapply(get(var.name), FUN = function(x){x == levels(get(var.name))})) ]
                    
                      cat(paste("\nDodano zmienne dummy: ", paste0(new.names, collapse = ", ")))
                    }
                    

                    用法:

                    data <- data.table(data)
                    data[, x:= droplevels(x)]
                    factorToDummy(data, "x")
                    

                    【讨论】:

                      【解决方案13】:

                      我在 kaggle 论坛上读到了这篇文章:

                      #Generate example dataframe with character column
                      example <- as.data.frame(c("A", "A", "B", "F", "C", "G", "C", "D", "E", "F"))
                      names(example) <- "strcol"
                      
                      #For every unique value in the string column, create a new 1/0 column
                      #This is what Factors do "under-the-hood" automatically when passed to function requiring numeric data
                      for(level in unique(example$strcol)){
                        example[paste("dummy", level, sep = "_")] <- ifelse(example$strcol == level, 1, 0)
                      }
                      

                      【讨论】:

                        【解决方案14】:

                        如果你想得到K个虚拟变量,而不是K-1,试试:

                        dummies = table(1:length(year),as.factor(year))  
                        

                        最好的,

                        【讨论】:

                        • 结果表不能用作data.frame。如果这有问题,请使用as.data.frame.matrix(dummies) 将其翻译成一个
                        【解决方案15】:

                        您好,我编写了这个通用函数来生成一个虚拟变量,它基本上复制了 Stata 中的替换函数。

                        如果 x 是数据框是 x,我想要一个名为 a 的虚拟变量,当 x$b 取值 c 时,它将取值 1

                        introducedummy<-function(x,a,b,c){
                           g<-c(a,b,c)
                          n<-nrow(x)
                          newcol<-g[1]
                          p<-colnames(x)
                          p2<-c(p,newcol)
                          new1<-numeric(n)
                          state<-x[,g[2]]
                          interest<-g[3]
                          for(i in 1:n){
                            if(state[i]==interest){
                              new1[i]=1
                            }
                            else{
                              new1[i]=0
                            }
                          }
                            x$added<-new1
                            colnames(x)<-p2
                            x
                          }
                        

                        【讨论】:

                          【解决方案16】:

                          我通常使用这种虚拟变量做的是:

                          (1) 如何为观察 #10 生成一个虚拟变量,即 1957 年(1957 年的值 = 1,否则为零)

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

                          (2) 如何生成一个在 1957 年之前为零并从 1957 年及以后到 2009 年取值为 1 的虚拟变量?

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

                          然后,我可以在我的模型中将此因素作为虚拟变量引入。例如,查看变量y 中是否存在长期趋势:

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

                          希望这会有所帮助!

                          【讨论】:

                            【解决方案17】:

                            产生这些虚拟变量的最简单方法如下:

                            > 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
                            

                            更一般地,您可以使用ifelse 根据条件在两个值之间进行选择。因此,如果您出于某种原因想要使用 4 和 7 而不是 0-1 虚拟变量,则可以使用 ifelse(year == 1957, 4, 7)

                            【讨论】:

                              猜你喜欢
                              • 2018-05-28
                              • 2020-06-22
                              • 2022-07-31
                              • 2021-11-08
                              • 2017-10-27
                              • 1970-01-01
                              相关资源
                              最近更新 更多