Невидимые факторные уровни при добавлении новых записей с невидимыми строковыми значениями в фрейм данных вызывают предупреждение и приводят к 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
вместо истинных значений
Я полагаю, что:
- вы создаете старые данные с другой версией R / RODBC, поэтому типы были созданы с помощью разных методов (разные настройки - возможно, десятичный разделитель)
- есть 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
}