根据条件查找并匹配最近的行值

时间:2016-12-16 02:54:36

标签: r pattern-matching match

寻找帮助来编写棘手的R代码。

我有一个以下结构的数据框:

#make fake data
category<-c("a", "a", "a", "a", "a", "b", "b", "b", "b", "b")
cat.id<-rep(1:5, 2)
time <- seq.POSIXt(as.POSIXct("10/24/16 21:05", format="%m/%d/%y %H:%M", tz="America/Chicago"), by="5 min", length.out=10)
x<-c(0.2, 3, 4, 0.5, 1.4, 3, 1.9, 2.2, 4, 1.2)

data<-data.frame(category, cat.id, time, x)

>data
   category cat.id                time   x
1         a      1 2016-10-24 21:05:00 0.2
2         a      2 2016-10-24 21:10:00 3.0
3         a      3 2016-10-24 21:15:00 4.0
4         a      4 2016-10-24 21:20:00 0.5
5         a      5 2016-10-24 21:25:00 1.4
6         b      1 2016-10-24 21:30:00 3.0
7         b      2 2016-10-24 21:35:00 1.9
8         b      3 2016-10-24 21:40:00 2.2
9         b      4 2016-10-24 21:45:00 4.0
10        b      5 2016-10-24 21:50:00 1.2

对于“类别”的每个子集(例如,“a”或“b”),我需要移动“cat.id”,以便:     -if“x”是&lt;在图2中,然后将“cat.id”匹配(或移位)到最接近的先前值“cat.id”,其中x是> = 2。      - 移位的“cat.id”值存储在“cat.idshifted”列中      - 对于“cat.id”== 1的值,没有移位,因为“category”的子集没有先前的值

这会生成如下数据框:

data$cat.idshifted<-c(1, 2, 3, 3, 3, 1, 1, 3, 4, 4)
>data
   category cat.id                time   x cat.idshifted
1         a      1 2016-10-24 21:05:00 0.2             1
2         a      2 2016-10-24 21:10:00 3.0             2
3         a      3 2016-10-24 21:15:00 4.0             3
4         a      4 2016-10-24 21:20:00 0.5             3
5         a      5 2016-10-24 21:25:00 1.4             3
6         b      1 2016-10-24 21:30:00 3.0             1
7         b      2 2016-10-24 21:35:00 1.9             1
8         b      3 2016-10-24 21:40:00 2.2             3
9         b      4 2016-10-24 21:45:00 4.0             4
10        b      5 2016-10-24 21:50:00 1.2             4

基本思想是“cat.id”表示“类别”收集的数据文件的数量。有时,由于硬件问题,实际属于单个事件的数据文件会被拆分为多个文件。因此,实际上可以在3个文件中收集1个数据事件。您可以通过查看“x”找出哪些文件在一起。如果x <2的值,则文件一起出现。并且由于1个文件可以分成许多,因此x&lt; 2表示属于一起的多个文件。

所以我想做的是每次x&lt; 2,并将“cat.id”或文件ID调整为正确的值,这恰好是收集了与x&gt; = 2的前一个文件中最接近的时间。

我在想一个索引最接近(及时)&gt; = 2的“x”值的函数可能是合适的。然后索引值将“cat.id”值返回“cat.idshifted”。

我熟悉which.max等索引值,但是我不知道如何通过说“给我最接近的值的东西”来索引值。

为简单起见,我没有在这里包含,但x实际上是每个文件集合之间的时间量。例如,它是一个difftime对象。也许一段时间循环可以工作?哪里: - 有x&lt; 2个值 -Shift cat.id值返回1(例如,cat.id-1) - 重新计算difftime - 检查是否仍然存在x <2的值,重复,直到不为真。

对这个棘手的代码有何看法?

2 个答案:

答案 0 :(得分:1)

试试这个:

# Create 'temp' column to indicate whether record belongs to previous file (0) or not (cat.id)
data$temp = ifelse(data$x < 2, 0, data$cat.id)
data$temp[data$cat.id==1] = 1

# Take the cumulative max of 'temp' by category.
data$cat.idshifted = unlist(by(data, data$category, function(da) cummax(da$temp)))

> data
#    category cat.id                time   x temp cat.idshifted
# 1         a      1 2016-10-24 21:05:00 0.2    1             1
# 2         a      2 2016-10-24 21:10:00 3.0    2             2
# 3         a      3 2016-10-24 21:15:00 4.0    3             3
# 4         a      4 2016-10-24 21:20:00 0.5    0             3
# 5         a      5 2016-10-24 21:25:00 1.4    0             3
# 6         b      1 2016-10-24 21:30:00 3.0    1             1
# 7         b      2 2016-10-24 21:35:00 1.9    0             1
# 8         b      3 2016-10-24 21:40:00 2.2    3             3
# 9         b      4 2016-10-24 21:45:00 4.0    4             4
# 10        b      5 2016-10-24 21:50:00 1.2    0             4

答案 1 :(得分:0)

data$cat.idshifted <- NA

for(c in data$category){
  for(i in which(data$category==c)){
    if(data$cat.id[i]==1){
      data$cat.idshifted[i] <- data$cat.id[i]      
    } else if(data$x[i]<=2){
        data$cat.idshifted[i] <- max( data$cat.id[data$x > 2 & data$category==c & data$cat.id < data$cat.id[i]])
      } else if(data$x[i]>2){
        data$cat.idshifted[i] <- data$cat.id[i]   
      }
    }
}

data
   category cat.id                time   x cat.idshifted
1         a      1 2016-10-24 21:05:00 0.2             1
2         a      2 2016-10-24 21:10:00 3.0             2
3         a      3 2016-10-24 21:15:00 4.0             3
4         a      4 2016-10-24 21:20:00 0.5             3
5         a      5 2016-10-24 21:25:00 1.4             3
6         b      1 2016-10-24 21:30:00 3.0             1
7         b      2 2016-10-24 21:35:00 1.9             1
8         b      3 2016-10-24 21:40:00 2.2             3
9         b      4 2016-10-24 21:45:00 4.0             4
10        b      5 2016-10-24 21:50:00 1.2             4

如果您希望缩短时间,可以先将if和我的第二个else if合并为一个if语句与|运算符,但这样可行原样。

声明的方式:

max( data$cat.id[data$x > 2 & data$category==c & data$cat.id < data$cat.id[i]])

作品就是如下:

  • 我希望我的替换cat.id对应x的值为&gt; 2,因此data$x > 2部分
  • 我只想在同一类别中查找替换(data$category==c
  • 我希望替换位于目标(data$cat.id < data$cat.id[i]
  • 之前
  • 我希望最近的行符合上述条件(这就是您使用max()
  • 的原因