Wie kann eine R -Funktion mehrere Spalten zurückgeben und an einen Datenrahmen anhängen?
Frage
Beginnend mit diesem Datenrahmen
myDF = structure(list(Value = c(-2, -1, 0, 1, 2)), .Names = "Value", row.names = c(NA, 5L), class = "data.frame")
Angenommen, ich möchte diese Funktion in jeder Reihe von MyDF $ Value ausführen
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)
}
... um diesen Datenrahmen zu erhalten
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")
Lösung
Vielleicht möchten Sie Ihre ändern getNumberInfo
Funktionieren Sie eine Liste anstelle eines Vektors, damit die Werte unterschiedliche Typen haben können. So wie es ist, werden sie alle in Saiten gegossen, was wahrscheinlich nicht das ist, was Sie wollen 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)
}
Darüber hinaus können Sie die Namen zu einem etwas besseren Effekt verwenden, damit Sie sie nicht wiederholen müssen:
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)
}
Dann wird die Lösung einfach:
> 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
Schließlich, wenn Sie verwenden ifelse
(was an Vektoren funktionieren kann) anstelle von if
, Es wird noch einfacher, weil Sie nicht anrufen müssen 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
Diese letzte Lösung gibt eine Warnung aus, da sie tatsächlich das Protokoll jedes Elements berechnet, nicht nur diejenigen mit x>0
. Ich bin mir nicht sicher, ob der eleganteste Weg, damit umzugehen.
Andere Tipps
Wie wäre es mit:
out <- cbind(myDF, t(apply(myDF, 1, getNumberInfo)))
colnames(out) <- c('Value', 'Evenness', 'Positivity', 'Log')
Was dir gibt:
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
Eine andere Alternative:
> 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