使用多列作为变量与 sapply

Posted

技术标签:

【中文标题】使用多列作为变量与 sapply【英文标题】:use multiple columns as variables with sapply 【发布时间】:2012-04-22 02:54:44 【问题描述】:

我有一个dataframe,我想应用一个函数来获取三列的值并计算三个值之间的最小差异。

#dataset
df <- data.frame(a= sample(1:100, 10),b = sample(1:100, 10),c= sample(1:100, 10))

#function
minimum_distance <- function(a,b,c)

  dist1 <- abs(a-b)
  dist2 <- abs(a-c)
  dist3 <- abs(b-c)
  return(min(dist1,dist2,dist3))

我正在寻找类似的东西:

df$distance <- sapply(df, function(x) minimum_distance(x$a,x$b,x$c) )
## errormessage
Error in x$a : $ operator is invalid for atomic vectors

虽然我可以使用 ddply:

df2 <- ddply(df,.(a),function(r) data.frame(min_distance=minimum_distance(r$a,r$b, r$c)), .drop=FALSE)

这不会保留所有列。有什么建议吗?

编辑:我最终使用了:

df$distance <- mapply(minimum_distance, df$a, df$b, df$c)

【问题讨论】:

【参考方案1】:

试试 mapply():

qq <- mapply(minimum_distance, df$a, df$b, df$c)

【讨论】:

哪一个是最快的?还是更高效?【参考方案2】:

试试这个:

do.call("mapply", c(list(minimum_distance), df))

但你可以编写矢量化版本:

pminimum_distance <- function(a,b,c)

 dist1 <- abs(a-b)
 dist2 <- abs(a-c)
 dist3 <- abs(b-c)
 return(pmin(dist1,dist2,dist3))

pminimum_distance(df$a, df$b, df$c)

# or
do.call("pminimum_distance", df)

【讨论】:

这很聪明,但有点不那么直截了当,谢谢 mapply。【参考方案3】:

我知道这个问题已经得到解答,但我实际上会采用一种不同的方法,该方法采用任意数量的列,并且使用外部方法更通用:

vdiff <- function(x)
    y <- outer(x, x, "-")
    min(abs(y[lower.tri(y)]))


apply(df, 1, vdiff)

我认为这更简洁灵活。

编辑:根据 zach 的 cmets,我提出了这个更正式的函数,该函数也适用于具有非数字列的数据帧,方法是删除它们并仅作用于数字列。

cdif <- function(dataframe)
    df <- dataframe[, sapply(dataframe, is.numeric)]
    vdiff <- function(x)
        y <- outer(x, x, "-")
        min(abs(y[lower.tri(y)]))
    
    return(apply(df, 1, vdiff))


#TEST it out
set.seed(10)
(df <- data.frame(a = sample(1:100, 10), b = sample(1:100, 10), 
    c = sample(1:100, 10), d =  LETTERS[1:10]))

cdif(df)

【讨论】:

好主意。但是,我的真实数据框不是矩阵-可以对其进行修改以在具有文本列的数据框中使用吗?像 outer(x,x,"-", drop_string=T)? 函数outer 并不一定意味着您正在处理矩阵。它只需要两个向量和一个函数,并为这两个向量创建一个包含所有可能组合的矩阵。在这里,我只是将相同的向量(行)提供给外部两次和函数减法- 运算符。我在我的解决方案中添加了一些内容,以创建一个独立的函数,该函数作用于数据帧并排除任何非数字的内容。 outer 可能非常强大我只是希望我能记得更多地使用它。至于 drop_string = T?没有这样的运气,但 sapplyis.numeric 查询效果很好。 非常好。我同意外部非常强大,对于更大的矩阵,这将是一种方法,而不是指定每个列或值。 注意:因为这个答案更通用,它可能也更慢,不确定问题速度有多大(即你的数据集有多大)。 在这种情况下速度不是问题,但我会记住这一点。谢谢泰勒。【参考方案4】:

最好写一个函数,然后在向量上使用mapply:

 f1 <- function(a,b,c)
 d =abs(a-b)
 e =abs(b-c)
 f= abs(c-a)
 return(pmin(d,e,f))
 

 qq <- mapply(f1, df$a, df$b, df$c)

【讨论】:

以上是关于使用多列作为变量与 sapply的主要内容,如果未能解决你的问题,请参考以下文章

以整齐的方式将多列作为分组变量传递给 UDF

如何在 Snowflake 中选择一个 csv 行的变量列作为多列?

HBase 与多列的一对多关系

将 LinQ 与多列分组一起使用

GroupBy 多列作为键并对多列求和,如 sql?

MYSQL 使用变量更新多列