Создать фиктивную переменную

86

У меня проблемы с созданием следующих фиктивных переменных в R:

Я анализирую данные годовых временных рядов (период 1948-2009 гг.). У меня два вопроса:

  1. Как мне создать фиктивную переменную для наблюдения № 10, то есть для 1957 года (значение = 1 в 1957 году и ноль в противном случае)?

  2. Как создать фиктивную переменную, которая была равна нулю до 1957 года и принимала значение 1 с 1957 года и далее до 2009 года?

Пантера
источник

Ответы:

113

Другой вариант, который может работать лучше, если у вас много переменных, - это factorи model.matrix.

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

Это будет включать столбец пересечения (все) и один столбец для каждого года в вашем наборе данных, кроме одного, который будет значением по умолчанию или значением пересечения.

Вы можете изменить способ выбора "по умолчанию", введя contrasts.argin model.matrix.

Кроме того, если вы хотите опустить перехват, вы можете просто отбросить первый столбец или добавить +0в конец формулы.

Надеюсь, это будет полезно.

Дэвид Дж. Харрис
источник
4
что, если вы хотите сгенерировать фиктивные переменные для всех (вместо k-1) без перехвата?
Фернандо Осес Де Ла Гуардия,
1
обратите внимание, что model.matrix () принимает несколько переменных для преобразования в фиктивные: model.matrix (~ var1 + var2, data = df) Опять же, просто убедитесь, что они являются факторами.
slizb
3
Таблица @Synergist (1: n, коэффициент). Где фактор - это исходная переменная, а n - ее длина
Фернандо Осес Де Ла Гуардия
1
@Synergist, эта таблица представляет собой матрицу тревог со всеми k индикаторными переменными (вместо k-1)
Фернандо Осес Де Ла Гуардия,
6
@FernandoHocesDeLaGuardia Вы можете удалить точку пересечения из формулы с помощью + 0 или - 1. Так model.matrix(~ year.f + 0)будут даны фиктивные переменные без эталонного уровня.
Грегор Томас
60

Самый простой способ создать эти фиктивные переменные - это примерно так:

> 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для выбора одного из двух значений в зависимости от условия. Так что, если вместо фиктивной переменной 0-1 по какой-то причине вы хотите использовать, скажем, 4 и 7, вы можете использовать ifelse(year == 1957, 4, 7).

Мартин О'Лири
источник
49

Использование 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
zx8754
источник
Может быть, добавление «fun = factor» в фиктивную функцию может помочь, если это значение переменной.
Филиппо Мацца
@FilippoMazza Я предпочитаю сохранять их целыми числами, да, при необходимости мы можем установить коэффициент.
zx8754 08
как удалить df1 перед именами заголовков каждого фиктивного столбца?
Майк
@mike colnames (df1) <- gsub ("df1_", "", fixed = TRUE, colnames (df1))
zx8754
19

Пакет для этого 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
.....

Энрике Перес Эрреро
источник
1
Энрике, я пробовал установить пакет, но, похоже, он не работает после выполнения библиотеки (mlr). Я получаю следующую ошибку: «Ошибка в loadNamespace (j <- i [[1L]], c (lib.loc, .libPaths ()), versionCheck = vI [[j]]): нет пакета с именем 'ggvis «Вдобавок: предупреждающее сообщение: пакет« mlr »был собран под R версии 3.2.5. Ошибка: не удалось загрузить пакет или пространство имен для« mlr »»
Старик в море.
1
сначала вам нужно установить ggvis
Тед Мосби
17

Другие ответы здесь предлагают прямые маршруты для выполнения этой задачи, которые многие модели (например lm) в любом случае сделают для вас внутри. Тем не менее, вот способы сделать фиктивные переменные популярными caretс помощью recipesпакетов Max Kuhn и . Хотя они несколько более подробны, они оба легко масштабируются для более сложных ситуаций и аккуратно вписываются в соответствующие рамки.


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
Алистер
источник
11

Для варианта использования, представленного в вопросе, вы также можете просто умножить логическое условие на 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, есть еще некоторые другие варианты, которые еще не были рассмотрены imo.

1) Сделайте свою собственную make_dummiesфункцию

# 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
Яап
источник
10

Что я обычно делаю для работы с такими фиктивными переменными:

(1) как мне создать фиктивную переменную для наблюдения № 10, то есть для 1957 года (значение = 1 в 1957 году и ноль в противном случае)

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

(2) как мне создать фиктивную переменную, которая была равна нулю до 1957 года и принимала значение 1 с 1957 года и далее до 2009 года?

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

Затем я могу ввести этот фактор в качестве фиктивной переменной в свои модели. Например, чтобы увидеть, есть ли долгосрочный тренд в переменной y :

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

Надеюсь это поможет!

Рикардо Гонсалес-Хиль
источник
7

Если вы хотите получить K фиктивных переменных вместо K-1, попробуйте:

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

Лучший,

Фернандо Осес де ла Гуардия
источник
итоговую таблицу нельзя использовать как data.frame. Если это проблема, используйте, as.data.frame.matrix(dummies)чтобы перевести это в один
sheß
7

Я прочитал это на форуме 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)
}
skpro19
источник
5

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"

Это самый простой вариант.

Алекс Томпсон
источник
4

Другой способ - использовать mtabulateиз qdapToolsпакета, т.е.

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
Сотос
источник
2

Преобразуйте свои данные в таблицу data.table и используйте набор по ссылке и фильтрацию строк

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]
слова
источник
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
Стивек
источник
1

Я использую такую ​​функцию (для 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")
Мацей Мозолевски
источник
1

Другой способ сделать это - использовать

ifelse(year < 1965 , 1, 0)
София Дж.
источник
0

Привет, я написал эту общую функцию для создания фиктивной переменной, которая по сути копирует функцию замены в Stata.

Если x - это фрейм данных, это x, и я хочу, чтобы вызывалась фиктивная переменная, aкоторая будет принимать значение, 1когда x$bпринимает значение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
  }
Kangkan Dc
источник
0

Мы также можем использовать cSplit_efrom splitstackshape. Использование данных @ 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
Ронак Шах
источник