2009-10-27 15 views
64

Tengo un gran marco de datos (14552 filas por 15 columnas) que contiene datos de facturación de 2001 a 2007. He utilizado sqlFetch para obtener datos de 2008. Con el fin de añadir los datos de 2008 a los datos de los 7 años anteriores se podría hacer de la siguiente maneraAdjuntar filas a un marco de datos: el problema del factor

alltime <-rbind(alltime,all2008)

desgracia que genera

mensaje Advertencia: en [<-.factor (*tmp*, ri, el valor = c (na, na, na, na, na, na, na, : nivel de factor válido, AN genera

Mi conjetura es que allí e hay algunos pacientes nuevos cuyos nombres no estaban en el marco de datos anterior y, por lo tanto, no sabrían a qué nivel darlo. Otra columna es para el nombre del médico referente. Un nuevo médico remitente causaría el mismo problema.

La forma en que R importa los datos y automáticamente resuelve lo que es numérico y lo que no (y lo convierte en un factor) es maravilloso, hasta que tenga que manipularlo más y luego se convierta en un dolor. ¿Cómo supero mi problema elegantemente?

+5

Esto es extraño. Los factores no deberían causar esto, en la ayuda para 'rbind' se dice: "Los factores tienen sus niveles expandidos según sea necesario" (R-2.9.2). ¿Tal vez podría verificar exactamente qué columna causa esto? – Marek

+1

¡Qué gran punto Marek! El mensaje de advertencia me asustó. Después de leer tu comentario volví a explorar mis datos. Parece que todos los datos nuevos están allí y se han agregado niveles adicionales. En esta etapa, podría dejarlo como una advertencia que debería ignorarse, que es un hábito peligroso para entrar (ya que uno tiene que tener una base de datos en su cabeza de advertencias para tomarse en serio frente a las advertencias que deben ignorarse). ¿Cómo averiguo de dónde vino el mensaje de advertencia? – Farrel

Respuesta

30

Podría deberse a una falta de coincidencia de tipos en dos data.frames.

En primer lugar compruebe los tipos (clases). Para fines de diagnóstico hacen esto:

new2old <- rbind(alltime, all2008) # this gives you a warning 
old2new <- rbind(all2008, alltime) # this should be without warning 

cbind(
    alltime = sapply(alltime, class), 
    all2008 = sapply(all2008, class), 
    new2old = sapply(new2old, class), 
    old2new = sapply(old2new, class) 
) 

espero que haya una fila se ve así:

  alltime all2008 new2old old2new 
...   ...  ...  ...  ... 
some_column "factor" "numeric" "factor" "character" 
...   ...  ...  ...  ... 

Si es así, la explicación: rbind no comprueban partido de tipos. Si analiza el código rbind.data.frame, puede ver que el primer argumento inicializó los tipos de salida. Si en el primer tipo data.frame es un factor, la columna output data.frame es factor con los niveles unique(c(levels(x1),levels(x2))). Pero cuando en la segunda columna data.frame no es factor, entonces levels(x2) es NULL, por lo que los niveles no se extienden.

¡Significa que sus datos de salida son incorrectos! Hay NA 's en lugar de los verdaderos valores

supongo que:

  1. que se crean datos antiguos con otra versión R/RODBC tan tipos fueron creados con diferentes métodos (diferentes configuraciones - separador decimal tal vez)
  2. hay NULL o algunos datos específicos en la columna problemática, por ej. alguien cambia de columna en la base de datos.

Solución:

encontrar la columna equivocada y encontrar por lo que su mal y de fijo. Elimina la causa, no los síntomas.

+1

Yip. Estás en lo correcto. en un marco de datos la clase de una columna era un factor y en otro era numérica. Eso estropeó las cosas mal. Convertí el número a un factor y todo estaba bien. Gracias por tu guía. Hubo algunas otras discrepancias también. Por ejemplo, la discrepancia entre factores y caracteres no estropeaba las cosas. – Farrel

+0

Tiene razón sobre factor-carácter, en alguna parte del código encontré que los niveles para esta combinación serán 'únicos (c (levels (x1), x2))'. Una cosa: la combinación factor-carácter lleva a un factor, combinación de carácter-factor a carácter. Por lo tanto, es mejor cuando los tipos coinciden. – Marek

26

Una manera "fácil" es simplemente no tener sus cadenas configuradas como factores al importar datos de texto.

Tenga en cuenta que las funciones read.{table,csv,...} toman un parámetro stringsAsFactors, que se establece de manera predeterminada en TRUE. Puede establecer esto en FALSE mientras está importando y rbind -sus datos.

Si desea establecer que la columna sea un factor al final, puede hacerlo también.

Por ejemplo:

alltime <- read.table("alltime.txt", stringsAsFactors=FALSE) 
all2008 <- read.table("all2008.txt", stringsAsFactors=FALSE) 
alltime <- rbind(alltime, all2008) 
# If you want the doctor column to be a factor, make it so: 
alltime$doctor <- as.factor(alltime$doctor) 
+1

Creo que tiene varios errores tipográficos en su respuesta ... – griffin

+1

Woops, gracias por señalarlo. Reparado (creo). –

4

Como se sugiere en la respuesta anterior, lea las columnas como el carácter y hacer la conversión a factores después rbind. SQLFetch (supongo RODBC) también tiene el argumento stringsAsFactors o as.is para controlar la conversión de caracteres. Los valores permitidos son como read.table, por ejemplo, as.is=TRUE o algún número de columna.

3

Tuve el mismo problema con los desajustes de tipos, especialmente con factores. Tuve que unir dos conjuntos de datos compatibles.

Mi solución es convertir factores en ambos dataframes en "carácter". Entonces funciona como un encanto :-)

convert.factors.to.strings.in.dataframe <- function(dataframe) 
    { 
     class.data <- sapply(dataframe, class) 
     factor.vars <- class.data[class.data == "factor"] 
     for (colname in names(factor.vars)) 
     { 
      dataframe[,colname] <- as.character(dataframe[,colname]) 
     } 
     return (dataframe) 
    } 

Si desea ver los tipos en sus dos tramas de datos (nombres de ejecutar el cambio var):

cbind("orig"=sapply(allSurveyData, class), 
      "merge" = sapply(curSurveyDataMerge, class), 
      "eq"=sapply(allSurveyData, class) == sapply(curSurveyDataMerge, class) 
    ) 
+0

función muy útil para tener, gracias. – PatrickT

+3

'mydf [sapply (mydf, is.factor)] <- lapply (mydf [sapply (mydf, is.factor)], as.character)' parece un enfoque más simple. – A5C1D2H2I1M1N2O1R2T1

7

1) crear la trama de datos con el sistema de stringsAsFactor a FALSO. Esto debería resolver el factor-problema

2) después no utilice rbind - confunde los nombres de las columnas si el marco de datos está vacío. simplemente hacerlo de esta manera:

df[nrow(df)+1,] <- c("d","gsgsgd",4) 

/

> df <- data.frame(a = character(0), b=character(0), c=numeric(0)) 

> df[nrow(df)+1,] <- c("d","gsgsgd",4) 

Warnmeldungen: 
1: In `[<-.factor`(`*tmp*`, iseq, value = "d") : 
    invalid factor level, NAs generated 
2: In `[<-.factor`(`*tmp*`, iseq, value = "gsgsgd") : 
    invalid factor level, NAs generated 

> df <- data.frame(a = character(0), b=character(0), c=numeric(0), stringsAsFactors=F) 

> df[nrow(df)+1,] <- c("d","gsgsgd",4) 

> df 
    a  b c 
1 d gsgsgd 4 
0

aquí es una función de tomar los nombres de las filas comunes de 2 tramas de datos y hacer un rbind donde básicamente encontramos los campos que son factores, añadir el nuevos factores luego hacen el rbind. Esto debe hacerse cargo de cualquier problema de factores:

rbindCommonCols < -función (x, y) {

commonColNames = intersect(colnames(x), colnames(y)) 
x = x[,commonColNames] 
y = y[,commonColNames] 

colClassesX = sapply(x, class) 
colClassesY = sapply(y, class) 
classMatch = paste(colClassesX, colClassesY, sep = "-") 
factorColIdx = grep("factor", classMatch) 

for(n in factorColIdx){ 
    x[,n] = as.factor(x[,n]) 
    y[,n] = as.factor(y[,n]) 
} 

for(n in factorColIdx){ 
    x[,n] = factor(x[,n], levels = unique(c(levels(x[,n]), levels(y[,n])))) 
    y[,n] = factor(y[,n], levels = unique(c(levels(y[,n]), levels(x[,n])))) 
} 

res = rbind(x,y) 
res 

}

Cuestiones relacionadas