如何为连续日期的每个夜间时段创建唯一 ID?
How do I create a unique ID for each night-time period across consecutive dates?
我连续几天连续收集数据。每个观察已经包含变量 datetime(一个 POSIXct 对象)和 par(一个数字对象)。我想创建一个名为 ID 的新变量,它将是与单个夜间时段关联的唯一编号。我将夜间定义为 par = 0 的所有观察值。下面连续 3 天给出了我希望我的数据看起来像的示例。
注意:我的实际数据是以 15 分钟为间隔获取的,但为了便于查看,我截断了此示例。
datetime par ID
1 2015-04-23 00:00:00 0.0 1
2 2015-04-23 08:00:00 0.0 1
3 2015-04-23 12:00:00 817.7 0
4 2015-04-23 19:00:00 0.0 2
5 2015-04-24 00:00:00 0.0 2
6 2015-04-24 08:00:00 0.0 2
7 2015-04-24 12:00:00 269.9 0
8 2015-04-24 19:00:00 0.0 3
9 2015-04-25 00:00:00 0.0 3
10 2015-04-25 08:00:00 0.0 3
11 2015-04-25 12:00:00 1701.8 0
12 2015-04-25 19:00:00 0.0 4
13 2015-04-25 23:00:00 0.0 4
我希望非夜间 (par !=0) 观察的 ID = 0。第一个夜间时段发生在 2015 年 4 月 23 日,所以我希望它的 ID = 1。然后我想添加1 到每个随后的夜间时段 ID。
有什么想法吗?尽管付出了很多努力,但我仍无法实现上述结果。提前谢谢你。
几种方法,都采用运行-length-encoding
data.table
这利用了时间段按日期分组的事实,因此我们可以使用 运行-length-encoding 对同一日期的值进行分组。然后任何带有 par > 0
的东西都可以设置为 0。
library(data.table)
setDT(df)
## explicitly ordering the data.table
df[order(datetime), ID := rleid(as.Date(datetime))][ par > 0, ID := 0]
df
# datetime par ID
# 1: 2015-04-23 00:00:00 0.0 1
# 2: 2015-04-23 08:00:00 0.0 1
# 3: 2015-04-23 12:00:00 817.7 0
# 4: 2015-04-23 19:00:00 0.0 2
# 5: 2015-04-24 00:00:00 0.0 2
# 6: 2015-04-24 08:00:00 0.0 2
# 7: 2015-04-24 12:00:00 269.9 0
# 8: 2015-04-24 19:00:00 0.0 3
# 9: 2015-04-25 00:00:00 0.0 3
# 10: 2015-04-25 08:00:00 0.0 3
# 11: 2015-04-25 12:00:00 1701.8 0
# 12: 2015-04-25 19:00:00 0.0 4
# 13: 2015-04-25 23:00:00 0.0 4
(这是我的首选解决方案,因为它可以处理任何日期,正确排序数据,而且效率很高,因为,你知道,data.table...)
基地
如果'night time period'总是被'daytime'句点隔开,那么你也可以这样做
## create an ID column set the 'daytime' periods to 0
df[ df$par != 0, "ID"] <- 0
## get the run-length-encoding of the ID column
r <- rle(is.na(df$ID))
## the length of the rle where the value is TRUE gives us teh number of NAs in each 'group', so we can replicate the rle value by that amount
rep(1:length(r$lengths[r$values]), r$length[r$values])
# [1] 1 1 2 2 2 3 3 3 4 4
## so you can fill the rest of hte column with these values
df[ df$par == 0, "ID"] <- rep(1:length(r$lengths[r$values]), r$length[r$values])
df
# datetime par ID
# 1 2015-04-23 00:00:00 0.0 1
# 2 2015-04-23 08:00:00 0.0 1
# 3 2015-04-23 12:00:00 817.7 0
# 4 2015-04-23 19:00:00 0.0 2
# 5 2015-04-24 00:00:00 0.0 2
# 6 2015-04-24 08:00:00 0.0 2
# 7 2015-04-24 12:00:00 269.9 0
# 8 2015-04-24 19:00:00 0.0 3
# 9 2015-04-25 00:00:00 0.0 3
# 10 2015-04-25 08:00:00 0.0 3
# 11 2015-04-25 12:00:00 1701.8 0
# 12 2015-04-25 19:00:00 0.0 4
# 13 2015-04-25 23:00:00 0.0 4
与cumsum
:
df$ID2 <- 0
sel <- df$par == 0
df$ID2[sel] <- cumsum(!sel)[sel] + 1
# par ID ID2
#1 0.0 1 1
#2 0.0 1 1
#3 817.7 0 0
#4 0.0 2 2
#5 0.0 2 2
#6 0.0 2 2
#7 269.9 0 0
#8 0.0 3 3
#9 0.0 3 3
#10 0.0 3 3
#11 1701.8 0 0
#12 0.0 4 4
#13 0.0 4 4
我会首先将您的 POSIXct
日期转换为 POSIXlt
日期,因为这些日期具有可以更轻松地确定诸如天数之类的属性。
df[["datetime"]] <- as.POSIXlt(df[["datetime"]])
然后我们可以使用字段 yday
和 hour
来获取一个数值,其中 24 小时内中午之后的任何值都具有相同的值。这仅在您所有时间都在同一年时才有效。否则,您将不得不使用 year
属性来调整天数。
indicator <- df[["datetime"]][["yday"]] + (df[["datetime"]][["hour"]] > 12)
使用因子水平,我们可以得到从 1 开始的订单号。
df[["ID"]] <- as.numeric(as.factor(indicator))
然后我们可以将所有day
个周期设置为0
。
df[["ID"]][df[["par"]] != 0] <- 0
如果需要,可以分两行完成。
df[["ID"]] <- as.numeric(as.factor(df[["datetime"]][["yday"]] +
(df[["datetime"]][["hour"]] > 12)))
df[["ID"]][df[["par"]] != 0] <- 0
无论您的数据采用何种顺序,此解决方案都适用。
我连续几天连续收集数据。每个观察已经包含变量 datetime(一个 POSIXct 对象)和 par(一个数字对象)。我想创建一个名为 ID 的新变量,它将是与单个夜间时段关联的唯一编号。我将夜间定义为 par = 0 的所有观察值。下面连续 3 天给出了我希望我的数据看起来像的示例。
注意:我的实际数据是以 15 分钟为间隔获取的,但为了便于查看,我截断了此示例。
datetime par ID
1 2015-04-23 00:00:00 0.0 1
2 2015-04-23 08:00:00 0.0 1
3 2015-04-23 12:00:00 817.7 0
4 2015-04-23 19:00:00 0.0 2
5 2015-04-24 00:00:00 0.0 2
6 2015-04-24 08:00:00 0.0 2
7 2015-04-24 12:00:00 269.9 0
8 2015-04-24 19:00:00 0.0 3
9 2015-04-25 00:00:00 0.0 3
10 2015-04-25 08:00:00 0.0 3
11 2015-04-25 12:00:00 1701.8 0
12 2015-04-25 19:00:00 0.0 4
13 2015-04-25 23:00:00 0.0 4
我希望非夜间 (par !=0) 观察的 ID = 0。第一个夜间时段发生在 2015 年 4 月 23 日,所以我希望它的 ID = 1。然后我想添加1 到每个随后的夜间时段 ID。
有什么想法吗?尽管付出了很多努力,但我仍无法实现上述结果。提前谢谢你。
几种方法,都采用运行-length-encoding
data.table
这利用了时间段按日期分组的事实,因此我们可以使用 运行-length-encoding 对同一日期的值进行分组。然后任何带有 par > 0
的东西都可以设置为 0。
library(data.table)
setDT(df)
## explicitly ordering the data.table
df[order(datetime), ID := rleid(as.Date(datetime))][ par > 0, ID := 0]
df
# datetime par ID
# 1: 2015-04-23 00:00:00 0.0 1
# 2: 2015-04-23 08:00:00 0.0 1
# 3: 2015-04-23 12:00:00 817.7 0
# 4: 2015-04-23 19:00:00 0.0 2
# 5: 2015-04-24 00:00:00 0.0 2
# 6: 2015-04-24 08:00:00 0.0 2
# 7: 2015-04-24 12:00:00 269.9 0
# 8: 2015-04-24 19:00:00 0.0 3
# 9: 2015-04-25 00:00:00 0.0 3
# 10: 2015-04-25 08:00:00 0.0 3
# 11: 2015-04-25 12:00:00 1701.8 0
# 12: 2015-04-25 19:00:00 0.0 4
# 13: 2015-04-25 23:00:00 0.0 4
(这是我的首选解决方案,因为它可以处理任何日期,正确排序数据,而且效率很高,因为,你知道,data.table...)
基地
如果'night time period'总是被'daytime'句点隔开,那么你也可以这样做
## create an ID column set the 'daytime' periods to 0
df[ df$par != 0, "ID"] <- 0
## get the run-length-encoding of the ID column
r <- rle(is.na(df$ID))
## the length of the rle where the value is TRUE gives us teh number of NAs in each 'group', so we can replicate the rle value by that amount
rep(1:length(r$lengths[r$values]), r$length[r$values])
# [1] 1 1 2 2 2 3 3 3 4 4
## so you can fill the rest of hte column with these values
df[ df$par == 0, "ID"] <- rep(1:length(r$lengths[r$values]), r$length[r$values])
df
# datetime par ID
# 1 2015-04-23 00:00:00 0.0 1
# 2 2015-04-23 08:00:00 0.0 1
# 3 2015-04-23 12:00:00 817.7 0
# 4 2015-04-23 19:00:00 0.0 2
# 5 2015-04-24 00:00:00 0.0 2
# 6 2015-04-24 08:00:00 0.0 2
# 7 2015-04-24 12:00:00 269.9 0
# 8 2015-04-24 19:00:00 0.0 3
# 9 2015-04-25 00:00:00 0.0 3
# 10 2015-04-25 08:00:00 0.0 3
# 11 2015-04-25 12:00:00 1701.8 0
# 12 2015-04-25 19:00:00 0.0 4
# 13 2015-04-25 23:00:00 0.0 4
与cumsum
:
df$ID2 <- 0
sel <- df$par == 0
df$ID2[sel] <- cumsum(!sel)[sel] + 1
# par ID ID2
#1 0.0 1 1
#2 0.0 1 1
#3 817.7 0 0
#4 0.0 2 2
#5 0.0 2 2
#6 0.0 2 2
#7 269.9 0 0
#8 0.0 3 3
#9 0.0 3 3
#10 0.0 3 3
#11 1701.8 0 0
#12 0.0 4 4
#13 0.0 4 4
我会首先将您的 POSIXct
日期转换为 POSIXlt
日期,因为这些日期具有可以更轻松地确定诸如天数之类的属性。
df[["datetime"]] <- as.POSIXlt(df[["datetime"]])
然后我们可以使用字段 yday
和 hour
来获取一个数值,其中 24 小时内中午之后的任何值都具有相同的值。这仅在您所有时间都在同一年时才有效。否则,您将不得不使用 year
属性来调整天数。
indicator <- df[["datetime"]][["yday"]] + (df[["datetime"]][["hour"]] > 12)
使用因子水平,我们可以得到从 1 开始的订单号。
df[["ID"]] <- as.numeric(as.factor(indicator))
然后我们可以将所有day
个周期设置为0
。
df[["ID"]][df[["par"]] != 0] <- 0
如果需要,可以分两行完成。
df[["ID"]] <- as.numeric(as.factor(df[["datetime"]][["yday"]] +
(df[["datetime"]][["hour"]] > 12)))
df[["ID"]][df[["par"]] != 0] <- 0
无论您的数据采用何种顺序,此解决方案都适用。