web-dev-qa-db-fra.com

Générer une variable factice

J'ai du mal à générer les variables nominales suivantes dans R: 

J'analyse des données de séries chronologiques annuelles (période 1948-2009). J'ai deux questions:

  1. Comment générer une variable muette pour l'observation n ° 10, c'est-à-dire pour l'année 1957 (valeur = 1 à 1957 et zéro sinon)?

  2. Comment générer une variable muette qui est zéro avant 1957 et prend la valeur 1 de 1957 à 2009?

61
Pantera

Une autre option qui peut fonctionner mieux si vous avez plusieurs variables est factor et model.matrix.

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

Cela inclura une colonne d'interception (toutes des unités) et une colonne pour chacune des années de votre ensemble de données, sauf une, qui sera la valeur par défaut ou la valeur d'interception.

Vous pouvez changer la façon dont la "valeur par défaut" est choisie en jouant avec contrasts.arg dans model.matrix.

En outre, si vous souhaitez omettre l'interception, vous pouvez simplement supprimer la première colonne ou ajouter +0 à la fin de la formule.

J'espère que c'est utile.

91
David J. Harris

Le moyen le plus simple de produire ces variables nominales est le suivant:

> 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

Plus généralement, vous pouvez utiliser ifelse pour choisir entre deux valeurs en fonction d'une condition. Ainsi, si au lieu d’une variable muette 0-1, pour une raison quelconque, vous souhaitiez utiliser, par exemple 4 et 7, vous pouvez utiliser ifelse(year == 1957, 4, 7).

47
Martin O'Leary

Utilisation de 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
34
zx8754

Le package mlr comprend createDummyFeatures à cette fin:

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 supprime la variable d'origine . https://www.rdocumentation.org/packages/mlr/versions/2.9/topics/createDummyFeatures

16

Les autres réponses proposées ici proposent des itinéraires directs pour accomplir cette tâche, que plusieurs modèles (par exemple, lm) feront pour vous en interne de toute façon. Néanmoins, il existe des moyens de créer des variables factices avec les packages populaires caret et recipes de Max Kuhn. Bien qu’ils soient un peu plus verbeux, ils s’adaptent facilement à des situations plus complexes et s’intègrent parfaitement dans leurs cadres respectifs.


caret::dummyVars

Avec caret, la fonction pertinente est dummyVars, qui dispose d'une méthode predict pour l'appliquer à un bloc de données:

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

Avec recipes, la fonction pertinente est 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

Selon le contexte, extrayez les données avec prep et soit bake ou 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
alistaire

Ce que je fais normalement pour travailler avec ce type de variables nominales est:

(1) comment générer une variable muette pour l'observation n ° 10, c'est-à-dire pour l'année 1957 (valeur = 1 pour 1957 et zéro sinon)

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

(2) Comment générer une variable muette nulle avant 1957 et prenant la valeur 1 de 1957 à 2009?

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

Ensuite, je peux introduire ce facteur en tant que variable muette dans mes modèles. Par exemple, pour voir s’il existe une tendance à long terme dans une variable y:

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

J'espère que cela t'aides!

9

Pour le cas d'utilisation présenté dans la question, vous pouvez simplement multiplier la condition logique avec 1 (ou peut-être même mieux avec 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)

qui donne:

> 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

Pour les cas d'utilisation tels que présentés dans, par exemple, les réponses de @ zx8754 et @Sotos, il existe encore d'autres options qui n'ont pas encore été couvertes.

1) Créez votre propre make_dummies- fonction

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

qui donne:

  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) utilise la fonction dcast- de data.table ou reshape2

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

qui donne:

  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

Toutefois, cela ne fonctionnera pas s'il existe des valeurs en double dans la colonne pour lesquelles les variables nominales doivent être créées. Dans le cas où une fonction d'agrégation spécifique est requise pour dcast et que le résultat de dcast doit être fusionné avec l'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)

ce qui donne (notez que le résultat est ordonné selon la colonne 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) utilise la fonction spread- de tidyr (avec mutate de dplyr )

library(dplyr)
library(tidyr)

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

qui donne:

  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
8
Jaap

Je lis ceci sur le forum 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)
}
7
skpro19

Si vous voulez obtenir des variables factices K, au lieu de K-1, essayez: 

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

Meilleur, 

La fonction ifelse est idéale pour une logique simple comme celle-ci.

> 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

En outre, si vous souhaitez qu'il renvoie des données de caractères, vous pouvez le faire.

> 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 catégoriques avec imbrication ...

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

C'est l'option la plus simple.

4
Alex Thompson

Une autre méthode consiste à utiliser mtabulate à partir du package qdapTools, c.-à-d.

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)

qui donne,

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

J'utilise une telle fonction (pour 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 = ", ")))
}

Usage:

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

Convertissez vos données en data.table et utilisez set by reference and filtering

library(data.table)

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

Exemple de jouet preuve de concept:

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]
1
wordsforthewise

Bonjour, j’ai écrit cette fonction générale pour générer une variable factice qui reproduit essentiellement la fonction de remplacement dans Stata.

Si x est le cadre de données est x et que je veux une variable factice appelée a qui prendra la valeur 1 lorsque x$b prendra la valeur 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
kangkan Dc

une autre façon de le faire est d'utiliser 

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