2012-02-09 20 views
10

Wiesz, w jaki sposób możesz dostarczyć wektor nazw do ramki danych, aby zmienić nazwy kolumn lub wierszy w ramce danych. Czy istnieje podobna metoda dostarczania wektora nazw, które zmieniają klasę każdej kolumny w ramce danych? Możesz to zrobić, gdy czytasz w ramce danych z read.table przy użyciu colClasses. Co się stanie, jeśli ramka danych zostanie utworzona wewnątrz R?dostarcza wektor do "klas" ramki danych

DF <- as.data.frame(matrix(rnorm(25), 5, 5)) 
str(DF) #all numeric modes 

names(DF) <- c("A", "A2", "B", "B2", "Z") #I want something like this for classes 
some_classes_function_like_names(DF) <- c(rep("character", 3), rep("factor", 2)) 

#I can do it like this but this seems inefficient 
DF[, 1:3] <- lapply(DF[, 1:3], as.character) 
DF[, 4:5] <- lapply(DF[, 4:5], as.factor) 

str(DF) 

EDYCJA: Zmieniłem sapply powyżej na lapply jak sapply nie ma sensu.

EDIT 2: Jeżeli istnieje sposób, aby napisać użytkownika określoną funkcję, która wystarczyłaby także

Odpowiedz

5

Wydaje class(x) <- "factor" nie działa i nie robi as(x, "factor"), więc nie wiem o bezpośredni sposób prowadzenia czego chcesz.

... Ale nieco bardziej wyraźny sposób jest:

# Coerces data.frame columns to the specified classes 
colClasses <- function(d, colClasses) { 
    colClasses <- rep(colClasses, len=length(d)) 
    d[] <- lapply(seq_along(d), function(i) switch(colClasses[i], 
     numeric=as.numeric(d[[i]]), 
     character=as.character(d[[i]]), 
     Date=as.Date(d[[i]], origin='1970-01-01'), 
     POSIXct=as.POSIXct(d[[i]], origin='1970-01-01'), 
     factor=as.factor(d[[i]]), 
     as(d[[i]], colClasses[i]))) 
    d 
} 

# Example usage 
DF <- as.data.frame(matrix(rnorm(25), 5, 5)) 
DF2 <- colClasses(DF, c(rep("character", 3), rep("factor", 2))) 
str(DF2) 

DF3 <- colClasses(DF, 'Date') 
str(DF3) 

Kilka rzeczy: można dodać więcej przypadków, ile potrzeba. A pierwsza linia tej funkcji pozwala na połączenie z jedną nazwą klasy. Ostatni "domyślny" przypadek switch wywołuje funkcję , a przebieg może się różnić.

+0

@ Tommy Miałem nadzieję na odpowiedź: "You nuy jest już podstawową funkcją, która robi to łatwo". Twoje funkcje działają dobrze. Wrzucę to do mojej .First() jako funkcji wygody dla siebie. Jestem trochę zaskoczony, że zespół R-core nie wdrożył już czegoś takiego, zwłaszcza, że ​​wydaje się być częścią read.table. Dziękuję Ci. –

+0

@Tyler Dzielę się twoją niespodzianką. Od dawna poszukiwałem funkcji bazowej, aby to osiągnąć i zazwyczaj podejmuję pewne działania ad hoc w locie. Byłoby wspaniale, gdyby zespół R-core rozważył to w bazie. – digitalmaps

8

Spróbuj tego:

toCls <- function(x, cls) do.call(paste("as", cls, sep = "."), list(x)) 
replace(DF,, Map(toCls, DF, cls)) 

drugim przykładzie. Spróbuj także tego przykładu (który pozwala na użycie NA dla każdej kolumny, której klasa nie ma być zmieniona). Ładujemy pakiet z ogrodem zoologicznym, ponieważ zapewnia on wersję as.Date, która ma domyślne pochodzenie i definiujemy naszą własną as.POSIXct2, aby uniknąć konieczności określania pochodzenia.

library(zoo) # supplies alternate as.Date with a default origin 
as.NA <- identity 
as.POSIXct2 <- function(x) as.POSIXct(x, origin = "1970-01-01") 

cls2 <- c("character", "Date", NA, "factor", "POSIXct2") 
replace(DF,, Map(toCls, DF, cls2)) 

Zauważ, że jej tylko podczas konwertowania numery "Date" lub "POSIXct", że istnieją względy pochodzenie i przy konwersji ciągów znaków takich jak "2000-01-01" nie pochodzenie musiałaby być określona w każdym razie więc do takich sytuacji nie musiałyby załaduj zoo i nie potrzebowalibyśmy naszej własnej wersji as.POSIXct.

EDYCJA: Dodano inny przykład.