Genera una variabile fittizia


87

Ho problemi a generare le seguenti variabili fittizie in R:

Sto analizzando i dati delle serie temporali annuali (periodo 1948-2009). Ho due domande:

  1. Come posso generare una variabile fittizia per l'osservazione n. 10, cioè per l'anno 1957 (valore = 1 al 1957 e zero altrimenti)?

  2. Come posso generare una variabile fittizia che è zero prima del 1957 e assume il valore 1 dal 1957 in poi fino al 2009?

Risposte:


113

Un'altra opzione che può funzionare meglio se hai molte variabili è factore model.matrix.

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

Ciò includerà una colonna di intercettazione (tutte) e una colonna per ciascuno degli anni nel set di dati tranne uno, che sarà il valore "predefinito" o di intercettazione.

È possibile modificare la modalità di "default" è scelto da scherzi con contrasts.argin model.matrix.

Inoltre, se vuoi omettere l'intercetta, puoi semplicemente eliminare la prima colonna o aggiungerla +0alla fine della formula.

Spero che questo sia utile.


4
cosa succede se si desidera generare variabili fittizie per tutti (invece di k-1) senza intercettazione?
Fernando Hoces De La Guardia

1
nota che model.matrix () accetta più variabili da trasformare in dummies: model.matrix (~ var1 + var2, data = df) Ancora una volta, assicurati che siano fattori.
slizb

3
@ Tabella sinergica (1: n, fattore). Dove factor è la variabile originale en è la sua lunghezza
Fernando Hoces De La Guardia

1
@Synergist quella tabella è una matrice anxk con tutte le variabili indicatore k (invece di k-1)
Fernando Hoces De La Guardia

6
@FernandoHocesDeLaGuardia Puoi rimuovere l'intercetta da una formula con + 0 o - 1. Quindi model.matrix(~ year.f + 0)fornirà variabili fittizie senza un livello di riferimento.
Gregor Thomas

60

Il modo più semplice per produrre queste variabili fittizie è simile al seguente:

> 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

Più in generale, puoi ifelsescegliere tra due valori a seconda di una condizione. Quindi, se invece di una variabile fittizia 0-1, per qualche motivo volessi usare, diciamo, 4 e 7, potresti usare ifelse(year == 1957, 4, 7).


49

Utilizzo di 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

Forse l'aggiunta di "fun = factor" nella funzione dummy può aiutare se questo è il significato della variabile.
Filippo Mazza

@FilippoMazza preferisco mantenerli interi, sì, potremmo impostare il fattore se necessario.
zx8754

come si rimuove df1 prima di ogni nome di intestazione di colonna fittizia?
mike

1
@mike colnames (df1) <- gsub ("df1_", "", fixed = TRUE, colnames (df1))
zx8754

19

Il pacchetto mlrinclude createDummyFeaturesa questo scopo:

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 rilascia la variabile originale.

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


1
Enrique, ho provato a installare il pacchetto, ma sembra che non funzioni dopo aver eseguito la libreria (mlr). Ottengo il seguente errore: «Errore in loadNamespace (j <- i [[1L]], c (lib.loc, .libPaths ()), versionCheck = vI [[j]]): non esiste un pacchetto chiamato 'ggvis 'Inoltre: messaggio di avviso: il pacchetto' mlr 'è stato creato con la versione R 3.2.5 Errore: caricamento del pacchetto o dello spazio dei nomi non riuscito per' mlr '»
Un vecchio nel mare.

1
devi prima installare "ggvis"
Ted Mosby

17

Le altre risposte qui offrono percorsi diretti per svolgere questo compito, uno che molti modelli (ad esempio lm) faranno comunque per te internamente. Tuttavia, qui ci sono modi per creare variabili fittizie con i pacchetti popolari carete di Max Kuhn recipes. Sebbene un po 'più prolissi, entrambi si adattano facilmente a situazioni più complicate e si adattano perfettamente alle rispettive strutture.


caret::dummyVars

Con caret, la funzione rilevante è dummyVars, che ha un predictmetodo per applicarlo su un frame di dati:

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 funzione rilevante è 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

A seconda del contesto, estrai i dati con prepe 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

11

Per il caso d'uso presentato nella domanda, puoi anche semplicemente moltiplicare la condizione logica con 1(o forse anche meglio, 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)

che dà:

> 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

Per i casi d'uso presentati, ad esempio, nelle risposte di @ zx8754 e @Sotos, ci sono ancora alcune altre opzioni che non sono state ancora coperte.

1) Crea il tuo make_dummies-funzione

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

che dà:

  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) usa la funzione- dcastda entrambi o

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

che dà:

  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

Tuttavia, ciò non funzionerà quando nella colonna sono presenti valori duplicati per i quali è necessario creare i manichini. Nel caso in cui sia necessaria una funzione di aggregazione specifica dcaste il risultato della dcastnecessità deve essere ricongiunto all'originale:

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

che dà (nota che il risultato è ordinato in base alla bycolonna):

  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) utilizzare la funzione spread-da(con mutateda)

library(dplyr)
library(tidyr)

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

che dà:

  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

Quello che faccio normalmente per lavorare con questo tipo di variabili fittizie è:

(1) come posso generare una variabile fittizia per l'osservazione n. 10, cioè per l'anno 1957 (valore = 1 al 1957 e zero altrimenti)

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

(2) come faccio a generare una variabile fittizia che è zero prima del 1957 e assume il valore 1 dal 1957 in poi fino al 2009?

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

Quindi, posso introdurre questo fattore come variabile fittizia nei miei modelli. Ad esempio, per vedere se esiste una tendenza a lungo termine in una variabile y :

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

Spero che sia di aiuto!


7

Se vuoi ottenere K variabili fittizie, invece di K-1, prova:

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

Migliore,


la tabella risultante non può essere utilizzata come data.frame. Se questo è un problema, as.data.frame.matrix(dummies)tradurlo in uno solo
sheß

7

Ho letto questo sul forum di 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

La ifelsefunzione è la migliore per una logica semplice come questa.

> 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

Inoltre, se vuoi che restituisca i dati dei personaggi, puoi farlo.

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

Variabili categoriali con annidamento ...

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

Questa è l'opzione più semplice.


5

Un altro modo è usare mtabulatefrom qdapToolspackage, ie

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)

che dà,

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

3

Questa fodera in base 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

2

Converti i tuoi dati in un data.table e usa set per riferimento e filtro di riga

library(data.table)

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

Esempio di giocattolo proof-of-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

Uso una tale funzione (per 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 = ", ")))
}

Utilizzo:

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

1

un altro modo per farlo è usare

ifelse(year < 1965 , 1, 0)

0

Ciao, ho scritto questa funzione generale per generare una variabile fittizia che replica essenzialmente la funzione di sostituzione in Stata.

Se x è il data frame è x e voglio una variabile fittizia chiamata ache avrà valore 1quando x$bassume valorec

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

Possiamo anche usare cSplit_eda splitstackshape. Utilizzo dei dati di @ 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

Per farlo funzionare per dati diversi da quelli numerici dobbiamo specificarli typein modo "character"esplicito

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.