Tạo một biến giả


86

Tôi gặp sự cố khi tạo các biến giả sau trong R:

Tôi đang phân tích dữ liệu chuỗi thời gian hàng năm (khoảng thời gian 1948-2009). Tôi có hai câu hỏi:

  1. Làm cách nào để tạo một biến giả cho quan sát số 10, tức là cho năm 1957 (giá trị = 1 vào năm 1957 và bằng không nếu không)?

  2. Làm cách nào để tạo một biến giả bằng 0 trước năm 1957 và nhận giá trị 1 từ năm 1957 trở đi đến năm 2009?

Câu trả lời:


113

Một tùy chọn khác có thể hoạt động tốt hơn nếu bạn có nhiều biến là factormodel.matrix.

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

Điều này sẽ bao gồm một cột chặn (tất cả các cột) và một cột cho mỗi năm trong tập dữ liệu của bạn ngoại trừ một cột, sẽ là giá trị "mặc định" hoặc giá trị chặn.

Bạn có thể thay đổi cách chọn "mặc định" bằng cách nhập contrasts.argvào model.matrix.

Ngoài ra, nếu bạn muốn bỏ qua dấu chặn, bạn chỉ cần bỏ cột đầu tiên hoặc thêm +0vào cuối công thức.

Hy vọng điều này là hữu ích.


4
Điều gì sẽ xảy ra nếu bạn muốn tạo các biến giả cho tất cả (thay vì k-1) mà không bị chặn?
Fernando Hoces De La Guardia

1
lưu ý rằng model.matrix () chấp nhận nhiều biến để chuyển đổi thành hình nộm: model.matrix (~ var1 + var2, data = df) Một lần nữa, chỉ cần đảm bảo rằng chúng là các yếu tố.
slizb

3
Bảng @Synergist (1: n, thừa số). Trong trường hợp yếu tố là biến ban đầu và n là chiều dài của nó
Fernando Hoces De La Guardia

1
@Synergist rằng bảng đó là ma trận anxk với tất cả k biến chỉ báo (thay vì k-1)
Fernando Hoces De La Guardia

6
@FernandoHocesDeLaGuardia Bạn có thể xóa dấu chặn khỏi công thức bằng + 0 hoặc - 1. Vì vậy, model.matrix(~ year.f + 0)sẽ cung cấp cho một biến giả mà không có mức tham chiếu.
Gregor Thomas

60

Cách đơn giản nhất để tạo ra các biến giả này giống như sau:

> 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

Nói chung hơn, bạn có thể sử dụng ifelseđể chọn giữa hai giá trị tùy thuộc vào điều kiện. Vì vậy, nếu thay vì một biến giả 0-1, vì lý do nào đó bạn muốn sử dụng, chẳng hạn, 4 và 7, bạn có thể sử dụng ifelse(year == 1957, 4, 7).


49

Sử dụng hình nộm :: 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

Có thể thêm "fun = factor" trong hàm giả có thể hữu ích nếu đó là ý nghĩa của biến.
Filippo Mazza

@FilippoMazza Tôi muốn giữ chúng dưới dạng số nguyên, vâng, chúng tôi có thể đặt hệ số nếu cần.
zx8754 Ngày

làm cách nào để xóa df1 trước mỗi tên tiêu đề cột giả?
mike

@ Mike colnames (df1) <- gsub ( "df1_", "", cố định = TRUE, colnames (df1))
zx8754

19

Gói mlrbao gồm createDummyFeaturescho mục đích này:

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 giảm biến ban đầu.

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


1
Enrique, tôi đã thử cài đặt gói, nhưng có vẻ như nó không hoạt động sau khi thực hiện thư viện (mlr). Tôi gặp lỗi sau: «Lỗi trong loadNamespace (j <- i [[1L]], c (lib.loc, .libPaths ()), versionCheck = vI [[j]]): không có gói nào được gọi là 'ggvis 'Ngoài ra: Thông báo cảnh báo: gói' mlr 'được xây dựng theo phiên bản R 3.2.5. Lỗi: tải gói hoặc không gian tên không thành công cho' mlr '»
Một ông già trên biển.

1
bạn cần phải cài đặt 'ggvis' đầu tiên
Ted Mosby

17

Các câu trả lời khác ở đây cung cấp các lộ trình trực tiếp để hoàn thành nhiệm vụ này — một cách mà nhiều mô hình (ví dụ lm) sẽ làm cho bạn trong nội bộ. Tuy nhiên, đây là cách tạo biến giả với các gói caretrecipesgói phổ biến của Max Kuhn . Mặc dù có phần dài dòng hơn, nhưng cả hai đều dễ dàng mở rộng các tình huống phức tạp hơn và phù hợp với khuôn khổ tương ứng của chúng.


caret::dummyVars

Với caret, hàm có liên quan là dummyVars, có predictphương pháp áp dụng nó trên khung dữ liệu:

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

Với recipes, chức năng liên quan là 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

Tùy thuộc vào ngữ cảnh, trích xuất dữ liệu bằng prepvà hoặc bakehoặc 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

11

Đối với usecase như được trình bày trong câu hỏi, bạn cũng có thể chỉ cần nhân điều kiện logic với 1(hoặc thậm chí có thể tốt hơn, với 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)

mang lại:

> 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

Đối với các tiện ích như được trình bày trong ví dụ: câu trả lời của @ zx8754 và @Sotos, vẫn còn một số tùy chọn khác chưa được đề cập đến trên imo.

1) Tạo make_dummieschức năng của riêng bạn

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

mang lại:

  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) sử dụng dcastchức năng từ một trong hai hoặc là

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

mang lại:

  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

Tuy nhiên, điều này sẽ không hoạt động khi có các giá trị trùng lặp trong cột mà các hình nộm phải được tạo. Trong trường hợp một hàm tổng hợp cụ thể là cần thiết dcastvà kết quả của việc dcastcần được hợp nhất trở lại ban đầu:

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

mà cho (lưu ý rằng kết quả được sắp xếp theo bycột):

  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) sử dụng spreadchức năng từ(với mutatetừ)

library(dplyr)
library(tidyr)

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

mang lại:

  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

10

Những gì tôi thường làm để làm việc với loại biến giả này là:

(1) làm cách nào để tạo một biến giả cho quan sát số 10, tức là cho năm 1957 (giá trị = 1 vào năm 1957 và bằng không nếu không)

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

(2) Làm cách nào để tạo một biến giả bằng 0 trước năm 1957 và nhận giá trị 1 từ năm 1957 trở đi đến năm 2009?

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

Sau đó, tôi có thể giới thiệu yếu tố này như một biến giả trong các mô hình của tôi. Ví dụ: để xem liệu có xu hướng dài hạn trong một biến thể hay không y :

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

Hi vọng điêu nay co ich!


7

Nếu bạn muốn nhận K biến giả, thay vì K-1, hãy thử:

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

Tốt,


bảng kết quả không thể được sử dụng làm data.frame. Nếu đó là vấn đề, hãy sử dụng as.data.frame.matrix(dummies)để dịch nó thành một vấn đề
sheß

7

Tôi đọc điều này trên diễn đàn 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)
}

5

Các ifelsechức năng là tốt nhất cho logic đơn giản như thế này.

> 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

Ngoài ra, nếu bạn muốn nó trả về dữ liệu ký tự thì bạn có thể làm như vậy.

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

Các biến phân loại có lồng ...

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

Đây là lựa chọn đơn giản nhất.


4

Một cách khác là sử dụng mtabulatetừ qdapToolsgói, tức là

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)

mang lại,

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

2

Chuyển đổi dữ liệu của bạn thành data.table và sử dụng theo bộ tham chiếu và lọc hàng

library(data.table)

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

Ví dụ về đồ chơi bằng chứng về khái niệm:

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]

2

Một lớp lót này trong cơ sở R

model.matrix( ~ iris$Species - 1)

cho

    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

1

Tôi sử dụng một hàm như vậy (cho 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 = ", ")))
}

Sử dụng:

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

1

một cách khác bạn có thể làm là sử dụng

ifelse(year < 1965 , 1, 0)

0

Xin chào, tôi đã viết hàm chung này để tạo một biến giả về cơ bản sao chép hàm thay thế trong Stata.

Nếu x là khung dữ liệu là x và tôi muốn một biến giả được gọi là biến anày sẽ nhận giá trị 1khi x$bnhận giá trịc

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
  }

0

Chúng tôi cũng có thể sử dụng cSplit_etừ splitstackshape. Sử dụng dữ liệu của @ 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

Để làm cho nó hoạt động cho dữ liệu không phải là số, chúng tôi cần chỉ định rõ ràng 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.