R - 删除连续(仅)重复项

时间:2018-03-15 18:33:20

标签: r duplicates delete-row repeat

我需要根据给定列中值的重复来消除数据帧中的行,但只需要连续的那些行。 例如,对于以下数据框:

df = data.frame(x=c(1,1,1,2,2,4,2,2,1))
df$y <- c(10,11,30,12,49,13,12,49,30)
df$z <- c(1,2,3,4,5,6,7,8,9)

x  y z
1 10 1
1 11 2
1 30 3
2 12 4
2 49 5
4 13 6
2 12 7
2 49 8
1 30 9

我需要在x列中消除具有连续重复值的行,保留最后一个重复行,并保持数据帧的结构:

x  y z
1 30 3
2 49 5
4 13 6
2 49 8
1 30 9

按照help和其他一些帖子的说明,我尝试使用duplicated功能:

df[ !duplicated(x,fromLast=TRUE), ] # which gives me this:
      x  y  z
1     1 10  1
6     4 13  6
7     2 12  7
9     1 30  9
NA   NA NA NA
NA.1 NA NA NA
NA.2 NA NA NA
NA.3 NA NA NA
NA.4 NA NA NA
NA.5 NA NA NA
NA.6 NA NA NA
NA.7 NA NA NA
NA.8 NA NA NA

我不确定为什么我会在最后得到NA行(我正在测试的类似表格没有发生),但只能部分地处理这些值。

我还尝试使用data.table包,如下所示:

library(data.table)
dt <- as.data.table(df)           
setkey(dt, x)                    
dt[J(unique(x)), mult ='last'] 

效果很好,但它消除了数据框中的所有重复项,而不仅仅是那些连续的重复项,如下所示:

x  y z
1 30 9
2 49 8
4 13 6

请原谅,如果交叉发布。我尝试了一些建议,但没有一个只能消除那些连续的建议。 我将不胜感激任何帮助。

由于

4 个答案:

答案 0 :(得分:7)

怎么样:

df[cumsum(rle(df$x)$lengths),]

说明:

rle(df$x)

为您提供x变量中连续重复项的运行长度和值。然后:

rle(df$x)$lengths

提取长度。最后:

cumsum(rle(df$x)$lengths)

给出了可以使用[选择的行索引。

编辑这里有趣的是microbenchmark到目前为止rle是我的答案,consec是我认为最基本的直接答案,由@James给出,并且是我将“接受”的答案,dp是@Nik给出的dplyr答案。

#> Unit: microseconds
#>    expr       min         lq       mean     median         uq        max
#>     rle   134.389   145.4220   162.6967   154.4180   172.8370    375.109
#>  consec   111.411   118.9235   136.1893   123.6285   145.5765    314.249
#>      dp 20478.898 20968.8010 23536.1306 21167.1200 22360.8605 179301.213

rle表现得比我想象的要好。

答案 1 :(得分:6)

你只需要登记一个号码后面没有重复,即x [i + 1]!= x [i]并注意最后一个值将始终存在。

df[c(df$x[-1] != df$x[-nrow(df)],TRUE),]
  x  y z
3 1 30 3
5 2 49 5
6 4 13 6
8 2 49 8
9 1 30 9

答案 2 :(得分:2)

我能想到的dplyr廉价解决方案:

方法:

library(dplyr)
df %>% 
  mutate(id = lag(x, 1), 
         decision = if_else(x != id, 1, 0), 
         final = lead(decision, 1, default = 1)) %>% 
  filter(final == 1) %>% 
  select(-id, -decision, -final)

输出:

  x  y z
1 1 30 3
2 2 49 5
3 4 13 6
4 2 49 8
5 1 30 9

如果您的数据在底部具有相同的x值

,这甚至可以使用

新输入:

df2 <- df %>% add_row(x = 1, y = 10, z = 12)
df2

   x  y  z
1  1 10  1
2  1 11  2
3  1 30  3
4  2 12  4
5  2 49  5
6  4 13  6
7  2 12  7
8  2 49  8
9  1 30  9
10 1 10 12

使用相同的方法:

df2 %>% 
  mutate(id = lag(x, 1), 
         decision = if_else(x != id, 1, 0), 
         final = lead(decision, 1, default = 1)) %>% 
  filter(final == 1) %>% 
  select(-id, -decision, -final)

新输出:

  x  y  z
1 1 30  3
2 2 49  5
3 4 13  6
4 2 49  8
5 1 10 12

答案 3 :(得分:1)

这是一个data.table解决方案。诀窍是使用x函数创建shift的移位版本,并将其与x进行比较

library(data.table)
dattab <- as.data.table(df)
dattab[x != shift(x = x, n = 1, fill = -999, type = "lead")] # edited to add closing )

通过这种方式,您可以将x的每个值与其紧随的值进行比较,并抛出它们匹配的位置。确保将填充设置为x以外的值,以便正确处理最后一个值。