Уровни невидимого фактора при добавлении новых записей с невидимыми строковыми значениями во фрейм данных вызывают предупреждение и приводят к NA
Вопрос
У меня есть фрейм данных (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
Я предполагаю, что есть несколько новых пациентов, имен которых не было в предыдущем фрейме данных, и поэтому он не знал бы, какой уровень им присвоить.Аналогично, появились новые невидимые имена в столбце "направляющий врач".
Каково же решение?
Решение
Это может быть вызвано несоответствием типов в двух 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 является фактором, то столбец output data.frame является фактором с уровнями unique(c(levels(x1),levels(x2)))
.Но когда во втором столбце data.frame это не фактор, тогда levels(x2)
является NULL
, таким образом, уровни не расширяются.
Это означает, что ваши выходные данные неверны!Есть такие NA
's вместо истинных значений
Я полагаю , что:
- вы создаете свои старые данные с другой версией R / RODBC, поэтому типы были созданы разными методами (возможно, с разными настройками - десятичный разделитель)
- в проблемном столбце есть NULL или какие-то конкретные данные, например.кто-нибудь, измените столбец в базе данных.
Решение:
найдите неправильный столбец и найдите причину, почему он неправильный, и исправьте его.Устраните причину, а не симптомы.
Другие советы
" easy " Можно просто не указывать строки в качестве факторов при импорте текстовых данных.
Обратите внимание, что функции 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)
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
или as.is
для управления преобразованием символов.
Допустимые значения: read.table
, например, as.is=TRUE
или номер столбца.
У меня была такая же проблема с несоответствиями типов, особенно с факторами. Мне пришлось склеить два набора данных, которые в противном случае были бы совместимы.
Мое решение состоит в том, чтобы преобразовать факторы в обоих информационных кадрах в " символ " ;. Тогда это работает как шарм: -)
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)
)
Когда вы создаете фрейм данных, у вас есть выбор: использовать факторы столбцов строк (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.Это должно позаботиться о любых факторных проблемах:
Rbindcommon - файлы<-функция(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
}