【问题标题】:Function with multiple conditions if, else or ifelse具有多个条件 if、else 或 ifelse 的函数
【发布时间】:2020-10-17 15:13:23
【问题描述】:

我正在处理潜水行为,然后我有一个函数可以在数据框中创建一个新列,其中包含每次潜水的太阳角度的表盘相位(白天、黎明、夜晚和黄昏),但显然它们的条件是重叠的彼此。我的真实数据框有超过 90.000 行

(1) 日出时,黎明时太阳高程为 -12 至 +6 度,相对于地平线,(2) 黄昏时太阳高程为 +6 至 -12 度,日落时。 (3) 大于+6度时确定白天,(4)小于-12度时确定夜晚。

dt = data.table(localtime= c("2016-10-24 12:45:06", "2016-10-24 12:46:13", "2016-10-24 12:47:02", "2016-10-24 12:48:27", "2016-10-24 12:52:39", "2016-10-24 12:55:11", "2016-10-30 21:08:02", "2016-10-30 21:18:27", "2016-10-30 21:30:13","2016-10-24 23:27:21", "2016-10-26 06:54:29"),
                lon = c(-39.94400, -39.94410, -39.94418, -39.94432, -39.94472, -39.94496, -40.87705, -40.87567, -40.87409, -40.00234, -40.59864),
DepthMean = 30, 50, 200, 76, 467, 87, 98, 10, 240, 176, 89))
dialphase <- function(df) {
  #loading the necessary package
  require(oce)
  
  #getting the sun angle from local time, longitude and latitude by the correction for atmospheric refraction
  x2<-sunAngle(df$localtime, df$lon, df$lon, useRefraction = TRUE)
  
  #converting into data.frame
  x3<-do.call(rbind, lapply(x2$altitude, as.data.frame))
  
  #creating new colum with the sun angles
  df$sun<- x3$`X[[i]]`
  
  #creating new column with only by hour about local time to do the next conditions
  df$hourBRT <- as.POSIXlt(df$localtime)$hour
  df <- df[!is.na(df$hourBRT),]
  
  #creating new column with dial phases by sun angles and hours with day, dawn, night and dusk
  df$dial_phase[df$sun >= 6.0] <- "day" 
  
  df$dial_phase[df$sun  < 6.0 & df$sun > -12.0 & df$hourBRT > 3] <- "dawn" #manhã
  
  df$dial_phase[df$sun <= -12.0] <- "night"
  
  df$dial_phase[df$sun < 6.0 & df$sun > -12.0 & df$hourBRT > 16 ] <- "dusk" #noite
  
  df$hourBRT<-NULL
  return(df)
}

我预料到了:

dt
              localtime       lon     DepthMean       dial_phase
 1: 2016-10-24 12:45:06 -39.94400        30             day
 2: 2016-10-24 12:46:13 -39.94410        50             day
 3: 2016-10-24 12:47:02 -39.94418        200            day
 4: 2016-10-24 12:48:27 -39.94432        76             day
 5: 2016-10-24 12:52:39 -39.94472        467            day
 6: 2016-10-24 12:55:11 -39.94496        87             day
 7: 2016-10-30 21:08:02 -40.87705        98             dusk
 8: 2016-10-30 21:18:27 -40.87567        10             dusk
 9: 2016-10-30 21:30:13 -40.87409        240            dusk
10: 2016-10-24 23:27:21 -40.00234        176            night
11: 2016-10-26 06:54:29 -40.59864        89             dawn
> 

我的猜测是因为使用ifelseifelse 时该功能会正常工作,我对吗?我没有使用这些代码执行功能的能力。有人可以帮忙吗?

我试过这个东西,但是缺少一个阶段

> f1<-function(df) {
+   #loading the necessary package
+   require(oce)
+   
+   #getting the sun angle from local time, longitude and latitude by the correction for atmospheric refraction
+   x2<-sunAngle(df$localtime, df$lon, df$lon, useRefraction = TRUE)
+   
+   #converting into data.frame
+   x3<-do.call(rbind, lapply(x2$altitude, as.data.frame))
+   
+   #creating new colum with the sun angles
+   df$sun<- x3$`X[[i]]`
+   
+   #creating new column with only by hour about local time to do the next conditions
+   df$hourBRT <- as.POSIXlt(df$localtime)$hour
+   df <- df[!is.na(df$hourBRT),]
+   df$dial_phase <- with(df, ifelse(sun >= 6.0, "day", 
+                                    ifelse(sun  < 6.0 & sun > -12.0 & hourBRT > 3, "dawn", 
+                                           ifelse(sun <= -12.0, "night",
+                                                  ifelse(sun < 6.0 & sun > -12.0 & hourBRT > 16 , "dusk", NA_character_)))))
+   df
+ }
> g<-f1(df)
> table(df$dial_phase) ### dusk is missing 

 dawn   day night 
12185 46276 33593 

** 编辑 **

我猜我的功能不行,因为当我绘图时,表盘相位重叠,像这样:

df$hourBRT <- as.POSIXlt(df$localtime)$hour
df <- df[!is.na(df$hourBRT),]
ggplot(df, aes(as.factor(hourBRT), DepthMean, col = dial_phase)) + 
  geom_boxplot() +
  scale_y_log10(breaks = c(10, 50, 100, 200, 300, 400, 500, 600)) +
  xlab("Hour of the day") +
  ylab("Depth of Dives (m)")

谢谢!

【问题讨论】:

  • 请展示一个可重现的小例子
  • 我试试,等一下
  • 在最后一部分中,您没有更新 with(df, ... 并且在此之前返回了原始 'df'
  • 我在下面发布了一个解决方案。由于没有数据,我无法测试它,但我猜它的方向是正确的
  • 我编辑了帖子,请看看df是否有效

标签: r function if-statement conditional-statements


【解决方案1】:

使用您提供的示例,如果您将函数 f1() 定义如下:

f1<-function(df) {
   #loading the necessary package
   require(oce)
   
  #getting the sun angle from local time, longitude and latitude by the correction for atmospheric refraction
  df$sun <- sunAngle(df$localtime, df$lon, df$lon, useRefraction = TRUE)$altitude
  #creating new column with only by hour about local time to do the next conditions
  df$hourBRT <- as.POSIXlt(df$localtime)$hour
  df <- df[!is.na(df$hourBRT),]

   df$dial_phase <- with(df, ifelse(sun >= 6.0, "day", 
                                    ifelse(sun <= -12.0, "night",
                                           ifelse((sun  < 6.0 & sun > -12.0) & (hourBRT > 3 & hourBRT < 16), "dawn", "dusk")
                                           )
                                    )
                         )
 return(df)
}

您将获得与使用函数dialphase() 相同的结果:

> dialphase(dt)
Loading required package: oce
Loading required package: gsw
Loading required package: testthat
              localtime       lon         sun dial_phase
 1: 2016-10-24 12:45:06 -39.94400  54.5839409        day
 2: 2016-10-24 12:46:13 -39.94410  54.7343935        day
 3: 2016-10-24 12:47:02 -39.94418  54.8437520        day
 4: 2016-10-24 12:48:27 -39.94432  55.0321025        day
 5: 2016-10-24 12:52:39 -39.94472  55.5801854        day
 6: 2016-10-24 12:55:11 -39.94496  55.9030545        day
 7: 2016-10-30 21:08:02 -40.87705   2.0214448       dusk
 8: 2016-10-30 21:18:27 -40.87567   0.4274248       dusk
 9: 2016-10-30 21:30:13 -40.87409  -2.2624818       dusk
10: 2016-10-24 23:27:21 -40.00234 -23.6748247      night
11: 2016-10-26 06:54:29 -40.59864  -8.4538891       dawn
> f1(dt)
              localtime       lon         sun hourBRT dial_phase
 1: 2016-10-24 12:45:06 -39.94400  54.5839409      12        day
 2: 2016-10-24 12:46:13 -39.94410  54.7343935      12        day
 3: 2016-10-24 12:47:02 -39.94418  54.8437520      12        day
 4: 2016-10-24 12:48:27 -39.94432  55.0321025      12        day
 5: 2016-10-24 12:52:39 -39.94472  55.5801854      12        day
 6: 2016-10-24 12:55:11 -39.94496  55.9030545      12        day
 7: 2016-10-30 21:08:02 -40.87705   2.0214448      21       dusk
 8: 2016-10-30 21:18:27 -40.87567   0.4274248      21       dusk
 9: 2016-10-30 21:30:13 -40.87409  -2.2624818      21       dusk
10: 2016-10-24 23:27:21 -40.00234 -23.6748247      23      night
11: 2016-10-26 06:54:29 -40.59864  -8.4538891       6       dawn

结果不一样,因为一旦你的变量 hourBRT 大于 3,dawn 的条件就满足了,所以就不需要评估 黄昏。

话虽如此,我宁愿使用dialphase() 中的原始代码,也不愿使用f1() 中的嵌套ifelse 结构。后者的可读性显然更差,更容易出错。在这方面,您可能会发现以下阅读内容很有趣:https://medium.com/edge-coders/coding-tip-try-to-code-without-if-statements-d06799eed231

【讨论】:

  • 那么,如果我理解正确的话,原来的功能更好,我需要改变条件吗?删除变量hourBRT 以评估dusk,像这样? df$dial_phase[df$sun &lt; 6.0 &amp; df$sun &gt; -12.0 &amp; df$hourBRT &gt; 3] &lt;- "dawn", df$dial_phase[df$sun &lt; 6.0 &amp; df$sun &gt; -12.0 ] &lt;- "dusk" 。如果我这样做,黎明就不见了
  • 没有。我的意思是函数f1() 不能像dialphase() 那样工作,因为当您为变量hourBRT 提供条件时出现错误。然后我给了你我的意见:在你的情况下,dialphase()(没有修改)比f1()更易读,更不容易出错,因为没有嵌套的 ifelses (但这只是我的观点)。我假设您的函数dialpahse() 完成了您希望它完成的工作而没有任何错误;如果不是这样,请尝试更清楚地向我们解释实际问题是什么
  • 啊好吧!我现在知道了!谢谢!我编辑了我的帖子,添加了另一个变量DepthMean(它的潜水行为,这个函数为每次潜水和位置创建拨号阶段)和图表代码(来自我的原始数据,而不是来自这里的示例)和结果那。使用这个DepthMean 变量,您还可以绘制它。
  • 三个后续问题:1)DepthMean如何计算; 2) 您是否尝试从我的解决方案中测试函数f1() 来绘制图表? 3)如果是这样,它会改变什么吗?在您的图表中,您使用的功能似乎不适用于某些情况......
  • 1) DepthMean 来自卫星轨道原始数据。 2) 是的,发生同样的事情.. 3) 是的,这正是问题所在,它们是重叠的,我不知道是因为代码还是条件,因此我认为 if else 更好,并且等等。
猜你喜欢
  • 1970-01-01
  • 2020-05-31
  • 1970-01-01
  • 2015-10-24
  • 1970-01-01
  • 2019-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多