2009-09-08 18 views
5

Począwszy od tej ramki danychJak sprawić, by funkcja R zwracała wiele kolumn i dołączała je do ramki danych?

myDF = structure(list(Value = c(-2, -1, 0, 1, 2)), .Names = "Value", row.names = c(NA, 5L), class = "data.frame") 

Załóżmy, że chcemy uruchomić tę funkcję na każdym rzędzie myDF $ Wartość

getNumberInfo <- function(x) { 
if(x %% 2 ==0) evenness = "Even" else evenness="Odd" 
if(x > 0) positivity = "Positive" else positivity = "NonPositive" 
if (positivity == "Positive") logX = log(x) else logX=NA 
c(evenness,positivity,logX) 
} 

... aby to ramka danych

structure(list(Value = c(-2, -1, 0, 1, 2), Evenness = c("Even", 
"Odd", "Even", "Odd", "Even"), Positivity = c("NonPositive", 
"NonPositive", "NonPositive", "Positive", "Positive"), Log = c(NA, 
NA, NA, "0", "0.693147180559945")), row.names = c(NA, 5L), .Names = c("Value", 
"Evenness", "Positivity", "Log"), class = "data.frame") 

Odpowiedz

8

Możesz chcieć zmienić swoją funkcję getNumberInfo zwraca listę zamiast wektora, tak że wartości mogą mieć różne typy. W rzeczywistości wszystkie są rzutowane na ciągi znaków, co prawdopodobnie nie jest tym, czego oczekujesz od logX.

getNumberInfo <- function(x) { 
    if(x %% 2 ==0) evenness = "Even" else evenness="Odd" 
    if(x > 0) positivity = "Positive" else positivity = "NonPositive" 
    if (positivity == "Positive") logX = log(x) else logX=NA 
    list(evenness,positivity,logX) 
} 

Ponadto, można użyć nazwy do nieco lepszego efektu, dzięki czemu nie trzeba ich powtarzać:

getNumberInfo <- function(x) { 
    list(evenness = if(x %% 2 ==0) "Even" else "Odd", 
     positivity = if(x > 0) "Positive" else "NonPositive", 
     logX = if(x > 0) log(x) else NA) 
} 

Następnie roztwór staje się prosta:

> cbind(myDF, t(sapply(myDF$Value, getNumberInfo))) 
    Value evenness positivity  logX 
1 -2  Even NonPositive  NA 
2 -1  Odd NonPositive  NA 
3  0  Even NonPositive  NA 
4  1  Odd Positive   0 
5  2  Even Positive 0.6931472 

Na koniec, jeśli używasz ifelse (który może pracować na wektorach) zamiast if, staje się jeszcze prostsze, ponieważ nie musisz dzwonić pod numer apply:

getNumberInfo <- function(x) { 
    list(evenness = ifelse(x %% 2 ==0, "Even", "Odd"), 
     positivity = ifelse(x > 0, "Positive", "NonPositive"), 
     logX = ifelse(x > 0, log(x), NA)) 
} 

> cbind(myDF, getNumberInfo(myDF$Value)) 
    Value evenness positivity  logX 
1 -2  Even NonPositive  NA 
2 -1  Odd NonPositive  NA 
3  0  Even NonPositive  NA 
4  1  Odd Positive 0.0000000 
5  2  Even Positive 0.6931472 

To ostatnie rozwiązanie emituje ostrzeżenie, bo to rzeczywiście obliczania dziennik każdym elemencie, nie tylko tych z x>0. Nie jestem pewna, jak najlepiej sobie z tym poradzić.

+0

Co to jest 't (sapply'do w przeciwieństwie do just' tapply'? Nie wiem, co owija coś 't()' nigdy nie widziałem tego udokumentowanego. –

3

Co powiesz na to:

out <- cbind(myDF, t(apply(myDF, 1, getNumberInfo))) 
colnames(out) <- c('Value', 'Evenness', 'Positivity', 'Log') 

co daje:

 
    Value Evenness Positivity    Log 
1 -2  Even NonPositive    NA 
2 -1  Odd NonPositive    NA 
3  0  Even NonPositive    NA 
4  1  Odd Positive     0 
5  2  Even Positive 0.693147180559945 

+0

Co 't (apply'do a nie tylko' tapply' nie wiem co owijania coś z 't()' nie nigdy nie widziałem?. to jest udokumentowane: –

3

Inną alternatywą:

> library(plyr) 
> df <- mdply(myDF, getNumberInfo) 
> names(df) <- c('Value', 'Evenness', 'Positivity', 'Log') 
> df 
    Value Evenness Positivity  Log 
1 -2  Even NonPositive  NA 
2 -1  Odd NonPositive  NA 
3  0  Even NonPositive  NA 
4  1  Odd Positive 0.0000000 
5  2  Even Positive 0.6931472