我需要根据给定列中值的重复来消除数据帧中的行,但只需要连续的那些行。 例如,对于以下数据框:
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
请原谅,如果交叉发布。我尝试了一些建议,但没有一个只能消除那些连续的建议。 我将不胜感激任何帮助。
由于
答案 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
以外的值,以便正确处理最后一个值。