une - r transformer variable numérique en facteur



Étendre automatiquement un facteur R dans une collection de variables indicatrices 1/0 pour chaque niveau de facteur (6)

J'ai juste rencontré ce vieux fil et pensé que j'ajouterais une fonction qui utilise ade4 pour prendre une base de données composée de facteurs et / ou de données numériques et renvoie une trame de données avec des facteurs comme des codes fictifs.

dummy <- function(df) {  

    NUM <- function(dataframe)dataframe[,sapply(dataframe,is.numeric)]
    FAC <- function(dataframe)dataframe[,sapply(dataframe,is.factor)]

    require(ade4)
    if (is.null(ncol(NUM(df)))) {
        DF <- data.frame(NUM(df), acm.disjonctif(FAC(df)))
        names(DF)[1] <- colnames(df)[which(sapply(df, is.numeric))]
    } else {
        DF <- data.frame(NUM(df), acm.disjonctif(FAC(df)))
    }
    return(DF)
} 

Essayons.

df <-data.frame(eggs = c("foo", "foo", "bar", "bar"), 
            ham = c("red","blue","green","red"), x=rnorm(4))     
dummy(df)

df2 <-data.frame(eggs = c("foo", "foo", "bar", "bar"), 
            ham = c("red","blue","green","red"))  
dummy(df2)

https://src-bin.com

J'ai une trame de données R contenant un facteur que je veux "développer" de sorte que pour chaque niveau de facteur, il y a une colonne associée dans une nouvelle trame de données, qui contient un indicateur 1/0. Par exemple, supposons que j'ai:

df.original <-data.frame(eggs = c("foo", "foo", "bar", "bar"), ham = c(1,2,3,4))

Je veux:

df.desired  <- data.frame(foo = c(1,1,0,0), bar=c(0,0,1,1), ham=c(1,2,3,4))

Parce que pour certaines analyses pour lesquelles vous avez besoin d'une trame de données entièrement numérique (p. Ex. Analyse en composantes principales), j'ai pensé que cette fonction pourrait être intégrée. Écrire une fonction pour cela ne devrait pas être trop difficile, mais je peux prévoir défis liés aux noms de colonnes et si quelque chose existe déjà, je préfère l'utiliser.


Answer #1

J'avais besoin d'une fonction pour "exploser" les facteurs qui soit un peu plus flexible, et en ai fait une basée sur la fonction acm.disjonctif du paquet ade4. Cela vous permet de choisir les valeurs éclatées, qui sont 0 et 1 dans acm.disjonctif. Cela ne fait qu'exploser les facteurs qui ont «peu» de niveaux. Les colonnes numériques sont conservées.

# Function to explode factors that are considered to be categorical,
# i.e., they do not have too many levels.
# - data: The data.frame in which categorical variables will be exploded.
# - values: The exploded values for the value being unequal and equal to a level.
# - max_factor_level_fraction: Maximum number of levels as a fraction of column length. Set to 1 to explode all factors.
# Inspired by the acm.disjonctif function in the ade4 package.
explode_factors <- function(data, values = c(-0.8, 0.8), max_factor_level_fraction = 0.2) {
  exploders <- colnames(data)[sapply(data, function(col){
      is.factor(col) && nlevels(col) <= max_factor_level_fraction * length(col)
    })]
  if (length(exploders) > 0) {
    exploded <- lapply(exploders, function(exp){
        col <- data[, exp]
        n <- length(col)
        dummies <- matrix(values[1], n, length(levels(col)))
        dummies[(1:n) + n * (unclass(col) - 1)] <- values[2]
        colnames(dummies) <- paste(exp, levels(col), sep = '_')
        dummies
      })
    # Only keep numeric data.
    data <- data[sapply(data, is.numeric)]
    # Add exploded values.
    data <- cbind(data, exploded)
  }
  return(data)
}

Answer #2

Si votre trame de données est composée uniquement de facteurs (ou si vous travaillez sur un sous-ensemble de variables qui sont tous des facteurs), vous pouvez également utiliser la fonction acm.disjonctif du paquet ade4 :

R> library(ade4)
R> df <-data.frame(eggs = c("foo", "foo", "bar", "bar"), ham = c("red","blue","green","red"))
R> acm.disjonctif(df)
  eggs.bar eggs.foo ham.blue ham.green ham.red
1        0        1        0         0       1
2        0        1        1         0       0
3        1        0        0         1       0
4        1        0        0         0       1

Pas exactement le cas que vous décrivez, mais ça peut aussi être utile ...


Answer #3

Un moyen rapide d'utiliser le paquet reshape2 :

require(reshape2)

> dcast(df.original, ham ~ eggs, length)

Using ham as value column: use value_var to override.
  ham bar foo
1   1   0   1
2   2   0   1
3   3   1   0
4   4   1   0

Notez que cela produit précisément les noms de colonne que vous voulez.


Answer #4

Utilisez la fonction model.matrix :

model.matrix( ~ Species - 1, data=iris )

Answer #5

Voici une façon plus claire de le faire. J'utilise model.matrix pour créer les variables booléennes factices, puis les fusionner dans la structure de données d'origine.

df.original <-data.frame(eggs = c("foo", "foo", "bar", "bar"), ham = c(1,2,3,4))
df.original
#   eggs ham
# 1  foo   1
# 2  foo   2
# 3  bar   3
# 4  bar   4

# Create the dummy boolean variables using the model.matrix() function.
> mm <- model.matrix(~eggs-1, df.original)
> mm
#   eggsbar eggsfoo
# 1       0       1
# 2       0       1
# 3       1       0
# 4       1       0
# attr(,"assign")
# [1] 1 1
# attr(,"contrasts")
# attr(,"contrasts")$eggs
# [1] "contr.treatment"

# Remove the "eggs" prefix from the column names as the OP desired.
colnames(mm) <- gsub("eggs","",colnames(mm))
mm
#   bar foo
# 1   0   1
# 2   0   1
# 3   1   0
# 4   1   0
# attr(,"assign")
# [1] 1 1
# attr(,"contrasts")
# attr(,"contrasts")$eggs
# [1] "contr.treatment"

# Combine the matrix back with the original dataframe.
result <- cbind(df.original, mm)
result
#   eggs ham bar foo
# 1  foo   1   0   1
# 2  foo   2   0   1
# 3  bar   3   1   0
# 4  bar   4   1   0

# At this point, you can select out the columns that you want.




r