2010-12-30 9 views
6

He importado datos de un archivo en un marco de datos en R. Es algo como esto.Cómo agregar una columna en un marco de datos en R

Name  Count Category 
A   100  Cat1 
C   10  Cat2 
D   40  Cat1 
E   30  Cat3 
H   3  Cat3 
Z   20  Cat2 
M   50  Cat10 

Así que ahora quiero añadir la columna de la Categoría en función de los valores en la columna Nombre . Entonces algo como si Nombre = (A, D), Categoría = 'Cat1' etc.

Esto es solo un ejemplo simple que estoy dando. Tengo una gran cantidad de nombres y categorías, así que quiero una sintaxis compacta. ¿Cómo puedo hacer esto?

Editar: He cambiado el ejemplo para adaptarlo mejor a mis necesidades, ya que el nombre puede ser cualquier cosa que no sea numérica. Perdón por no haber sido tan claro antes.

Respuesta

2

Puede utilizar un mapa. (Actualizado para utilizar stringsAsFactors = FALSE)

df <- data.frame(Name = c('A', 'C', 'D', 'E', 'H', 'Z', 'M'), 
        Count = c(100,10,40,30,3,20,50), stringsAsFactors = FALSE) 
Categories <- list(Cat1 = c('A','D'), 
        Cat2 = c('C','Z'), 
        Cat3 = c('E','H'), 
        Cat10 = 'M') 
nams <- names(Categories) 
nums <- sapply(Categories, length) 
CatMap <- unlist(Map(rep, nams, nums)) 
names(CatMap) <- unlist(Categories) 

df <- transform(df, Category = CatMap[ Name ]) 
+0

+1 Buen uso de 'Map()'. Esta es la segunda vez en una semana que alguien aquí ha usado 'Map()' en una respuesta y parece muy útil. –

+0

@Gavin gracias. De hecho, esa otra publicación me enseñó sobre Map! –

+0

@pchalasani Gracias, esta es una buena manera de hacer la recodificación. Sin embargo, probé esto y el mapeo está mal de alguna manera cuando lo hice en mis datos reales. El ejemplo que das funciona bien. ¿Alguna posible razón para esto? – sfactor

3

Puede usar ifelse. Si su trama de datos se llama df puede hacer:

df$cat <- ifelse(df$name<100, "Ones", "Hundreds") 
df$cat <- ifelse(df$name<1000, df$cat, "Thousands") 
+0

lo siento, debería haber sido más claro, así que cambié el ejemplo, el nombre puede ser cualquier valor alfabético no numérico. pero gracias intentaré aplicar una lógica como esta y veré. – sfactor

2

[Actualización siguiente comentario de la OP y Q alterada]

DF <- data.frame(Name = c("A","C","D","E","H","Z","M"), 
       Count = c(100,10,40,30,3,20,50), stringsAsFactors = FALSE) 
lookup <- data.frame(Name = c("A","C","D","E","H","Z","M"), 
        Category = paste("Cat", c(1,2,1,3,3,2,10), sep = ""), 
        stringsAsFactors = FALSE) 

El uso de las tramas de datos anteriores, podemos hacer una combinación de base de datos. Necesita configurar lookup para las combinaciones NameCategory que desee, lo cual es correcto si no hay un número muy grande de Name s (Al menos solo tiene que enumerarlos una vez cada uno en lookup y no tiene que hacerlo con el fin - una lista de todos Cat1Name s primero, etc):

> merge(DF, lookup, by = "Name") 
    Name Count Category 
1 A 100  Cat1 
2 C 10  Cat2 
3 D 40  Cat1 
4 E 30  Cat3 
5 H  3  Cat3 
6 M 50 Cat10 
7 Z 20  Cat2 
> merge(DF, lookup, by = "Name", sort = FALSE) 
    Name Count Category 
1 A 100  Cat1 
2 C 10  Cat2 
3 D 40  Cat1 
4 E 30  Cat3 
5 H  3  Cat3 
6 Z 20  Cat2 
7 M 50 Cat10 

Una opción es la indexación:

foo <- function(x) { 
    out <- character(length = length(x)) 
    chars <- c("Ones", "Tens", "Hundreds", "Thousands") 
    out[x < 10] <- chars[1] 
    out[x >= 10 & x < 100] <- chars[2] 
    out[x >= 100 & x < 1000] <- chars[3] 
    out[x >= 1000 & x < 10000] <- chars[4] 
    return(factor(out, levels = chars)) 
} 

Una alternativa que la escala Es mejor decir,

bar <- function(x, cats = c("Ones", "Tens", "Hundreds", "Thousands")) { 
    out <- cats[floor(log10(x)) + 1] 
    factor(out, levels = cats) 
} 
0

la salida:

  • cut()
  • recode() en el car paquete
0

Tal vez más simple y más fácil de leer usando ifelse y% en%:

df <- data.frame(Name = c('A', 'C', 'D', 'E', 'H', 'Z', 'M'), 
Count =c(100,10,40,30,3,20,50), stringsAsFactors = FALSE) 

cat1 = c("A","D") 
cat2 = c("C","Z") 
cat3 = c("E","H") 
cat10 = c("M") 

df$Category = ifelse(df$Name %in% cat1, "Cat1", 
       ifelse(df$Name %in% cat2, "Cat2", 
       ifelse(df$Name %in% cat3, "Cat3", 
       ifelse(df$Name %in% cat10, "Cat10", 
       NA)))) 

    Name Count Category 
1 A 100  Cat1 
2 C 10  Cat2 
3 D 40  Cat1 
4 E 30  Cat3 
5 H  3  Cat3 
6 Z 20  Cat2 
7 M 50 Cat10 
Cuestiones relacionadas