如何在r中编写函数对记录进行计算?

如何在r中编写函数对记录进行计算?,r,if-statement,vectorization,R,If Statement,Vectorization,在C#中,我习惯了数据集和当前记录的概念。 对我来说,编写一个复杂的计算价格函数是很容易的,其中包含当前记录上的条件 我很难理解如何在r中这样做 我尝试了以下方法 train <- read.csv("Train.csv" ) df <- as.data.frame.matrix(train) v = c( df$Fuel.Type ,df$No.Gears) names(v ) <- c( "FuelType"

在C#中,我习惯了数据集和当前记录的概念。 对我来说,编写一个复杂的计算价格函数是很容易的,其中包含当前记录上的条件

我很难理解如何在r中这样做

我尝试了以下方法

   train <- read.csv("Train.csv" )
   df <- as.data.frame.matrix(train)
   v = c(  df$Fuel.Type ,df$No.Gears)
   names(v ) <- c( "FuelType" ,"NoGears")
   df$FEType = FEType( v)
将具有向我的数据框中添加一列的效果,该列具有计算的isPretty属性


为什么我不能在计算中包含if条件?

矢量化是在R中需要习惯的最基本(也是最不寻常)的事情之一。许多(大多数?)R操作都是矢量化的。但是有一些东西不是,而
if(){}else{}
是一种非矢量化的东西。它用于控制流(是否运行代码块),而不是向量操作
ifelse()
是一个单独的函数,用于向量,其中第一个参数是“test”,第二个和第三个参数是“if yes”和“if no”结果。测试是一个向量,返回的值是测试中每个项目的适当是/否结果。结果将与测试长度相同

因此,我们将像这样编写您的
IsPretty
函数:

IsPretty <- function(PetalWidth){
  return(ifelse(PetalWidth > 0.3, "Y", "N"))
}

df <- iris
df$Pretty = IsPretty(df$Petal.Width)
下面的基准测试表明,矢量化版本的速度快了50倍。这是一个如此简单的情况,数据如此之小,以至于无关紧要,但是对于较大的数据,或者对于更复杂的操作,矢量化代码和非矢量化代码之间的差异可能是几分钟而不是几天

microbenchmark::microbenchmark(
  loop = {
    for(i in 1:nrow(df)) {
      df$PrettyLoop[i] = IsPrettyIf(df$Petal.Width[i])
    }
  },
  vectorized = {
    df$Pretty = IsPretty(df$Petal.Width)    
  }
)
Unit: microseconds
       expr    min     lq     mean median      uq     max neval
       loop 3898.9 4365.6 5880.623 5442.3 7041.10 11344.6   100
 vectorized   47.7   59.6  112.288   67.4   83.85  1819.4   100
对于R学习者来说,这是一个常见的问题-您可以发现许多关于堆栈溢出的问题,人们在需要
ifelse()
时使用
if(){}else{}
,反之亦然。是来自问题另一面的常见问题


你的尝试是怎么回事?
df0.3
#>[1]假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假假
#>[13]假假假真假假假真假假真
## ... 截断的
##R警告我们只使用第一个值(恰好为FALSE)
结果=如果(df$Petal.Width>0.3){“Y”}否则{“N”}
#>if(df$Petal.Width>0.3)中的警告{:条件的长度大于1且仅为
#>将使用第一个元素
##结果是一个“N”
后果
#>[1]“N”
长度(结果)
#> [1] 1
##R“回收”长度不足的输入
##所以我们得到了一整列的“N”
df$Pretty=结果
头部(df)
#>萼片。长萼片。宽花瓣。长花瓣。宽种美丽
#>1 5.1 3.5 1.4 0.2刚毛
#>2 4.9 3.0 1.4 0.2刚毛
#>3 4.7 3.2 1.3 0.2刚毛
#>4.6 3.1 1.5 0.2刚毛
#>5.0 3.6 1.4 0.2刚毛
#>6 5.4 3.9 1.7 0.4刚毛

由(v0.3.0)于2020年11月8日创建,用于我自己对Gregor答案的注释

IsPrettyIf <-function(row){
 ret ="N"  
 if(row$Petal.Width > 0.3) { ret="Y"}
 return(ret)
}

 
df <- iris
df$PrettyLoop ="" # add a column and initialize all the cells to be empty
for(i in 1:5) {
  df$PrettyLoop[i] = IsPrettyIf(df[i,])
  cat("Row",i, "is Pretty?",df$PrettyLoop[i],"\n")
}
IsPrettyIf 0.3){ret=“Y”}
返回(ret)
}

df还注意到,您得到的是警告,而不是错误。错误将停止代码的执行。一个警告是R说某些东西似乎不规则,并要求您检查以确保它是正确的-但代码确实执行。我的问题的答案是我不能编写一个函数来对单个记录进行计算吗?我需要同时考虑所有的记录吗?您应该尝试编写一次处理
n
记录的向量化函数,其中
n
为1或更多。在大多数情况下,这是可能的,R使它相对容易和高效。您可以编写对单个记录进行操作的函数-这正是您所做的。但是您需要在单个记录上调用这样的函数,就像我在
for
循环示例中所显示的那样。错误结果的原因是您编写了一个函数来对单个记录进行操作,但随后您将所有记录作为参数传递-
IsPretty(df$Petal.Width)
正在对所有Petal-Width记录调用
IsPretty
。您的问题中有一个
库(dplyr)
调用,尽管您没有使用任何
dplyr
函数。这是一个按组应用函数的优秀软件包-功能非常强大。有些函数无法矢量化-如果
i
th计算以一种非常简单的方式依赖于
i-1
th结果,那么您最终需要使用
for
循环并一次操作一条记录。但是,在大多数主题领域,这些任务相对较少且相差甚远。
row$PrettyLoop
是一个列-它只需要是一行数据帧的一列,就像编写函数一样,因此它也是一个单元格。如果您想使用这样的函数而不是矢量化函数,那么最好添加一个输入检查,比如
If(nrow(row)>1)stop(“输入应该只有一行!”)
IsPretty <- function(PetalWidth){
  return(ifelse(PetalWidth > 0.3, "Y", "N"))
}

df <- iris
df$Pretty = IsPretty(df$Petal.Width)
IsPrettyIf <-function(PetalWidth){
  if (PetalWidth  >0.3) return("Y")
  return("N")
}

for(i in 1:nrow(df)) {
  df$PrettyLoop[i] = IsPrettyIf(df$Petal.Width[i])
}
microbenchmark::microbenchmark(
  loop = {
    for(i in 1:nrow(df)) {
      df$PrettyLoop[i] = IsPrettyIf(df$Petal.Width[i])
    }
  },
  vectorized = {
    df$Pretty = IsPretty(df$Petal.Width)    
  }
)
Unit: microseconds
       expr    min     lq     mean median      uq     max neval
       loop 3898.9 4365.6 5880.623 5442.3 7041.10 11344.6   100
 vectorized   47.7   59.6  112.288   67.4   83.85  1819.4   100
IsPrettyIf <-function(row){
 ret ="N"  
 if(row$Petal.Width > 0.3) { ret="Y"}
 return(ret)
}

 
df <- iris
df$PrettyLoop ="" # add a column and initialize all the cells to be empty
for(i in 1:5) {
  df$PrettyLoop[i] = IsPrettyIf(df[i,])
  cat("Row",i, "is Pretty?",df$PrettyLoop[i],"\n")
}