【问题标题】:Removing Only Adjacent Duplicates in Data Frame in R仅删除 R 中数据框中的相邻重复项
【发布时间】:2015-01-17 06:41:39
【问题描述】:

我在 R 中有一个 应该是重复的数据框。但是,我需要删除一些重复项。特别是,我只想删除行相邻的重复项,但保留其余的。例如,假设我有数据框:

df = data.frame(x = c("A", "B", "C", "A", "B", "C", "A", "B", "B", "C"), 
                y = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))

这会产生以下数据框

x   y
A   1
B   2
C   3
A   4
B   5
C   6
A   7
B   8
B   9
C   10

在这种情况下,我希望重复“A、B、C、A、B、C 等”。但是,只有当我看到 adjacent row 重复时才会出现问题。在我上面的示例中,这将是第 8 行和第 9 行,其中重复的“B”彼此相邻。

在我的数据集中,无论何时发生这种情况,第一个实例始终是用户错误,第二个实例始终是正确的版本。在极少数情况下,可能会出现重复出现 3 次(或更多)次的情况。但是,在每种情况下,我总是希望保留最后一次出现。因此,按照上面的示例,我希望最终的数据集看起来像

A   1
B   2
C   3
A   4
B   5
C   6
A   7
B   9
C   10

在 R 中有一种简单的方法可以做到这一点吗?提前感谢您的帮助!


编辑:美国东部标准时间 2014 年 11 月 19 日下午 12:14 用户 Akron(拼写?)发布了一个解决方案,该解决方案已被删除。我现在知道为什么了,因为它似乎对我有用?

解决办法是

df = df[with(df, c(x[-1]!= x[-nrow(df)], TRUE)),]

它似乎对我有用,为什么它被删除了?例如,如果连续重复超过 2 个:

df = data.frame(x = c("A", "B", "B", "B", "C", "C", "C", "A", "B", "C", "A", "B", "B", "C"), y = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14))
   x  y
1  A  1
2  B  2
3  B  3
4  B  4
5  C  5
6  C  6
7  C  7
8  A  8
9  B  9
10 C 10
11 A 11
12 B 12
13 B 13
14 C 14

> df = df[with(df, c(x[-1]!= x[-nrow(df)], TRUE)),]
> df
   x  y
1  A  1
4  B  4
7  C  7
8  A  8
9  B  9
10 C 10
11 A 11
13 B 13
14 C 14

这似乎行得通?

【问题讨论】:

  • df[diff(as.numeric(df$x)) != 0, ] 可能吗?
  • @DavidArenburg 当我运行as.numeric(df$x) 时,我得到了NAs 的向量。
  • @DavidArenburg 哎呀。我忘了我加了stringsAsFactors = F
  • @akrun,看来他是对的,你现在可以取消删除了:)
  • 是的,你似乎是对的。我实际上评论说“我不认为”它会起作用,因为我也没有测试它

标签: r duplicates


【解决方案1】:

试试

 df[with(df, c(x[-1]!= x[-nrow(df)], TRUE)),]
#   x  y
#1  A  1
#2  B  2
#3  C  3
#4  A  4
#5  B  5
#6  C  6
#7  A  7
#9  B  9
#10 C 10

说明

在这里,我们将一个元素与它之前的元素进行比较。这可以通过从列中删除first element 并将该列与删除last element 的列进行比较来完成(使长度变得相等)

 df$x[-1] #first element removed
 #[1] B C A B C A B B C
 df$x[-nrow(df)]
  #[1] A B C A B C A B B #last element `C` removed

 df$x[-1]!=df$x[-nrow(df)]
 #[1]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE

在上面,当我们删除了一个元素时,1 的长度小于dfnrow。为了弥补这一点,我们可以连接一个TRUE,然后使用这个index 对数据集进行子集化。

【讨论】:

  • 这个解决方案有效,但我对它为什么有效感到困惑。我在帮助页面上查找了 with,但我仍然不确定。我提前道歉,我是新手 R 用户。
  • 非常感谢您的帮助!
【解决方案2】:

这是rle 解决方案:

df[cumsum(rle(as.character(df$x))$lengths), ]
#    x  y
# 1  A  1
# 2  B  2
# 3  C  3
# 4  A  4
# 5  B  5
# 6  C  6
# 7  A  7
# 9  B  9
# 10 C 10

解释:

RLE 代表运行长度编码。它产生一个向量列表。一个是运行、值,另一个长度是每个值的连续重复次数。例如,x <- c(3, 2, 2, 3) 的游程向量为 c(3, 2, 3),长度为 c(1, 2, 1)。在此示例中,长度的累积总和产生c(1, 3, 4)。用这个向量子集x,你得到c(3, 2, 3)。请注意,长度向量的第二个元素是该向量的第三个元素,并且是该特定“运行”中最后一次出现的 2。

【讨论】:

    【解决方案3】:

    你也可以试试

    df[c(diff(as.numeric(df$x)), 1) != 0, ]
    

    如果x 属于character 类(而不是factor),请尝试

    df[c(diff(as.numeric(factor(df$x))), 1) != 0, ]
    #    x  y
    # 1  A  1
    # 2  B  2
    # 3  C  3
    # 4  A  4
    # 5  B  5
    # 6  C  6
    # 7  A  7
    # 9  B  9
    # 10 C 10
    

    【讨论】:

    • 我认为你需要填充你的差异:s,比如c(1, diff(as.integer(as.factor(df$x))))。检查例如x <- c("a", "a", "b"); x[diff(as.numeric(factor(x))) != 0]
    • @Henrik,您的方法不会达到预期的结果。比较新提供的数据集
    • @David Arenburg 假设数据(基于编辑的数据集)set.seed(14); df1 <- df[sample(1:nrow(df)),];row.names(df1) <- NULL; df1[diff(as.numeric(factor(df1$x))) != 0, ] 没有给出最后一行。也许,需要填充。
    • @akrun,很好。似乎如果欺骗是在开始时,则需要填充。虽然填充应该添加到末尾,而不是开头(如 Henrik 示例中)。已编辑。
    • 这就是为什么我要求你在x <- c("a", "a", "b") 上检查你的代码;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-29
    • 2023-01-02
    • 2020-04-10
    • 2018-11-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多