生成一个虚拟变量

Posted

技术标签:

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

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

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

    如何为观察 #10 ,即 1957 年(1957 年的值 = 1,否则为零)?

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

【问题讨论】:

【参考方案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) 使用data.table 或reshape2 中的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) 使用来自tidyr 的spread 函数(与来自dplyr 的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)

【讨论】:

以上是关于生成一个虚拟变量的主要内容,如果未能解决你的问题,请参考以下文章

在 R data.table 中创建虚拟变量

Java 虚拟机原理Class 字节码二进制文件分析 七 ( 局部变量表分析 )

细说虚拟机栈

java虚拟机内存区常用名词解释

java 静态变量和静态常量

Java虚拟机 学习 第二章总结