R - 删除连续的(仅)重复项
R - delete consecutive (ONLY) duplicates
我需要根据给定列中重复的值从数据框中删除行,但仅删除那些连续的行。
例如,对于以下数据框:
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 行(我正在测试的类似 table 没有发生),但只对值起作用。
我也试过使用 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
如有转载请见谅。我尝试了一些建议,但 none 只消除了那些连续的建议。
如果有任何帮助,我将不胜感激。
谢谢
怎么样:
df[cumsum(rle(df$x)$lengths),]
解释:
rle(df$x)
为您提供 运行 长度和 连续 重复值 x
变量。那么:
rle(df$x)$lengths
提取长度。最后:
cumsum(rle(df$x)$lengths)
给出您可以 select 使用 [
的行索引。
编辑 为了好玩,这里有 microbenchmark
到目前为止给出的答案,rle
是我的,consec
是我的想法最基本的直接答案,由@James 给出,我会 "accept",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
比我想象的要好。
我能想到的 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
您只需检查数字后面没有重复项,即 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
这是一个data.table
解决方案。诀窍是使用 shift
函数创建 x
的移位版本,并将其与 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 的每个值与其紧随其后的值进行比较,并在它们匹配的地方抛出。确保将 fill 设置为 x
中没有的内容,以便正确处理最后一个值。
我需要根据给定列中重复的值从数据框中删除行,但仅删除那些连续的行。 例如,对于以下数据框:
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 行(我正在测试的类似 table 没有发生),但只对值起作用。
我也试过使用 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
如有转载请见谅。我尝试了一些建议,但 none 只消除了那些连续的建议。 如果有任何帮助,我将不胜感激。
谢谢
怎么样:
df[cumsum(rle(df$x)$lengths),]
解释:
rle(df$x)
为您提供 运行 长度和 连续 重复值 x
变量。那么:
rle(df$x)$lengths
提取长度。最后:
cumsum(rle(df$x)$lengths)
给出您可以 select 使用 [
的行索引。
编辑 为了好玩,这里有 microbenchmark
到目前为止给出的答案,rle
是我的,consec
是我的想法最基本的直接答案,由@James 给出,我会 "accept",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
比我想象的要好。
我能想到的 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
您只需检查数字后面没有重复项,即 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
这是一个data.table
解决方案。诀窍是使用 shift
函数创建 x
的移位版本,并将其与 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 的每个值与其紧随其后的值进行比较,并在它们匹配的地方抛出。确保将 fill 设置为 x
中没有的内容,以便正确处理最后一个值。