将具有看不见的字符串值的新记录附加到数据帧时看不见的因子级别,导致警告并导致NA

问题描述 投票:66回答:7

我有一个数据框(14.5K行乘15列),包含2001年至2007年的计费数据。

我将新的2008年数据附加到:alltime <- rbind(alltime,all2008)

不幸的是,它会产生警告:

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

我的猜测是,有些新病人的名字不在之前的数据框中,因此不知道给那些人提供什么水平。类似于“推荐医生”专栏中新的看不见的名字。

解决方案是什么?

r dataframe append r-factor
7个回答
30
投票

这可能是由两个data.frames中的类型不匹配引起的。

首先检查类型(类)。为诊断目的这样做:

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

我希望有一行看起来像:

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

如果是,那么解释:rbind不检查类型匹配。如果你分析rbind.data.frame代码,那么你可以看到第一个参数初始化输出类型。如果在第一个data.frame类型是一个因子,那么输出data.frame列是具有级别unique(c(levels(x1),levels(x2)))的因子。但是当在第二个data.frame列不是因素时,levels(x2)NULL,因此级别不会扩展。

这意味着您的输出数据是错误的!有NA而不是真值

我想:

  1. 你使用另一个R / RODBC版本创建旧数据,因此使用不同的方法创建类型(不同的设置 - 可能是小数分隔符)
  2. 有问题的列中有NULL或某些特定数据,例如。有人更改数据库下的列。

解:

找到错误的列并找出原因导致错误并修复。消除原因不是症状。


27
投票

一种“简单”的方法是在导入文本数据时不将字符串设置为因子。

请注意,read.{table,csv,...}函数采用stringsAsFactors参数,默认情况下设置为TRUE。您可以在导入和FALSE数据时将其设置为rbind

如果您想将列设置为最后的一个因素,您也可以这样做。

例如:

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)

9
投票

1)创建数据帧,其中stringsAsFactor设置为FALSE。这应解决因素问题

2)之后不要使用rbind - 如果数据框为空,它会混淆列名。简单地这样做:

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

4
投票

正如上一个答案中所建议的那样,将列作为字符读取并在rbind之后转换为因子。 SQLFetch(我假设RODBC)也有stringsAsFactorsas.is参数来控制字符的转换。允许的值与read.table相同,例如as.is=TRUE或某些列号。


3
投票

我遇到了类型不匹配的问题,尤其是因素。我不得不将两个兼容的数据集粘在一起。

我的解决方案是将两个数据帧中的因子转换为“字符”。然后它就像一个魅力:-)

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

如果要查看两个数据帧中的类型,请运行(更改var名称):

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

2
投票

创建数据框时,您可以选择制作字符串列因子(stringsAsFactors=T),或将它们保留为字符串。

对于您的情况,不要使您的字符串列因素。将它们保持为字符串,然后附加工作正常。如果你需要它们最终成为因子,那么首先将所有插入和附加作为字符串,然后最终将它们转换为因子。

如果你创建字符串列因子然后追加包含看不见的值的行,你会得到你在每个新的看不见的因子级别上提到的错误,并且该值被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>

所以不要让你的字符串列因素。将它们保持为字符串,然后附加工作正常:

> 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

要更改默认行为:

options(stringsAsFactors=F)

要将单个列转换为字符串或因子

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

0
投票

这里有一个函数来获取2个数据帧的公共行名称并执行一个rbind,其中我们基本上找到作为因子的字段,添加新因子然后执行rbind。这应该解决任何因素问题:

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

}

© www.soinside.com 2019 - 2024. All rights reserved.