Les niveaux de facteur invisibles lors de l'ajout de nouveaux enregistrements avec des valeurs de chaîne invisibles à une image de données, entraînent un avertissement et génèrent un NA

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

  •  06-07-2019
  •  | 
  •  

Question

J'ai une base de données (14,5K lignes sur 15 colonnes) contenant les données de facturation de 2001 à 2007.

J'y ajoute de nouvelles données 2008 avec: alltime <- rbind(alltime,all2008)

Malheureusement, cela génère un avertissement:

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

Je suppose que certains noms de nouveaux patients ne figuraient pas dans la base de données précédente et que, par conséquent, ils ne sauraient pas quel niveau attribuer à ceux-ci. De même, de nouveaux noms non vus dans la colonne "médecin référant".

Quelle est la solution?

Était-ce utile?

La solution

Cela pourrait être dû à une incompatibilité de types dans deux data.frames.

Tout d’abord, vérifiez les types (classes). Pour diagnostiquer, procédez comme suit:

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)
)

Je m'attends à ce qu'il y ait une ligne ressemblant à:

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

Si oui, explication: rbind Ne cochez pas les types correspondants. Si vous analysez rbind.data.frame le code, vous constaterez que le premier argument initialise les types de sortie. Si en premier le type data.frame est un facteur, alors la colonne de sortie data.frame est un facteur de niveaux unique(c(levels(x1),levels(x2))). Mais lorsque la seconde colonne data.frame n'est pas un facteur, alors levels(x2) est NULL, les niveaux ne s'étendent donc pas.

Cela signifie que vos données de sortie sont fausses! Il y a NA au lieu de valeurs vraies

Je suppose que:

  1. vous créez vos anciennes données avec une autre version de R / RODBC, ainsi les types ont été créés avec différentes méthodes (paramètres différents - séparateur décimal peut-être)
  2. il y a NULL ou des données spécifiques dans la colonne problématique, par exemple. quelqu'un change de colonne sous la base de données.

Solution:

trouve la mauvaise colonne et trouve la raison pour laquelle elle est fausse et corrigée. Éliminer la cause, pas les symptômes.

Autres conseils

Un " facile " Pour cela, il suffit de ne pas définir vos chaînes comme facteurs lors de l’importation de données texte.

Notez que les fonctions read.{table,csv,...} prennent un paramètre stringsAsFactors, défini par défaut sur TRUE. Vous pouvez définir ce paramètre sur FALSE lors de l'importation et rbind de vos données.

Si vous souhaitez que la colonne soit un facteur à la fin, vous pouvez également le faire.

Par exemple:

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) créez le bloc de données avec stringsAsFactor défini sur FALSE. Cela devrait résoudre le problème de facteur

2) Ensuite, n'utilisez pas rbind. Les noms des colonnes sont égarés si le bloc de données est vide. faites-le simplement de cette façon:

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

Comme suggéré dans la réponse précédente, lisez les colonnes sous forme de caractère et effectuez la conversion en facteurs après rbind. SQLFetch (Je suppose que RODBC ) possède également l'argument stringsAsFactors ou as.is permettant de contrôler la conversion des caractères. Les valeurs autorisées sont les mêmes que pour read.table, par exemple, as.is=TRUE ou un numéro de colonne.

J'ai eu le même problème avec les mésappariements de types, en particulier avec les facteurs. J'ai dû coller deux ensembles de données par ailleurs compatibles.

Ma solution consiste à convertir les facteurs des deux cadres de données en & "; caractère &"; Ensuite, cela fonctionne comme un charme: -)

    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 vous souhaitez voir les types de vos deux cadres de données s'exécuter (changez les noms de variables):

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

Lorsque vous créez le cadre de données, vous avez le choix de définir vos facteurs de colonnes de chaîne (stringsAsFactors=T) ou de les conserver sous forme de chaînes.

Dans votre cas, ne faites pas de facteurs de colonnes de chaîne. Conservez-les en tant que chaînes, puis l'ajout fonctionne. Si vous souhaitez que ces facteurs soient finalement des facteurs, effectuez d'abord l'insertion et l'ajout en tant que chaîne, puis convertissez-les en facteur.

Si vous créez des facteurs de colonnes de chaîne, puis ajoutez des lignes contenant des valeurs invisibles, vous obtenez l'erreur que vous avez mentionnée à chaque nouveau niveau de facteur invisible et cette valeur est remplacée par 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>

Donc ne faites pas de facteurs de colonnes de chaîne. Conservez-les sous forme de chaînes, puis l'ajout fonctionne 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

Pour modifier le comportement par défaut :

options(stringsAsFactors=F)

Pour convertir des colonnes individuelles en / à partir d'une chaîne ou d'un facteur

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

voici une fonction qui prend les noms de ligne courants de 2 trames de données et fait un rbind où nous trouvons essentiellement les champs qui sont des facteurs, ajoutons les nouveaux facteurs puis faisons le rbind. Cela devrait résoudre tous les problèmes de facteurs:

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

}

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top