【问题标题】:IF statements in R - Always nested?R中的IF语句 - 总是嵌套?
【发布时间】:2012-01-22 17:00:24
【问题描述】:

我现在才开始深入研究R 中的IF 语句。从我从CRAN documentation on IF statements 中看到的,看起来所有IF 语句都必须是nested

这是真的吗?如果是,这个IF/THEN 结构更像EXCEL,而且我认为不像RUBYPython IF/THEN 逻辑那么简单。我没有打断这个正确吗?

EXCEL(gui,而不是VBA)中,您必须运行这样的公式:

#IF Statement 1
=IF(A1<20, A1*1, 
#IF Statement 2
IF(A1<50, A1*2,
#IF Statement 3
IF(A1<100, A1*3, A1*4)
#Closes IF Statement 2
)
#Closes IF Statement 1
) 

Nested IF/THEN 很复杂,因为您必须确保正确关闭函数。

下一部分 - 我不是 100% 确定,因为我是这两种语言的初学者,但是...在 RubyPython,您可以在更多结构化方式:

IF 
ELSE
END

这更加简单和明确。

我错过了在 R 中运行它的正确方法,还是有那么复杂?在 IF/THEN/Loop for R 上是否有我还没有找到的好资源?

谢谢

【问题讨论】:

  • 作为旁注,对于您给出的示例,您最好完全避免使用if 语句,并使用x * as.numeric(cut(x, c(-Inf, 20, 50, 100, Inf))) 之类的东西。
  • 或(为了可读性和灵活性稍微重新排列)categ &lt;- cut(x,c(-Inf,20,50,100,Inf)); x &lt;- x*(1:4)[categ]

标签: excel r if-statement nested


【解决方案1】:

R 中实际上有两种形式的if-else 流控制逻辑。

if 语句大致上类似于 C、C++ 或 Java 的if。就像在那些语言中一样,您可以按顺序链接ifs。

if(test) {
    statements
}
else if(test2) {
    statements
}
else {
    statements
}

R 也有ifelse 函数,这确实很像Excel 的=IF。上面 if-elseif-else 的大致等价物是

ifelse(test, result1, ifelse(test2, result2, result3))

关键区别在于,在第二个示例中,testresult1result2result3 都是向量。

如果您想对整个数据集执行相同 组操作,则应该使用第一个,但哪个 组取决于测试。第二个用于向量化计算,您希望对向量的每个元素执行不同的操作。

【讨论】:

  • 只是为了使事情复杂化(或简化!),R 的if 也是一个函数。例如,您可以写x &lt;- if(a &lt; b) 1 else 2,而不是if(a &lt; b) x &lt;- 1 else x &lt;- 2。但这与问题无关。
【解决方案2】:

许多 R 的新用户对if 感到困惑。它只计算一个值,然后执行后面的表达式或else 子句。在 R 中,ifelse 函数通常是以前的 SAS、Excel 和 SPSS 用户想要的,它支持嵌套。 switch 函数在某些情况下可能会有所帮助,尽管我看不出您的一组非排他逻辑条件如何立即适合其逻辑。

在您的情况下,我会考虑使用 findInterval 函数。这将在您的示例中完成逻辑和数学运算的组合运算(如果“A”是向量,则返回向量):

A*( 1+ findInterval( A, c(20,50,100) )  )  # OR 
A*( 1+ findInterval( A, c(-Inf, 20, 50, 100) )  ) # the equivalent using -Inf

再想一想findInterval 函数也可以用作switch 的第一个参数,如果您想将函数应用于“A”。

(进一步评论:我假设您的“A1”表达式将被复制到 Excel 电子表格中的一列或一行单元格中,并在此过程中以 Excel 支持的特定自动方式递增行或列引用成为 A2、A3 等。这是与您要比较的任何更通用语言不同的编程视角。对 R 向量的操作是类似的,但通常不需要“1”、“2”、“3” .. . 条目,所以我从代码中省略了它们。)

【讨论】:

  • 非常方便。可以与match 类似地用作索引策略。另一种矢量化方法是使用cut,但这会变得非常混乱。
【解决方案3】:

我不确定我是否理解这个问题,但是您的 Excel 代码的自然 R 等效项是

if (a1 < 20)
  a1 * 1
else if (a1 < 50)
  a1 * 2
else if (a1 < 100)
  a1 * 3
else
  a1 * 4

如果你愿意,你可以在a1 * n 表达式周围加上花括号。但是,如果a1 是一个向量而不是一个标量,您可能希望并行评估所有向量元素的比较,这是使用ifelse 完成的,它确实 像 Excel 构造一样嵌套:

ifelse(a1 < 20, a1 * 1,
       ifelse(a1 < 50, a1 * 2,
              ifelse(a1 < 100, a1 * 3,
                               a1 * 4)))

第三种写法,向量a1,利用逻辑索引:

a2 <- a1 # take a copy
a2[a1 >=  20 & a1 <  50] <- a1[a1 >=  20 & a1 <  50] * 2
a2[a1 >=  50 & a1 < 100] <- a1[a1 >=  50 & a1 < 100] * 3
a2[a1 >= 100           ] <- a1[a1 >= 100           ] * 4

【讨论】:

  • 我会解释这一点,如果我错了,请告诉我,ifelseelseelse 是更好的方法,而不是ifelse 方法。 ifelse 方法看起来非常嵌套,正如我在问题中解释(或尝试)的那样,处理起来很痛苦。这个比那个好吗?谢谢
  • 你要哪一个取决于a1的内容。如果它是标量,是的,使用更易于阅读的if-else if 链。但是,如果它是 vector,您可能需要 ifelse 的逐个元素评估。我将用第三种方式进行编辑,在某些方面更符合 R 语言习惯。
  • 你是对的,第三种方式通常被称为“优雅的 R 风格”,但如果我告诉我的学生,他们会笑话我,而且是有道理的。我必须先复制一份,然后在左侧和右侧重复相同的条件(您检查了吗???),这是非 R 程序员世界中不良风格的一个例子。已经对数据帧(变换,plyr)进行了一些尝试,但总的来说我认为这很丑陋。躲起来就跑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-17
  • 1970-01-01
  • 1970-01-01
  • 2012-06-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-06
相关资源
最近更新 更多