无循环R中的条件标签

无循环R中的条件标签,r,R,我试图找出最好的(性能最好的)数据框架形式,在一年中的四个季节中的每一个都有一个名为“季节”的新列: 一年一度的星期一 1 1 1 2010 2 1 1 2010 3 1 1 2010 4 1 1 2010 5 1 1 2010 6 1 1 2010 一个简单的方法是创建一个以MON和DAY列为条件的循环,并逐个赋值,但我认为有更好的方法。我在其他帖子上看到过关于ifelse或:=或apply的建议,但大多数问题都是二进制的,或者可以根据参数根

我试图找出最好的(性能最好的)数据框架形式,在一年中的四个季节中的每一个都有一个名为“季节”的新列:

一年一度的星期一
1   1   1 2010
2   1   1 2010
3   1   1 2010
4   1   1 2010
5   1   1 2010
6   1   1 2010

一个简单的方法是创建一个以MON和DAY列为条件的循环,并逐个赋值,但我认为有更好的方法。我在其他帖子上看到过关于
ifelse
:=
apply
的建议,但大多数问题都是二进制的,或者可以根据参数根据给定的单个函数f赋值


在我的情况下,我相信一个包含四个站标签的向量和某种程度上的条件就足够了,但我不知道如何把所有的东西放在一起。我的情况更像是一个开关箱

我先给出一个简单的答案,然后再深入研究细节。 我最快的方法是检查MON和DAY的值,并输出正确的季节。这是微不足道的:

f=function(m,d){
  if(m==12 && d>=21) i=3
  else if(m>9 || (m==9 && d>=21)) i=2
  else if(m>6 || (m==6 && d>=21)) i=1
  else if(m>3 || (m==3 && d>=21)) i=0
  else i=3
}
这个
f
函数,给定一天和一个月,将返回一个与季节对应的整数(不管是整数还是字符串,整数只允许节省一点内存,但这是一个技术性问题)。 现在,您希望将其应用于data.frame。不需要为此使用循环;我们将使用
mapply
d
将是我们的模拟数据.frame。我们将考虑产量以获得好的季节名称

d=data.frame(MON=rep(1:12,each=30),DAY=rep(1:30,12),YEAR=2012))
d$SEA=factor(
  mapply(f,d$MON,d$DAY),
  levels=0:3,
  labels=c("Spring","Summer","Autumn","Winter")
)
给你

我意识到季节并不总是在21世纪改变。如果需要微调,则应将三维数组定义为全局变量,以存储准确的天数。给定一个季节和一年,您可以访问相应的日期,并用正确的调用替换
f
函数中的“21”(您显然会为该年添加第三个参数)

关于你在问题中提到的事情:

  • ifelse
    是进行条件测试的“函数”方式。在原子变量上,它仅略优于条件语句,但它是矢量化的,这意味着如果参数是矢量,它将在其元素上循环自身。我不熟悉它,但这是获得优化解决方案的途径
  • mapply
    源于“
    apply
    系列”的
    sapply
    ,允许调用向量上带有多个参数的函数(请参见
    ?mapply
  • 我不认为
    :=
    是R中的标准运算符,这就引出了我的下一点:
  • 数据表
    !它是一个提供新结构的包,扩展了
    data.frame
    ,以实现快速计算和键入(以及其他功能)
    :=
    是该包中的运算符,允许定义新列。在我们的例子中,如果
    d
    是一个data.table,您可以编写
    d[,SEA:=mapply(f,MON,DAY)]

如果您真的关心性能,我就不能坚持使用
data.table
,因为如果您有大量数据,这将是一项重大改进。不过,我不知道我提出的解决方案是否真的会影响时间计算。

如果行数较大,使用模运算和算术运算符将逻辑值强制为0/1的事实将更加有效:

d$SEASON <- with(d,  c( "Winter","Spring", "Summer", "Autumn")[
                               1+(( (DAY>=21) + MON-1) %/% 3)%%4 ] )
d$seasure=21)+MON-1)%/%3)%%%4])

第一个添加的“1”将括号内所有结果的%%4运算范围从0:3移动到1:4。第二个减去的“1”将(内部)1:12范围移回0:11,
(DAY>=21)
将边界月份提前一个。

请注意问题的标题。这个季节的例子只是为了将其背景化。这个问题更一般。只需将MON、DAY、YEAR替换为其他列,以下链接上提供的解决方案将不再回答我的问题标题。.这里有几种备选方案:@BondedDust请阅读您上面的评论。@Oeufcoquepentean您可以嵌套
ifelse
以获得两个以上的结果。例如,请参见,链接中的第一个答案(我的答案)确实提供了多种结果的选项。这就是为什么我在这里提供它。您需要通过发布一个示例和所需结果的特定描述来澄清您的需求。如果您在一个包含数百行代码的数据集上尝试此操作,您将看到
ifelse
If(){}else{}
之间的性能差异很大。我没有意识到ifelse是矢量化的。我不熟悉它的用途。我将据此进行编辑。