2011-01-31 23 views
9

Tengo 2 columnas de datos con el mismo tipo de datos (Cadenas).Unir niveles de factor de dos columnas en R

Quiero unirme a los niveles de las columnas. es decir. tenemos:

col1 col2 
Bob John 
Tom Bob 
Frank Jane 
Jim Bob 
Tom Bob 
... ... (and so on) 

ahora col1 tiene 4 niveles (Bob, Tom Frank, Jim) y col2 tiene 3 niveles (John, Jane, Bob)

Pero quiero ambas columnas tienen todos los niveles de los factores (Bob, Tom, Frank, Jim, Jane, John), como para reemplazar más adelante cada uno de los 'nombres' con un identificador único, de tal manera que el resultado final sería:

col1 col2 
1  5 
2  1 
3  6 
4  1 
2  1 

que es Bob -> 1 , Tom -> 2, etc. en ambas columnas.

Alguna idea :)?

editar: ¡Gracias a todos por las maravillosas respuestas! Todos ustedes son impresionantes por lo que yo sé :)

Respuesta

6

desea que el factores que incluyen todos los nombres únicos de ambas columnas.

col1 <- factor(c("Bob", "Tom", "Frank", "Jim", "Tom")) 
col2 <- factor(c("John", "Bob", "Jane", "Bob", "Bob")) 
mynames <- unique(c(levels(col1), levels(col2))) 
fcol1 <- factor(col1, levels = mynames) 
fcol2 <- factor(col2, levels = mynames) 

EDIT: un poco más agradable si se reemplaza la tercera línea con esto:

mynames <- union(levels(col1), levels(col2)) 
2

podría haber jurado que este no funcionaba cuando estaba escribiendo la abominación de abajo, pero lo hace ahora:

## self contained example: 
txt <- "col1 col2 
Bob John 
Tom Bob 
Frank Jane 
Jim Bob 
Tom Bob" 
dat <- read.table(textConnection(txt), header = TRUE) 

sólo calcula conjunto único de los niveles y coaccionar a cada colX a un factor:

> dat3 <- dat 
> lev <- as.character(unique(unlist(sapply(dat, levels)))) 
> dat3 <- within(dat3, col1 <- factor(col1, levels = lev)) 
> dat3 <- within(dat3, col2 <- factor(col2, levels = lev)) 
> str(dat3) 
'data.frame': 5 obs. of 2 variables: 
$ col1: Factor w/ 6 levels "Bob","Tom","Frank",..: 1 2 3 4 2 
$ col2: Factor w/ 6 levels "Bob","Tom","Frank",..: 5 1 6 1 1 
> data.matrix(dat3) 
    col1 col2 
[1,] 1 5 
[2,] 2 1 
[3,] 3 6 
[4,] 4 1 
[5,] 2 1 

[original: para mostrar cómo estúpidamente complejo y ofuscado se puede escribir código R es uno trata muy duro] No estoy seguro es particularmente estrecha sala hormiga (y no lo es), pero ...

En primer lugar, no listados los datos:

tmp <- unlist(dat) 

después calcular los niveles únicos

lev <- as.character(unique(tmp)) 

y luego reestructurar tmp (desde arriba) volver a las mismas dimensiones que los datos originales, convertir a data.frame (preservar las cadenas), aplicar sobre este marco de datos, crear un factor con los niveles lev calculado anteriormente, y finalmente forzar a un marco de datos.

dat2 <- data.frame(lapply(data.frame(matrix(tmp, ncol = ncol(dat)), 
            stringsAsFactors = FALSE), 
          FUN = factor, levels = lev)) 

que da:

> dat2 
    X1 X2 
1 Bob John 
2 Tom Bob 
3 Frank Jane 
4 Jim Bob 
5 Tom Bob 
> sapply(dat2, levels) 
    X1  X2  
[1,] "Bob" "Bob" 
[2,] "Tom" "Tom" 
[3,] "Frank" "Frank" 
[4,] "Jim" "Jim" 
[5,] "John" "John" 
[6,] "Jane" "Jane" 
> data.matrix(dat2) 
    X1 X2 
[1,] 1 5 
[2,] 2 1 
[3,] 3 6 
[4,] 4 1 
[5,] 2 1 
11
x <- structure(list(col1 = structure(c(1L, 4L, 2L, 3L, 4L), .Label = c("Bob", "Frank", "Jim", "Tom"), class = "factor"), col2 = structure(c(3L, 1L, 2L, 1L, 1L), .Label = c("Bob", "Jane", "John"), class = "factor")), .Names = c("col1", "col2"), class = "data.frame", row.names = c(NA, -5L)) 

Hacer una simple unión de los nombres de los factores:

both <- union(levels(x$col1), levels(x$col2)) 

Y Vuelva a nivelar los dos factores:

x$col1 <- factor(x$col1, levels=both) 
x$col2 <- factor(x$col2, levels=both) 

Después de la edición: ejemplo suplementarias para los valores numéricos de los factores

Simplemente podría transformar los niveles de los factores a los valores numéricos, por ejemplo,:

as.numeric(x$col1) 

O una simple solución más, más agradable basado en la insinuación de @Gavin Simpson a continuación en un solo paso:

data.matrix(x) 
+1

aseado, limpio y rápido. Muy buena. En mi humilde opinión mejor que contestar que @Gavin publicó, aunque preferiría 'data.frame (lapply (...' solución, por pura pereza. – aL3xa

+1

+1), me ganaste con una respuesta sensata. ¿Puedes modificar tu 'como.numérico? (x $ col1) 'a simplemente' data.matrix (x) '? De ser así, eliminaré mi respuesta superflua. –

+1

@ aL3xa - hey, no es justo, ¡debo obtener puntos por el número de caracteres escritos !? - -) –

Cuestiones relacionadas