generar - regresion con variables dummy en r
Generar una variable ficticia (15)
Convierte tus datos a data.table y usa set por referencia y filtro de fila
library(data.table)
dt <- as.data.table(your.dataframe.or.whatever)
dt[, is.1957 := 0]
dt[year == 1957, is.1957 := 1]
Ejemplo de juguete con 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]
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:
¿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)?
¿Cómo puedo generar una variable ficticia que sea cero antes de 1957 y tome el valor 1 desde 1957 en adelante hasta 2009?
El paquete mlr
incluye createDummyFeatures
para 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
suelta la variable original. https://www.rdocumentation.org/packages/mlr/versions/2.9/topics/createDummyFeatures
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 xy quiero una variable ficticia llamada a
que tomará el valor 1
cuando x$b
toma valor 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
}
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 usar ifelse
para elegir entre dos valores según una condición. Entonces, si en lugar de una variable ficticia 0-1, por alguna razón que quisiera usar, por ejemplo, 4 y 7, podría usar ifelse(year == 1957, 4, 7)
.
La función ifelse
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 anidación ...
> 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"
Esta es la opción más directa.
Las otras respuestas aquí ofrecen rutas directas para realizar esta tarea, una que muchos modelos (por ejemplo, lm
) le harán internamente de todos modos. Sin embargo, aquí hay maneras de hacer variables ficticias con los paquetes de caret
y recipes
populares de Max Kuhn. Aunque algo más detallado, ambos escalan fácilmente a situaciones más complicadas, y se ajustan perfectamente en sus respectivos marcos.
caret::dummyVars
Con caret
, la función relevante es dummyVars
, que tiene un método de predict
para aplicarlo 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 la prep
y bake
o 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
Lo leí 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)
}
Lo que normalmente hago para trabajar con este tipo de variables ficticias es:
(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)
data$factor_year_1 <- factor ( with ( data, ifelse ( ( year == 1957 ), 1 , 0 ) ) )
(2) ¿cómo puedo generar una variable ficticia que sea cero antes de 1957 y tome el valor 1 desde 1957 en adelante hasta 2009?
data$factor_year_2 <- factor ( with ( data, ifelse ( ( year < 1957 ), 0 , 1 ) ) )
Entonces, puedo presentar este factor como una variable ficticia en mis modelos. Por ejemplo, para ver si hay una tendencia a largo plazo en una variable y
:
summary ( lm ( y ~ t, data = data ) )
¡Espero que esto ayude!
Otra forma en que puede hacerlo es usar
ifelse(year < 1965 , 1, 0)
Otra forma es usar mtabulate
del paquete qdapTools
, 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
Para el caso de uso presentado en la pregunta, también puede simplemente multiplicar la condición lógica por 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 presentados en, por ejemplo, las respuestas de @ zx8754 y @Sotos, todavía hay algunas otras opciones que aún no se han cubierto.
1) Haz tu propia make_dummies
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''))
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) use la dcast
dcast desde data.table o reshape2
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 cuales se deben crear los dummies. En el caso de que se necesite una función de agregación específica para dcast
el resultado de dcast
debe combinarse 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 es orden según la columna 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) usa la función de tidyr de tidyr (con dplyr de dplyr )
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
Si desea obtener K variables ficticias, en lugar de K-1, intente:
dummies = table(1:length(year),as.factor(year))
Mejor,
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
Yo uso tal función (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")
Otra opción que puede funcionar mejor si tiene muchas variables es factor
y model.matrix
.
> year.f = factor(year)
> dummies = model.matrix(~year.f)
Esto incluirá una columna de intercepción (todas) y una columna para cada uno de los años en su conjunto de datos excepto uno, que será el valor "predeterminado" o de intercepción.
Puede cambiar cómo se elige el "predeterminado" jugando con contrasts.arg
en model.matrix
.
Además, si desea omitir la intercepción, puede simplemente colocar la primera columna o agregar +0
al final de la fórmula.
Espero que esto sea útil.