自定义索引列

时间:2016-05-13 19:40:06

标签: r

我有一个带有不规则日期列的数据集。我想创建一个索引列。对于三个不相似的连续日期,索引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")

4 个答案:

答案 0 :(得分:4)

使用rleid包中的data.tablecumsum

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
  • 通过从游程长度id中减去1并获取其模数(%% 3部分),您将获得01&amp; {的序列向量{1}}的。
  • 最后一步,您将获取值与先前值的比较累计和。当2index < 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)