Невидимые факторные уровни при добавлении новых записей с невидимыми строковыми значениями в фрейм данных вызывают предупреждение и приводят к NA

у меня есть большой фрейм данных (14552 строки по 15 столбцам), содержащий платежные данные с 2001 по 2007 год. Я использовал sqlFetch для получения данных 2008 года. Для добавления данных за 2008 год к данным за предыдущие 7 лет необходимо сделать следующее:

alltime <- rbind(alltime,all2008)

к сожалению, это генерирует

предупреждение : В [<-.factor(*tmp*, ri, value = c(NA, NA, NA, NA, NA, NA, NA, : недопустимый уровень коэффициента, сгенерированный NAs

мой предположим, что есть некоторые новые пациенты, чьи имена не были в предыдущем фрейме данных, и поэтому он не знал бы, какой уровень дать ему. Аналогично новое невидимое имя в колонке "доктор".

то, как R импортирует данные и автоматически определяет, что является числовым, а что нет (и тем самым делает его фактором), замечательно - до тех пор, пока вам не придется манипулировать им дальше, а затем это становится болью. Как элегантно преодолеть свою проблему?

7 ответов


это может быть вызвано несоответствием типов в двух 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 code тогда вы могли видеть, что первый аргумент инициализировал выходные типы. Если в первых данных.тип кадра-это фактор, а затем выходные данные.столбец рамки-фактор с уровнями unique(c(levels(x1),levels(x2))). Но когда во вторых данных.столбец frame не является фактором тогда levels(x2) is NULL, поэтому уровни не распространяются.

это означает, что ваши данные ошибочны! Есть NAвместо истинных значений

Я полагаю, что:

  1. вы создаете старые данные с другой версией R / RODBC, поэтому типы были созданы с помощью разных методов (разные настройки - возможно, десятичный разделитель)
  2. есть NULL или некоторые конкретные данные в проблемной колонке, например. кто-то меняет столбец в базе данных.

устранение:

найти неправильный столбец и найти причину, почему его неправильно и исправлено. Устранить причину а не симптомы.


"простой" способ-просто не устанавливать строки в качестве факторов при импорте текстовых данных.

отметим, что read.{table,csv,...} функции принимают stringsAsFactors параметр, который по умолчанию установлен в TRUE. Вы можете указать FALSE пока вы импортируете и rbind - ing ваши данные.

если вы хотите установить столбец в качестве фактора в конце, вы также можете это сделать.

например:

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) Создайте фрейм данных со значением 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

как было предложено в предыдущем ответе, прочитайте столбцы как символ и выполните преобразование в факторы после rbind. SQLFetch (Я предполагаю,RODBC), а также stringsAsFactors или


у меня была такая же проблема с несоответствием типов, особенно с факторами. Мне пришлось склеить два набора данных, в остальном совместимых.

мое решение заключается в преобразовании факторов в обоих кадрах данных в "символ". Тогда это работает как шарм: -)

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

когда вы создаете фрейм данных, у вас есть выбор сделать ваши строковые столбцы факторами (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)

вот функция, чтобы взять общие имена строк 2 фреймов данных и сделать rbind, где мы в основном находим поля, которые являются факторами, добавить новые факторы, а затем сделать rbind. Это должно позаботиться о любых факторных проблемах:

rbindCommonCols

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

}