在R函数内部调用data.frame列?

时间:2015-05-11 21:09:23

标签: r function apply

这样做的正确方法是什么?

我有一个功能,在一系列输入的情况下可以自行运行,我想在大型数据集上使用此函数,而不是通过逐行循环数据来使用奇异值。我试图更新函数来调用data.frame列而不是向量值,但一直没有成功。

一个简单的例子是:

假设我有一个包含4列的date.frame,数据$ id,数据$ height,数据$ weight,data $ gender。我想编写一个循环遍历每一行的函数(使用apply)并计算BMI(kg / m ^ 2)。我知道使用dplyr会很容易,但是我想学习如何在不使用外部包的情况下做到这一点但是找不到如何正确引用函数中的列的明确答案。

如果这是重复,请提前道歉。我一直在寻找Stackoverflow,希望找到一个现有的例子。

3 个答案:

答案 0 :(得分:3)

我认为这就是你要找的东西。在功能上引用数据框列的最简单方法是使用引用的列名。原则上,你正在做的是这个

$cdata = $doc->createCDATASection( 'whatever' ));
$doc->getElementsByTagName("SomeNode")->item(0)->nodeValue = $cdata;

但在函数内部,您可能希望让用户指定高度或重量列的命名方式不同,以便您可以编写函数

data[, "weight"] / data[, "height"]^2

此函数将假定默认情况下要使用的列名为“height”和“weight”,但用户可以根据需要指定其他名称。您可以使用列索引来执行类似的解决方案,但使用名称往往更容易调试。

这个简单的功能很少有用。如果你正在为很多数据集计算BMI,那么值得保留这个函数,但由于它是基数R中的单行,你可能不需要它。

add_bmi = function(data, height_col = "height", weight_col = "weight") {
    data$bmi = data[, weight_col] / data[, height_col]
    return(data)
}

需要注意的是,使用存储在变量中的列名意味着您无法使用my_data$BMI = with(my_data, weight / height^2) 。这是我们通过使事物更具程序性而付出的代价,并且为这些应用程序形成这是一个好习惯。见$

  

大多数R初学者迟早都被这个太方便的捷径所咬。作为一个R新手,想一想   R作为您的银行帐户:过度使用$ -extraction会导致不良后果。这是最好的   早期获得'[['和'''习惯。

     

- Peter Ehlers(关于$ -extraction的使用)        R-help(2013年3月)

对于像fortunes::fortune(343)这样的更高级用法,你不需要引用列名等(并且可以评估表达式),dplyr包会使事情变得相对轻松并且具有非常好的插图。< / p>

基函数lazyeval可用于进行一些惰性求值,例如

with

with(mtcars, plot(disp, mpg)) # sometimes with is nice plot(mtcars$disp, mtcars$mpg) 最好以交互方式和简单的脚本使用。如果您开始编写程序化生产代码(例如,您自己的R包),则避免非标准评估会更安全。例如,参见with中的警告,这是另一个使用非标准评估的基本R函数。

答案 1 :(得分:0)

一般来说,功能不应该比需要了解更多。如果你编写一个需要data.frame的函数,当输入数据不是必须在data.frame中提供的时候,你就会使你的函数比它需要的更具限制性。

编写此函数的正确方法如下:

bmi <- function(height,weight) weight/height^2;

这将允许您从高度值向量和权重值向量计算BMI值向量,因为/^都是向量化操作。因此,例如,如果您有两个宽松和重量的宽松向量,那么您可以按如下方式调用它:

set.seed(1);
N <- 5;
height <- rnorm(N,1.7,0.2);
weight <- rnorm(N,65,4);
BMI <- bmi(height,weight);
height; weight; BMI;
## [1] 1.574709 1.736729 1.532874 2.019056 1.765902
## [1] 61.71813 66.94972 67.95330 67.30313 63.77845
## [1] 24.88926 22.19652 28.91995 16.50967 20.45224

如果你的输入包含在data.frame中,你就可以这样做:

set.seed(2);
N <- 5;
df <- data.frame(id=1:N, height=rnorm(N,1.7,0.2), weight=rnorm(N,65,4), gender=sample(c('M','F'),N,replace=T) );
df$BMI <- bmi(df$height,df$weight);
df;
##   id   height   weight gender      BMI
## 1  1 1.520617 65.52968      F 28.33990
## 2  2 1.736970 67.83182      M 22.48272
## 3  3 2.017569 64.04121      F 15.73268
## 4  4 1.473925 72.93790      M 33.57396
## 5  5 1.683950 64.44485      M 22.72637

答案 2 :(得分:0)

提供此答案是因为我无法在SO上找到它,并撞到墙上试图弄清楚为什么我的R包中的函数假定我的新列是对象而不是data.frame列。

如果某个函数采用data.frame,并且在该函数内您要添加和转换其他列,则这样做的方式如下:

example_func <- function(df) {
  # To add a new column
  df[["New.Column"]] <- value
  
  # To get the ith value of that column
  df[[i, "New.Column"]]

  # To subset set the df using some conditional logic on that column
  df[df[["New.Column"]]==value]

  # To sort on that column
  setorderv(df, "New.Column", -1)
}

请注意,这需要library(devtools)