2009-10-27 12 views
64

Mam dużą ramkę danych (14552 wiersze po 15 kolumnach) zawierającą dane rozliczeniowe od 2001 do 2007 roku. Skorzystałem z narzędzia sqlFetch, aby uzyskać dane z 2008 roku. Aby dołączyć dane z danymi z poprzednich 7 lat należałoby zrobić w 2008 roku następującoDołączanie wierszy do ramki danych - problem z czynnikiem

alltime <-rbind(alltime,all2008)

Niestety to generuje

komunikat ostrzegawczy: W [<-.factor (*tmp*, RI, wartość = c (NA, NA, NA, NA, NA, NA,: nieprawidłowy poziom czynnika, NN wygenerowany

Zgaduję, że Są to nowi pacjenci, których nazwiska nie znajdowały się w poprzedniej ramce danych, a zatem nie wiedzieliby, jaki poziom ją podać. Kolejna kolumna dotyczy nazwiska polecającego lekarza. Nowy lekarz kierujący sprawiłby ten sam problem.

Sposób, w jaki R importuje dane i automatycznie sprawdza, co jest numeryczne, a co nie jest (a tym samym czyni to czynnikiem) jest wspaniały - dopóki nie będziesz musiał nim manipulować dalej, a potem stanie się to bólem. Jak elegancko pokonywać mój problem?

+5

To jest dziwne. Czynnik nie powinien tego powodować, w celu określenia "rbind": "Czynniki mają w razie potrzeby zwiększone poziomy" (R-2.9.2). Może mógłbyś sprawdzić dokładnie, która kolumna to powoduje? – Marek

+1

Co za wspaniały punkt Marek! Wiadomość ostrzegawcza mnie przeraziła. Po przeczytaniu Twojego komentarza wróciłem, by poznać moje dane. Pojawiają się wszystkie nowe dane i dodano dodatkowe poziomy. Na tym etapie mogłem po prostu zostawić to jako ostrzeżenie, które powinno być zignorowane - co jest niebezpiecznym nawykiem, do którego należy się dostać (od tego czasu należy utrzymywać bazę danych w swoich ostrzeżeniach, które należy traktować poważnie, a ostrzeżenia należy zignorować). Jak mogę się dowiedzieć, skąd pochodzi komunikat ostrzegawczy? – Farrel

Odpowiedz

30

Może to być spowodowane niedopasowaniem typów w dwóch data.frames.

Przede wszystkim typy kontrolne (klasy). Do celów diagnostycznych to zrobić:

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

się spodziewać tam być wiersz wygląda następująco:

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

Jeśli tak to wyjaśnienie: rbind nie sprawdza typy dopasowania. Jeśli przeanalizujesz kod rbind.data.frame, możesz zauważyć, że pierwszy argument inicjował typy wyjściowe. Jeśli w pierwszym typie data.frame jest współczynnik, to wyjściowa kolumna data.frame jest czynnikiem o poziomach unique(c(levels(x1),levels(x2))). Ale gdy w drugiej kolumnie data.frame nie ma współczynnika, to levels(x2) to NULL, więc poziomy nie rozciągają się.

Oznacza to, że dane wyjściowe są błędne! Istnieje NA „s zamiast prawdziwych wartości

Przypuszczam, że:

  1. utworzyć stary danych z innym R wersji/RODBC więc typy zostały stworzone z różnymi metodami (różnymi ustawieniami - separator dziesiętny może)
  2. W kolumnie problematycznej znajdują się dane NULL lub niektóre specyficzne, np. ktoś zmienił kolumnę w bazie danych.

Rozwiązanie:

znaleźć złego kolumnę i znaleźć przyczynę jego jest nie tak i stałe. Wyeliminuj przyczynę, a nie objawy.

+1

Yip. Masz rację. w jednej ramce danych była to klasa kolumny, a w drugiej była to cyfra. To źle poradziło. Przekształciłem numerycznie na współczynnik i wszystko było OK. Dziękuję za wskazówki. Wystąpiły również inne rozbieżności. Na przykład rozbieżność między współczynnikami a charakterem nie powodowała bałaganu. – Farrel

+0

Masz rację co do znaku-znaku, gdzieś w kodzie znalazłem, że poziomy dla tej kombinacji będą "unikalne (c (poziomy (x1), x2))". Jedna rzecz: charakterystyka kombinacji znaków prowadzi do czynnika, kombinacji charakteru postaci do postaci. Więc lepiej, gdy typy się zgadzają. – Marek

26

"Prostym" sposobem jest po prostu nie ustawianie swoich ciągów jako czynników podczas importowania danych tekstowych.

Należy pamiętać, że funkcje read.{table,csv,...} przyjmują parametr stringsAsFactors, który jest domyślnie ustawiony na TRUE. Możesz ustawić to na FALSE podczas importowania i rbind -wprowadzaniu danych.

Jeśli chcesz ustawić kolumnę jako czynnik na końcu, możesz to zrobić.

Na przykład:

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

Wierzę, że masz w swojej odpowiedzi kilka literówek ... – griffin

+1

Woops, dzięki za wskazanie tego. Naprawiono (myślę). –

4

Jak zasugerowano w poprzedniej odpowiedzi, przeczytaj kolumny jak charakter i zrobić konwersję na czynniki po rbind. SQLFetch (Zakładam, że RODBC) ma również argument stringsAsFactors lub as.is do kontrolowania konwersji znaków. Dozwolone wartości są takie same jak dla read.table, np. as.is=TRUE lub niektóre numery kolumn.

3

Miałem ten sam problem z niedopasowaniem typu, szczególnie z czynnikami. Musiałem skleić ze sobą dwa kompatybilne zestawy danych.

Moim rozwiązaniem jest przekonwertowanie czynników z obu ramek danych na "znak". To działa jak czar :-)

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

Jeśli chcesz zobaczyć typy w swoich dwóch dataframes run (zmiana nazwy VAR):

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

bardzo przydatna funkcja, dzięki. – PatrickT

+3

'mydf [sapply (mydf, is.factor)] <- lapply (mydf [sapply (mydf, is.factor)], as.character) wydaje się być prostszym podejściem. – A5C1D2H2I1M1N2O1R2T1

7

1) utworzyć ramkę danych ze zbioru stringsAsFactor do FALSE. Powinno to rozwiązać problem z wydajnością: 2) następnie nie używaj rbind - przesuwa nazwy kolumn, jeśli ramka danych jest pusta. po prostu zrobić to w ten sposób:

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 
0

oto funkcja do podjęcia wspólnych nazw rzędzie 2 ramek danych i zrobić rbind gdzie w zasadzie znaleźć pola, które są czynnikami, dodaj nowe czynniki następnie wykonaj rbind. To powinno dbać o wszelkie kwestie czynników:

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 

}

Powiązane problemy