使用整数和字符变量

时间:2017-06-16 14:02:33

标签: r function dataframe row apply

一个完全基本的问题 - 如果它是重复的话,请原谅我。

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。

2 个答案:

答案 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