2012-09-17 31 views
5

Tengo un gran marco de datos de 1000 x 100000 como el siguiente para recodificar los valores numéricos.datos de recodificación en r

myd <- data.frame (v1 = sample (c("AA", "AB", "BB", NA), 10, replace = T), 
        v2 = sample (c("CC", "CG", "GG", NA), 10, replace = T), 
        v3 = sample (c("AA", "AT", "TT", NA) , 10, replace = T), 
        v4 = sample (c("AA", "AT", "TT", NA) , 10, replace = T), 
        v5 = sample (c("CC", "CA", "AA", NA) , 10, replace = T) 
        ) 
myd 
    v1 v2 v3 v4 v5 
1 AB CC <NA> <NA> AA 
2 AB CG TT TT AA 
3 AA GG AT AT CA 
4 <NA> <NA> <NA> AT <NA> 
5 AA <NA> AA <NA> CA 
6 BB <NA> TT TT CC 
7 AA GG AA AT CA 
8 <NA> GG <NA> AT CA 
9 AA <NA> AT <NA> CC 
10 AA GG TT AA CC 

Cada variable tiene potencialmente cuatro valores únicos.

unique(myd$v1) 

[1] AB AA <NA> BB 
Levels: AA AB BB 

unique(myd$v2) 

[1] CC CG GG <NA> 
    Levels: CC CG GG 

Tales valores únicos pueden ser cualquier combinación, sin embargo, consta de dos alfabetos (excepto NA). Por ejemplo, "A", "B" en el primer caso harán la combinación "AA", "AB", "BB". El código numérico para estos sería 1, 0, -1 respectivamente. De manera similar para el segundo caso, los alfabetos "C", "G" hacen "CC", "CG", "GG", por lo tanto los códigos numéricos serían 1, 0, -1 respectivamente. Así, la anterior necesidad myd a recodificar con:

myd 
     v1 v2 v3 v4  v5 
    1 0 1  <NA> <NA> 1 
    2 0 0  -1 -1  1 
    3 1 -1  0 0  0 
    4 <NA> <NA> <NA> 0  <NA> 
    5 1 <NA> 1 < NA>  0 
    6 -1 <NA> -1 -1  -1 
    7 1 -1 1  0  0 
    8 <NA> -1 <NA> 0  0 
    9 1 <NA> 0 <NA>  -1 
    10 1 -1 -1  1  -1 

Respuesta

7

Usted puede tomar ventaja del hecho de que sus datos son factores, que tienen índices numéricos por debajo de ellos.

Por ejemplo:

> as.numeric(myd$v1) 
[1] 2 2 1 NA 1 3 1 NA 1 1 

Los valores numéricos corresponden a la levels() del factor:

> levels(myd$v1) 
[1] "AA" "AB" "BB" 

Así 1 == AA, 2 == AB, 3 == BB ... y así.

Así que simplemente puede convertir sus datos a numéricos, y aplicar las matemáticas necesarias para obtener sus datos a escala como usted lo desee. Así podemos restar por 2, y luego multiplicar por -1 para obtener los resultados:

(sapply(myd, as.numeric) - 2) * -1 
#----- 
     v1 v2 v3 v4 v5 
[1,] 0 1 NA NA 1 
[2,] 0 0 -1 -1 1 
[3,] 1 -1 0 0 0 
[4,] NA NA NA 0 NA 
[5,] 1 NA 1 NA 0 
[6,] -1 NA -1 -1 -1 
[7,] 1 -1 1 0 0 
[8,] NA -1 NA 0 0 
[9,] 1 NA 0 NA -1 
[10,] 1 -1 -1 1 -1 
+1

Si desea un 'data.frame' return ed use 'do.call (data.frame, lapply (myd, function (.x) {- (as.numeric (.x) -2)}))' o 'as.data.frame (lapply (myd, function) (.x) {- (as.numeric (.x) -2)})) ' – mnel

8

Voy a publicar una solución diferente - (pase a data.table para el enfoque súper rápido!)

Si desea para recodificar AA, AB, BB, 1,0,-1, etc. puede usar la indexación (junto con el factor a la solución numérica). ¡Esto te permitirá tener una recodificación diferente si lo deseas!

hecho a sí mismo la función de recodificación

simple_recode <- function(.x, new_codes){ 
    new_codes[as.numeric(.x)] 
} 

as.data.frame(lapply(myd, simple_recode, new_codes = 1:-1)) 

uso factor

Simplemente puede etiquetar de nuevo las cartas llamando factor con los nuevos niveles como labels

as.data.frame(lapply(myd, factor, labels = 1:-1)) 

data.table para la eficiencia

Si sus datos son grandes, entonces sugiero un enfoque data.table que será eficiente en cuanto a tiempo y memoria.

library(data.table) 
DT <- as.data.table(myd) 
as.data.table(DT[,lapply(.SD, simple_recode, new_codes = 1:-1))]) 

O, de manera más eficiente

as.data.table(DT[, lapply(.SD, setattr, 'levels', 1:-1)]) 

O aún más eficiente (modificación de los niveles en el lugar, y evitando la as.data.llamada de la tabla)

for(name in names(DT)){ 
    setattr(DT[[name]],'levels',1:-1) 
    } 

setattr modifica por referencia por lo que no la copia.

enfoque prácticamente instantánea utilizando data.table y setattr

Como se ha demostrado en este gran conjunto de datos

# some big data (100 columns, 1e6 rows) 
big <- replicate(100, factor(sample(c('AA','AB','BB', NA), 1e6, T)), simplify = F) 
bigDT <- as.data.table(big) 

system.time({ 
    for(name in names(big)){ 
    setattr(big[[name]],'levels',1:-1) 
    } 
    })) 

## user system elapsed 
## 0  0  0 
+0

Cosas buenas. Sospecho que la estrategia de data.table sería rapidísima. –

+0

Estoy seguro de que habrá un enfoque 'data.table' aún más eficiente usando' setattr', si eso pudiera llegar a 'inside' the' data.table'. – mnel

+0

'setattr' puede alcanzar dentro! - data.table es increíble. – mnel

4

Si configura una asignación por lo que el LHS tiene la estructura adecuada, se puede utilizar el implícitamente coaccionó los valores de los factores como índices en los valores que desea:

> myd[] <- c(-1,0,1)[data.matrix(myd)] 
> myd 
    v1 v2 v3 v4 v5 
1 NA 0 0 0 1 
2 -1 1 0 0 -1 
3 0 NA 1 0 0 
4 NA -1 -1 0 -1 
5 -1 0 1 -1 NA 
6 0 NA 0 1 NA 
7 NA 0 1 NA -1 
8 0 0 0 -1 1 
9 -1 NA 1 -1 NA 
10 0 1 1 NA NA