我有一个带有不规则日期列的数据集。我想创建一个索引列。对于三个不相似的连续日期,索引ID(例如1)是相同的,然后对于接下来的三个不同的连续日期改变(例如,改变为2),依此类推。以下是日期示例以及所需列的外观:
structure(list(Date = c(42370, 42371, 42371, 42371, 42372, 42372,
42375, 42375, 42375, 42377, 42377, 42383, 42383, 42385, 42386,
42386, 42386, 42393, 42393, 42394, 42394, 42395, 42398, 42398,
42398, 42398), Index = c(1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4)), .Names = c("Date",
"Index"), row.names = c(NA, 26L), class = "data.frame")
答案 0 :(得分:4)
使用rleid
包中的data.table
和cumsum
:
library(data.table)
setDT(d1)[, index := (rleid(Date)-1) %% 3
][, index := cumsum(index < shift(index, fill=1))][]
给出:
Date index
1: 01-01-16 1
2: 02-01-16 1
3: 02-01-16 1
4: 02-01-16 1
5: 03-01-16 1
6: 03-01-16 1
7: 06-01-16 2
8: 06-01-16 2
9: 06-01-16 2
10: 08-01-16 2
11: 08-01-16 2
12: 14-01-16 2
13: 14-01-16 2
14: 16-01-16 3
15: 17-01-16 3
16: 17-01-16 3
17: 17-01-16 3
18: 24-01-16 3
19: 24-01-16 3
20: 25-01-16 4
21: 25-01-16 4
22: 26-01-16 4
23: 29-01-16 4
24: 29-01-16 4
25: 29-01-16 4
26: 29-01-16 4
解释:
rleid
函数创建一个游程长度id。这意味着每次Date
更改时,游程长度ID都会增加1
。1
并获取其模数(%% 3
部分),您将获得0
,1
&amp; {的序列向量{1}}的。2
为index < shift(index, fill=1)
时,cumsum函数会将其计为一个。为了更好地了解此代码的作用,请参阅以下代码的输出,该代码为每个步骤创建变量:
TRUE
使用过的数据:
setDT(d1)[, index1 := (rleid(Date)-1) %% 3
][, index2 := cumsum(index1 < shift(index1, fill=1))][]
答案 1 :(得分:3)
这为Date的唯一值构造了一个3分组的索引,然后使用字符名来管理转换的查找表:
fac <- ((seq(length(unique(dat$Date)))-1) %/%3) +1
names(fac) <- unique(dat$Date)
dat$myIndex <- fac[as.character(dat$Date)]
dat
#-------
Date Index myIndex
1 42370 1 1
2 42371 1 1
3 42371 1 1
4 42371 1 1
5 42372 1 1
6 42372 1 1
7 42375 2 2
8 42375 2 2
9 42375 2 2
10 42377 2 2
11 42377 2 2
12 42383 2 2
13 42383 2 2
14 42385 3 3
15 42386 3 3
16 42386 3 3
17 42386 3 3
18 42393 3 3
19 42393 3 3
20 42394 4 4
21 42394 4 4
22 42395 4 4
23 42398 4 4
24 42398 4 4
25 42398 4 4
26 42398 4 4
答案 2 :(得分:3)
基础R。我们可以修改对象的rle
(游程编码)以对三个值进行分组:
DF$index = with(rle(DF$Date), {
g = ceiling(seq_along(values)/3)
split(values, g) <- seq(tail(g,1))
inverse.rle(list(lengths = lengths, values = values))
})
奇怪的split(x,g) <-
位来自ave
。如果Date
列增加,可以更简单地完成(感谢@Jaap):
DF$index = ceiling(match(DF$Date, unique(DF$Date))/3) # or...
DF$index = ceiling(as.integer(factor(DF$Date))/3)
data.table。 data.table模拟更简单:
library(data.table)
setDT(DF)[, index := ceiling(rleid(Date)/3)]
答案 3 :(得分:2)
我使用了问题早期版本的数据:
df <- data.frame(Date = c("01-01-16", "02-01-16", "02-01-16", "02-01-16",
"03-01-16", "03-01-16", "06-01-16", "06-01-16", "06-01-16", "08-01-16",
"08-01-16", "14-01-16", "14-01-16", "16-01-16", "17-01-16", "17-01-16",
"17-01-16", "24-01-16", "24-01-16", "25-01-16", "25-01-16", "26-01-16",
"29-01-16", "29-01-16", "29-01-16", "29-01-16"),
Index = c(1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L,
3L, 3L, 4L, 4L, 4L, 4L, 4L, 4L, 4L))
我首先将Date列从字符转换为date,并确保数据框按日期排序(您不需要那个部分包含Date
已经是数字的数据的新版本,如果您确定数据框已按日期排序):
df$Date <- as.Date(df$Date, format="%d-%m-%y")
df <- df[ order(df$Date),]
然后我会将日期转换为连续的整数 - 一种方法是转换为因子然后取消分类(这里我使用c
作为简写) - 然后cut
它是等间隔的:
df$ndx <- c(factor(as.numeric(df$Date)))
df$ndx <- cut(df$ndx, seq(0.5, max(df$ndx)+0.5, by=3), labels=FALSE)