【问题标题】:Using Apply or Vectorize to apply custom function to a dataframe使用 Apply 或 Vectorize 将自定义函数应用于数据框
【发布时间】:2018-12-20 04:52:15
【问题描述】:

我正在尝试应用一个自定义函数,该函数调用该数据框的组件来进行计算。我在下面做了一个简单的例子,因为我的实际问题很难做一个可重现的例子。在下面的示例中,我希望将前两列加在一起以创建第三列,这是它们的总和。下面是我在网上找到的一个与我想要的很接近的例子:

celebrities=data.frame(name=c("Andrew","matt","Dany","Philip","John","bing","Monica"),
                       age=c(28,23,49,29,38,23,29),
                       income=c(25.2,10.5,11,21.9,44,11.5,45))
f=function(x,output){
  name=x[1]
  income=x[3]
  cat(name,income,"\n")
}
apply(celebrities,1,f)

但是当我尝试使用它并应用数学函数时它不起作用:

  f2=function(x,output){
  age=x[2]
  income=x[3]
  sum(age,income)
}
apply(celebrities,1,f2)

本质上,我需要的是 apply 获取数据集,使用该行中的值作为函数的输入遍历该数据集的每一行,然后将第三列添加到数据集以及函数的结果。如果需要,请告诉我如何澄清这个问题。我已经提到了以下问题,但它们似乎对我不起作用。

Apply a function to every row of a matrix or a data frame

How to assign new values from lapply to new column in dataframes in list

Call apply-like function on each row of dataframe with multiple arguments from each row

【问题讨论】:

  • 当您在data.frame 上使用apply 时,会将其转换为matrix 以进行处理。如果(已处理帧的)任何列是character,则所有列都将转换为character,从而使任何数学运算失效。虽然我倾向于不鼓励 apply 使用框架,但如果您必须确保只使用其中的一部分,例如 apply(celebrities[c("age","income")], 1, sum)
  • 您可以尝试使用library(plyr) 中的某些内容,例如adplyaaply(取决于您希望输出格式是什么样的),它们不会将所有列强制转换为character
  • 我相信dplyr 现在有一个rowwise 函数可以帮助你做你想做的事。例如,library(dplyr) ; celebrities %>% rowwise %>% mutate(new_var = f(var1, var2))

标签: r vectorization apply lapply


【解决方案1】:

对于请求的特定任务,它可能是

celebrities$newcol <- with(celebrities, age + income)

+ 函数本质上是矢量化的。将applysum 一起使用是低效的。通过省略第一列可以大大简化使用apply,因为这样可以避免由第一列引起的对字符矩阵的强制。

 celebrities$newcol <- apply(celebrities[-1], function(x) sum(x) )

这样您就可以避免将向量强制转换为“字符”,然后将以前的数字列强制转换为 numeric。在 apply 中使用 sum 确实可以解决 sum 未矢量化的事实,但它是 R 编码效率低下的一个示例。

如果“内部”算法可以完全由矢量化函数构建,您将获得自动矢量化:Math 和 Ops 组是常用的组件。见?Ops。否则,您可能需要使用mapplyVectorize

【讨论】:

    【解决方案2】:

    从@r2evans 和@user2738526 获得提示,我已经对您的函数进行了修改。 将数字显式转换为数字。 以下代码 sn-p 适用于您的情况:

    f2=function(x,output){
      age=as.numeric(x[2])
      income=as.numeric(x[3])
      sum(age,income)
    }
    apply(celebrities,1,f2)
    
    [1] 53.2 33.5 60.0 50.9 82.0 34.5 74.0
    

    【讨论】:

    • 我没有反对,因为在识别出原始错误后确实解决了问题,但您应该明白这是相当丑陋的 R 编码,不会成为其他人效仿的好例子。 r2evans 给出了更好的建议,而你似乎忽略了它。
    • @42- 我也不喜欢我的解决方案,它相当低效、麻烦等等,但我想如果 OP 有任何其他数值函数而不是 sum。我同意 r2evans 给出了更好的解决方案。原来的问题根本不需要apply
    • 如果这里不值得保留,我会删除它
    • 它可能有助于解释为什么您应该在使用apply 之前搜索其他策略。如果它在那个方向上有所改进,我会赞成它。
    • @42- 我会这么做的。我需要阅读更多内容以按照建议的方向改进它
    【解决方案3】:

    试试这个:

    library(dplyr)
    celebrities=data.frame(name=c("Andrew","matt","Dany","Philip","John","bing","Monica"),
                           age=c(28,23,49,29,38,23,29),
                           income=c(25.2,10.5,11,21.9,44,11.5,45)) 
    
    celebrities %>% 
      rowwise %>% 
      mutate(age_plus_income = sum(age, income))
    

    (显然,要对两列求和,最好使用mutate(celebrities, age_plus_income = age + income),但我假设您的实际示例使用了更复杂的函数。)

    【讨论】:

      猜你喜欢
      • 2023-03-06
      • 2017-01-28
      • 1970-01-01
      • 2020-10-28
      • 1970-01-01
      • 2021-09-20
      • 1970-01-01
      • 2020-10-01
      • 2018-03-03
      相关资源
      最近更新 更多