生成一个虚拟变量
Posted
技术标签:
【中文标题】生成一个虚拟变量【英文标题】:Generate a dummy-variable 【发布时间】:2012-08-10 18:26:48 【问题描述】:我无法在 R 中生成以下虚拟变量:
我正在分析年度时间序列数据(时间段 1948-2009)。我有两个问题:
如何为观察 #10 ,即 1957 年(1957 年的值 = 1,否则为零)?
如何生成一个在 1957 年之前为零并从 1957 年及以后到 2009 年取值为 1 的虚拟变量?
【问题讨论】:
【参考方案1】:如果您有很多变量,另一个可以更好地工作的选项是factor
和model.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 流行的 caret
和 recipes
包制作虚拟变量。虽然有些冗长,但它们都可以轻松扩展到更复杂的情况,并巧妙地融入各自的框架。
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
根据上下文,使用prep
和bake
或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
【讨论】:
【参考方案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)
。
【讨论】:
以上是关于生成一个虚拟变量的主要内容,如果未能解决你的问题,请参考以下文章