R

时间:2018-12-13 23:13:26

标签: r dplyr data.table

我看到了在列之间使用lapply的示例,但没有人考虑(1)时间戳(2)基于时间戳的组(3)检测值何时更改

我正在寻找一种方法来对每个Panels SensorPanel 3等任意数量的Panel 4执行以下操作:

  • 对于每个yearmonthhour,我正在寻找sumCounts Turn On,它们是数值的#倍从0变为非零数字。为简化起见,hour开头的非零值不应计入该值(即使前一个值为0)也是如此。

使用df

cols <- c("Timestamp","1000 Sensor 2 Panel 1","1000 Sensor 2 Panel 2")
tstmp <- seq(as.POSIXct("2018-08-13 00:00:00", tz="US/Eastern"), 
             as.POSIXct("2018-08-13 03:30:00", tz="US/Eastern"), 
             by="15 min") %>% as.data.frame()
stage1 <- c(rep(c(0,.7,1),5)) %>% as.data.frame() 
stage2 <- c(0,1,rep(c(0,.5),5),0,1,1) %>% as.data.frame()

df = cbind(tstmp,stage1,stage2)
colnames(df) = cols

我希望结果为results_1

ID                      Year    Month   Hour    Sum     Count Turn On
1000 Sensor 2 Panel 1   2018        8   0       1.7         1
1000 Sensor 2 Panel 1   2018        8   1       2.4         1
1000 Sensor 2 Panel 1   2018        8   2       2.7         1
1000 Sensor 2 Panel 1   2018        8   3       1.7         1
1000 Sensor 2 Panel 2   2018        8   0       1.5         2
1000 Sensor 2 Panel 2   2018        8   1       1           2
1000 Sensor 2 Panel 2   2018        8   2       1           2
1000 Sensor 2 Panel 2   2018        8   3       2           1

对于更具野心的人,我希望看到一个解决方案,该解决方案能够确定前一小时的最后一个读数是否为0,而下一个小时的第一个读数是否为非零,并能够对其进行计数朝Count Turns On迈进–解决方案如下图所示,results_advanced

ID                      Year    Month   Hour    Sum     Count Turn On
1000 Sensor 2 Panel 1   2018        8   0       1.7         1
1000 Sensor 2 Panel 1   2018        8   1       2.4         2
1000 Sensor 2 Panel 1   2018        8   2       2.7         1
1000 Sensor 2 Panel 1   2018        8   3       1.7         1
1000 Sensor 2 Panel 2   2018        8   0       1.5         2
1000 Sensor 2 Panel 2   2018        8   1       1           2
1000 Sensor 2 Panel 2   2018        8   2       1           2
1000 Sensor 2 Panel 2   2018        8   3       2           1

我希望至少有一个results_1的解决方案,但希望为results_1results_advanced都提供解决方案。请提供您有关思考过程的任何详细信息,这将帮助我(和其他人)了解更多信息。

我相信同时有data.tabledplyr解决方案,因此我将同时对其进行标记。

1 个答案:

答案 0 :(得分:1)

这是第一个问题的tidyverse方法。希望您可以使用它来解决问题的第二部分。

首先,我们将wide to long中的数据与gather中的tidyr进行转换。我还删除了Timestamp变量,但这是可选的。

library(lubridate); library(tidyverse)

df_long <- df %>% 
  gather(ID, Val, -Timestamp)
head(df_long)
            Timestamp                    ID Val
1 2018-08-13 00:00:00 1000 Sensor 2 Panel 1 0.0
2 2018-08-13 00:15:00 1000 Sensor 2 Panel 1 0.7
3 2018-08-13 00:30:00 1000 Sensor 2 Panel 1 1.0
4 2018-08-13 00:45:00 1000 Sensor 2 Panel 1 0.0
5 2018-08-13 01:00:00 1000 Sensor 2 Panel 1 0.7
6 2018-08-13 01:15:00 1000 Sensor 2 Panel 1 1.0

df_long <- df_long %>% 
  mutate(Year = year(Timestamp),
         Month = month(Timestamp),
         Hour = hour(Timestamp)) %>% 
  select(-Timestamp)

然后我使用dplyr::group_bydplyr::lag计算打开次数,这使您可以访问以前的值。

df_long <- df_long %>% 
  group_by(ID, Year, Month, Hour) %>% 
  mutate(Turned = ifelse(lag(Val) == 0 & Val != 0, 1, 0))

然后仅使用dplyr::summarise计算最终值。注意,由于我们已经分组了,所以这部分的group_by语句是多余的,但是为了清楚起见,我将其保留在其中。

df_long %>% 
  group_by(ID, Year, Month, Hour) %>% 
  summarise(Sum = sum(Val),
            NTurned = sum(Turned, na.rm = T))

  ID                     Year Month  Hour   Sum NTurned
  <chr>                 <dbl> <dbl> <int> <dbl>   <dbl>
1 1000 Sensor 2 Panel 1  2018     8     0   1.7       1
2 1000 Sensor 2 Panel 1  2018     8     1   2.4       1
3 1000 Sensor 2 Panel 1  2018     8     2   2.7       1
4 1000 Sensor 2 Panel 1  2018     8     3   1.7       1
5 1000 Sensor 2 Panel 2  2018     8     0   1.5       2
6 1000 Sensor 2 Panel 2  2018     8     1   1         2
7 1000 Sensor 2 Panel 2  2018     8     2   1         2
8 1000 Sensor 2 Panel 2  2018     8     3   2         1