一个完全基本的问题 - 如果它是重复的话,请原谅我。
set.seed(1)
df <-
data.frame(id=c('a', 'a', 'b', 'b', 'a'),
a=sample(1:10, size=5, replace=T),
b=sample(1:10, size=5, replace=T),
c=sample(1:10, size=5, replace=T))
然后,
> df
id a b c
1 a 3 9 3
2 a 4 10 2
3 b 6 7 7
4 b 10 7 4
5 a 3 1 8
要返回具有最大值的列名(a,b或c),如果它在id
变量中取第二个最高值,则使用以下函数。
FUN <- function(r) {
top <- names(r[,c('a', 'b', 'c')])[order(r[,c('a', 'b', 'c')], decreasing=T)]
ifelse(top[1] == r[['id']], top[2], top[1])
}
我能做到:
FUN(df[1,]) #[1] "b"
和所有行:
res <- NULL
for(i in 1:nrow(df)) {
res <- c(res, FUN(df[i,]))
}
得到
> res
[1] "b" "b" "c" "a" "c"
但我怎么能apply
这个?例如。这不起作用:
apply(df, 1, FUN)
我怀疑问题是FUN
假定1行数据帧(而不是像(第一行)这样的字符的命名向量)
id a b c
"a" "3" "9" "c"
来自apply?
:
如果X不是数组而是具有非空昏暗值的类的对象(例如数据框),则应用尝试通过as.matrix将其强制转换为数组(如果它是二维的)(例如,数据框)或通过as.array。
答案 0 :(得分:1)
如果你必须使用你的功能,你可以这样做,
sapply(split(df, 1:nrow(df)), f1)
# 1 2 3 4 5
#"b" "b" "c" "a" "c"
注意我将您的FUN
重命名为f1
,因为R中的各种函数使用了FUN
,以便定义函数的参数
答案 1 :(得分:1)
另一种选择是对FUN
进行一些小修改。我认为您遇到的问题是apply
会将每一行视为向量。由于您的id
列是一个字符,这意味着您的a/b/c
列也会被强制转换为字符。实现这一点,我们可以稍微修改FUN
以将其转换回numeric
进行排序:
FUN <- function(r) {
top <- c('a', 'b', 'c')[order(as.numeric(r[c('a', 'b', 'c')]), decreasing=T)]
ifelse(top[1] == as.character(r['id']), top[2], top[1])
}
apply(df, 1, FUN)
#[1] "b" "b" "c" "a" "c"
要了解其工作原理,您可以运行以下内容,看看apply
正在读取命名的字符向量。
apply(df, 1, function(x) {print(x); print(class(x)); return(NULL)})
# id a b c
# "a" " 3" " 9" "3"
#[1] "character"
# id a b c
# "a" " 4" "10" "2"
#[1] "character"
# id a b c
# "b" " 6" " 7" "7"
#[1] "character"
# id a b c
# "b" "10" " 7" "4"
#[1] "character"
# id a b c
# "a" " 3" " 1" "8"
#[1] "character"
#NULL