Los niveles de factores no vistos al agregar nuevos registros con valores de cadena no vistos a un marco de datos, provocan advertencia y resultan en NA

StackOverflow https://stackoverflow.com/questions/1632772

  •  06-07-2019
  •  | 
  •  

Pregunta

Tengo un marco de datos (14.5K filas por 15 columnas) que contiene datos de facturación de 2001 a 2007.

Añado nuevos datos de 2008 con: alltime <- rbind(alltime,all2008)

Desafortunadamente eso genera una advertencia:

> Warning message:
In `[<-.factor`(`*tmp*`, ri, value = c(NA, NA, NA, NA, NA, NA, NA,  :
  invalid factor level, NAs generated

Supongo que hay algunos pacientes nuevos cuyos nombres no estaban en el marco de datos anterior y, por lo tanto, no sabrían qué nivel darles. Del mismo modo, nuevos nombres no vistos en la columna 'médico de referencia'.

¿Cuál es la solución?

¿Fue útil?

Solución

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

Primero de todos los tipos de verificación (clases). Para fines de diagnóstico, haga 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 como esta:

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

Si es así, entonces explicación: rbind no verifica que los tipos coincidan. Si analiza el código rbind.data.frame, entonces podría ver que el primer argumento inicializa los tipos de salida. Si en el primer tipo data.frame es un factor, la columna data.frame de salida es un factor con 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 en lugar de valores verdaderos

Supongo que:

  1. crea sus datos antiguos con otra versión R / RODBC, por lo que los tipos se crearon con diferentes métodos (diferentes configuraciones, quizás separador decimal)
  2. hay NULL o algunos datos específicos en la columna problemática, por ejemplo. alguien cambia la columna en la base de datos.

Solución:

encuentra la columna incorrecta y encuentra la razón por la cual está mal y arreglado. Eliminar causa no síntomas.

Otros consejos

Un " fácil " La forma es simplemente no tener sus cadenas establecidas como factores al importar datos de texto.

Tenga en cuenta que las funciones read.{table,csv,...} toman un parámetro stringsAsFactors, que por defecto está configurado en TRUE. Puede establecer esto en FALSE mientras está importando y rbind - ingresando sus datos.

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

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) cree el marco de datos con stringsAsFactor establecido en FALSE. Esto debería resolver el problema del factor

2) luego no use rbind: desordena los nombres de columna si el marco de datos está vacío. simplemente hazlo 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

Como se sugirió en la respuesta anterior, lea las columnas como caracteres y realice la conversión a factores después de rbind. SQLFetch (supongo que 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.

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

Mi solución es convertir factores en ambos marcos de datos a " 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 la ejecución de sus dos marcos de datos (cambie los nombres de var):

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

Cuando crea el marco de datos, tiene la opción de hacer sus factores de columnas de cadena (stringsAsFactors=T), o mantenerlos como cadenas.

Para su caso, no haga los factores de sus columnas de cadena. Guárdelos como cadenas, luego agregarlos funciona bien. Si necesita que sean factores, haga toda la inserción y agregue primero como cadena, luego finalmente conviértalos en factor.

Si hace que los factores de las columnas de cadena y luego agregue filas que contienen valores invisibles, obtiene el error que mencionó en cada nuevo nivel de factor invisible y ese valor se reemplaza con NA ...

> df <- data.frame(patient=c('Ann','Bob','Carol'), referring_doctor=c('X','Y','X'), stringsAsFactors=T)

  patient referring_doctor
1     Ann                X
2     Bob                Y
3   Carol                X

> df <- rbind(df, c('Denise','Z'))
Warning messages:
1: In `[<-.factor`(`*tmp*`, ri, value = "Denise") :
  invalid factor level, NA generated
2: In `[<-.factor`(`*tmp*`, ri, value = "Z") :
  invalid factor level, NA generated
> df
  patient referring_doctor
1     Ann                X
2     Bob                Y
3   Carol                X
4    <NA>             <NA>

Así que no conviertas los factores de tus columnas de cadena. Guárdelos como cadenas, luego, anexar funciona bien :

> df <- data.frame(patient=c('Ann','Bob','Carol'), referring_doctor=c('X','Y','X'), stringsAsFactors=F)
> df <- rbind(df, c('Denise','Z'))
  patient referring_doctor
1     Ann                X
2     Bob                Y
3   Carol                X
4  Denise                Z

Para cambiar el comportamiento predeterminado :

options(stringsAsFactors=F)

Para convertir columnas individuales a / desde cadenas o factores

df$col <- as.character(df$col)
df$col <- as.factor(df$col)

aquí hay una función para tomar los nombres de fila comunes de 2 marcos de datos y hacer un rbind donde básicamente encontramos los campos que son factores, agregamos los nuevos factores y luego hacemos el rbind. Esto debería solucionar cualquier problema de factores:

rbindCommonCols < -function (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

}

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top