R - 基于重复序列的子集数据帧

时间:2016-08-29 17:05:06

标签: r sequence subset

我正在尝试根据列v3中出现的特定序列对数据框进行子集化。 数据框的示例:

v1 <- c(1:20)
v2 <- c(1,1,0,0,1,0,1,1,1,0,1,1,0,0,0,1,1,0,0,0)
v3 <- c(4,4,2,3,2,3,2,4,4,2,3,2,3,3,3,4,4,2,3,3)
my_df <- data.frame(v1,v2,v3)         # creating a dataframe

my_df

的示例输出
   v1 v2 v3
1   1  1  4
2   2  1  4
3   3  0  2
4   4  0  3
5   5  1  2
6   6  0  3
7   7  1  2
8   8  1  4
9   9  1  4
10 10  0  2
11 11  1  3
12 12  1  2
13 13  0  3
14 14  0  3
15 15  0  3
16 16  1  4
17 17  1  4
18 18  0  2
19 19  0  3
20 20  0  3

我想要实现的输出应该是这样的

1   1  1  4
2   2  1  4
3   3  0  2
8   8  1  4
9   9  1  4
10 10  0  2
16 16  1  4
17 17  1  4
18 18  0  2

所以我想根据4 4 2v3的顺序对我的df进行子集化。我到目前为止尝试的是:

my_df[which(c(diff(v3))==-2),]

但这仅提取序列4 4 2的中间四个,如

v1 v2 v3
 2  2  1  4
 9  9  1  4
17 17  1  4

我尝试的另一种选择:

m = match(v3, c(4,4,2))
> m
 [1]  1  1  3 NA  3 NA  3  1  1  3 NA  3 NA NA NA  1  1  3 NA NA  
> my_df[!is.na(m),]
   v1 v2 v3
1   1  1  4
2   2  1  4
3   3  0  2
5   5  1  2
7   7  1  2
8   8  1  4
9   9  1  4
10 10  0  2
12 12  1  2
16 16  1  4
17 17  1  4
18 18  0  2

这个输出给了我所有4和2但不是我想要的序列4 4 2。任何帮助,将不胜感激。 我已经在matlab中用for和if循环实现了这个,但我只是想知道如何以无循环的方式在R中解决这个问题。

2 个答案:

答案 0 :(得分:1)

我们可以使用data.table执行此操作。转换&#39; data.frame&#39;到&#39; data.table&#39; (setDT(my_df))。使用shift中的data.table,我们获得了type = "lead"的下一个元素。由于shift采用n的向量,我们指定n = 0:2,因此我们得到三列,其中n = 0对应于原始的&#39; v3&#39}。列和其他第1和第2个下一个值。然后,paste元素rowwise(do.call(paste0, ...),检查它是否等于442,获取TRUE值的索引(which),使用rep复制索引并添加0:2,以便我们获得每个索引的三行索引。这可用于对原始数据集行进行子集化。

library(data.table)
setDT(my_df)[my_df[, rep(which(do.call(paste0, shift(v3, 0:2,
                 type= "lead")) == 442), each = 3) + 0:2]]
#   v1 v2 v3
#1:  1  1  4
#2:  2  1  4
#3:  3  0  2
#4:  8  1  4
#5:  9  1  4
#6: 10  0  2
#7: 16  1  4
#8: 17  1  4
#9: 18  0  2

数据

my_df <- structure(list(v1 = 1:20, v2 = c(1L, 1L, 0L, 0L, 1L, 0L, 1L, 
1L, 1L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L), v3 = c(4L, 
4L, 2L, 3L, 2L, 3L, 2L, 4L, 4L, 2L, 3L, 2L, 3L, 3L, 3L, 4L, 4L, 
2L, 3L, 3L)), .Names = c("v1", "v2", "v3"), class = "data.frame", 
row.names = c("1", 
"2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", 
"14", "15", "16", "17", "18", "19", "20"))

答案 1 :(得分:1)

只要v3没有任何缺失值且v3的值是单个字符,您也可以使用gregexpr完成此操作,如下所示

# get the row indices where the pattern 442 starts c(1 , 8, 16)
rowstarts <- unlist(gregexpr("442", paste(my_df$v3, collapse="")))

# extract rows from the data fram
dfNew <- my_df[sort(c(outer(rowstarts, (0:2), "+"))), ]

返回

dfNew
   v1 v2 v3
1   1  1  4
2   2  1  4
3   3  0  2
8   8  1  4
9   9  1  4
10 10  0  2
16 16  1  4
17 17  1  4
18 18  0  2
带有collapse参数的

paste将向量v3转换为单个字符串。 grexpr然后在此字符串中找到任何“442”子表达式的起始位置。

最后一步使用@ alexis-laz在上面评论中建议的outer函数对data.frame进行子集化。