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:
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)?
Comment générer une variable muette qui est zéro avant 1957 et prend la valeur 1 de 1957 à 2009?
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.
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)
.
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
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
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
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!
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
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)
}
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.
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
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")
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]
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
}
une autre façon de le faire est d'utiliser
ifelse(year < 1965 , 1, 0)