Невидимые уровни факторов при добавлении новых записей с невидимыми строковыми значениями в фрейм данных вызывают предупреждение и приводят к NA - PullRequest
66 голосов
/ 27 октября 2009

У меня есть фрейм данных (14,5 тыс. Строк на 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

Я предполагаю, что есть некоторые новые пациенты, чьи имена не были в предыдущем кадре данных, и поэтому он не знал бы, какой уровень дать им. Точно так же новые невидимые имена в столбце «Приглашающий доктор».

Какое решение?

Ответы [ 7 ]

30 голосов
/ 29 октября 2009

Это может быть вызвано несовпадением типов в двух 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 голосов
/ 27 октября 2009

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

Обратите внимание, что функции 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 голосов
/ 30 марта 2013

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 голосов
/ 27 октября 2009

Как предлагается в предыдущем ответе, прочитайте столбцы как символы и выполните преобразование в коэффициенты после rbind. SQLFetch (я полагаю RODBC ) также имеет аргумент stringsAsFactors или as.is для управления преобразованием символов. Допустимые значения: read.table, например, as.is=TRUE или номер столбца.

3 голосов
/ 07 февраля 2012

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

Мое решение состоит в том, чтобы преобразовать факторы в обоих информационных кадрах в «символ». Тогда это работает как шарм: -)

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

Если вы хотите увидеть типы в двух ваших фреймах данных (измените имена переменных):

    cbind("orig"=sapply(allSurveyData, class), 
          "merge" = sapply(curSurveyDataMerge, class),
          "eq"=sapply(allSurveyData, class) == sapply(curSurveyDataMerge, class)
    )
2 голосов
/ 30 мая 2018

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

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

rbindCommonCols <-функция (x, y) {</p>

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

}

...