Generar una variable ficticia

86

Tengo problemas para generar las siguientes variables ficticias en R:

Estoy analizando datos de series de tiempo anuales (período de tiempo 1948-2009). Tengo dos preguntas:

  1. ¿Cómo puedo generar una variable ficticia para la observación n. ° 10, es decir, para el año 1957 (valor = 1 en 1957 y cero en caso contrario)?

  2. ¿Cómo genero una variable ficticia que es cero antes de 1957 y toma el valor 1 desde 1957 en adelante hasta 2009?

Pantera
fuente

Respuestas:

113

Otra opción que puede funcionar mejor si tiene muchas variables es factory model.matrix.

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

Esto incluirá una columna de intersección (todos unos) y una columna para cada uno de los años en su conjunto de datos excepto uno, que será el valor "predeterminado" o de intersección.

Puede cambiar la forma en que se elige el "predeterminado" jugando con contrasts.argin model.matrix.

Además, si desea omitir la intersección, puede soltar la primera columna o agregarla +0al final de la fórmula.

Espero que esto sea de utilidad.

David J. Harris
fuente
4
¿Qué pasa si desea generar variables ficticias para todos (en lugar de k-1) sin intersección?
Fernando Hoces De La Guardia
1
tenga en cuenta que model.matrix () acepta múltiples variables para transformarlas en dummies: model.matrix (~ var1 + var2, data = df) De nuevo, asegúrese de que sean factores.
Slizb
3
@ Tabla de sinergistas (1: n, factor). Donde factor es la variable original yn es su longitud
Fernando Hoces De La Guardia
1
@Synergist esa tabla es una matriz de ansiedad con todas las k variables indicadoras (en lugar de k-1)
Fernando Hoces De La Guardia
6
@FernandoHocesDeLaGuardia Puede eliminar la intersección de una fórmula con + 0 o - 1. Por model.matrix(~ year.f + 0)lo tanto , dará variables ficticias sin un nivel de referencia.
Gregor Thomas
60

La forma más sencilla de producir estas variables ficticias es algo como lo siguiente:

> 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

De manera más general, puede utilizar ifelsepara elegir entre dos valores según una condición. Entonces, si en lugar de una variable ficticia 0-1, por alguna razón quisiera usar, digamos, 4 y 7, podría usar ifelse(year == 1957, 4, 7).

Martin O'Leary
fuente
49

Usando 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
fuente
Quizás agregar "diversión = factor" en la función ficticia puede ayudar si ese es el significado de la variable.
Filippo Mazza
@FilippoMazza Prefiero mantenerlos como números enteros, sí, podríamos establecer el factor si fuera necesario.
zx8754
¿Cómo se elimina df1 antes de cada nombre de encabezado de columna ficticia?
Mike
@mike colnames (df1) <- gsub ("df1_", "", fixed = TRUE, colnames (df1))
zx8754
19

El paquete mlrincluye createDummyFeaturespara este propósito:

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 elimina la variable original.

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

Enrique Pérez Herrero
fuente
1
Enrique, he intentado instalar el paquete, pero parece que no funciona después de hacer la biblioteca (mlr). Aparece el siguiente error: «Error en loadNamespace (j <- i [[1L]], c (lib.loc, .libPaths ()), versionCheck = vI [[j]]): no hay ningún paquete llamado 'ggvis 'Además: Mensaje de advertencia: el paquete' mlr 'se creó con la versión R 3.2.5 Error: la carga del paquete o del espacio de nombres falló para' mlr '»
Un anciano en el mar.
1
primero debe instalar 'ggvis'
Ted Mosby
17

Las otras respuestas aquí ofrecen rutas directas para realizar esta tarea, una que muchos modelos (por ejemplo lm) harán por usted internamente de todos modos. No obstante, aquí hay formas de crear variables ficticias con los paquetes carety populares de Max Kuhn recipes. Aunque son algo más detallados, ambos escalan fácilmente a situaciones más complicadas y encajan perfectamente en sus respectivos marcos.


caret::dummyVars

Con caret, la función relevante es dummyVars, que tiene un predictmétodo para aplicarla en un marco de datos:

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

Con recipes, la función relevante es 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

Según el contexto, extraiga los datos con prepy con bakeo 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
alistaire
fuente
11

Para el caso de uso como se presenta en la pregunta, también puede simplemente multiplicar la condición lógica con 1(o tal vez incluso mejor, con 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)

lo que da:

> 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

Para los casos de uso que se presentan, por ejemplo, en las respuestas de @ zx8754 y @Sotos, todavía hay algunas otras opciones que aún no se han cubierto en mi opinión.

1) Crea tu propia make_dummiesfunció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'))

lo que da:

  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) utilice la función dcast-de o

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

lo que da:

  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

Sin embargo, esto no funcionará cuando haya valores duplicados en la columna para los que se deben crear las variables ficticias. En el caso de que se necesite una función de agregación específica dcasty el resultado de la dcastnecesidad de fusionarse con el original:

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

que da (tenga en cuenta que el resultado está ordenado de acuerdo con la bycolumna):

  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) usa el spread -de(con mutatede)

library(dplyr)
library(tidyr)

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

lo que da:

  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
Jaap
fuente
10

Lo que normalmente hago para trabajar con este tipo de variables ficticias es:

(1) ¿cómo genero una variable ficticia para la observación n. ° 10, es decir, para el año 1957 (valor = 1 en 1957 y cero en caso contrario)

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

(2) ¿cómo genero una variable ficticia que es cero antes de 1957 y toma el valor 1 desde 1957 en adelante hasta 2009?

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

Entonces, puedo introducir este factor como una variable ficticia en mis modelos. Por ejemplo, para ver si existe una tendencia a largo plazo en una variable y :

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

¡Espero que esto ayude!

Ricardo González-Gil
fuente
7

Si desea obtener K variables ficticias, en lugar de K-1, intente:

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

Mejor,

Fernando Hoces De La Guardia
fuente
la tabla resultante no se puede utilizar como data.frame. Si eso es un problema, use as.data.frame.matrix(dummies)para traducirlo en uno
sheß
7

Leí esto en el foro de 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
fuente
5

La ifelsefunción es mejor para una lógica simple como esta.

> 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

Además, si desea que devuelva datos de caracteres, puede hacerlo.

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

Variables categóricas con anidamiento ...

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

Ésta es la opción más sencilla.

Alex Thompson
fuente
4

Otra forma es usar mtabulatedesde el qdapToolspaquete, es decir

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)

lo que da,

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

Convierta sus datos en una tabla de datos y use el conjunto por referencia y filtrado de filas

library(data.table)

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

Ejemplo de juguete de prueba de concepto:

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]
palabras por lo demás
fuente
2

Este forro en la base R

model.matrix( ~ iris$Species - 1)

da

    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
stevec
fuente
1

Yo uso una función de este tipo (para 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 = ", ")))
}

Uso:

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

otra forma de hacerlo es usar

ifelse(year < 1965 , 1, 0)
Sophia J
fuente
0

Hola, escribí esta función general para generar una variable ficticia que esencialmente replica la función de reemplazo en Stata.

Si x es, el marco de datos es x y quiero una variable ficticia llamada aque tomará valor 1cuando x$btome valorc

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
fuente
0

También podemos usar cSplit_efrom splitstackshape. Usando los datos de @ 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

Para hacer que funcione para datos que no sean numéricos necesidad que especificar typecomo "character"explícitamente

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
Ronak Shah
fuente