首页 > 解决方案 > R tidyverse删除在动态列数中具有相同值的行

问题描述

我有一个这样的数据框:

df = data.frame(x = c("1_1_1", "2_1_1", "3_1_1"),
                y = c("1_1_1", "1_1_1", "1_1_1"),
                z = c("1_1_1", "4_1_1", "1_1_1"))

我现在想动态地遍历我的所有列并检查任何两列是否每行具有相同的值。所以我想比较 x 和 y,x 和 z 以及 y 和 z。请注意,我在现实中有更多的专栏。

期望的结果是删除至少有一个重复值的每一行,即在我的示例中,我想删除第 1 行(因为所有值都相同)和第 3 行(因为 y 和 z 相同)。

也许另一个注意事项:实际上我的数据框有大约 30m 行。

我知道有duplicatedoranyDuplicated函数,但是 AFAIK 这些假设我同时检查所有列中的重复项,而我希望基于成对列比较来获得它。

编辑:与这个问题有些相关(不确定这是否会使事情变得更容易):我df以一种我有一个字符变量的方式创建 dfx=c("1_1_1", "2_1_1", "3_1_1", "1_2_1")等等,然后我使用这个expand.grid函数:

df = expand.grid(x, x, x)

这首先导致重复。所以理想情况下,我会df以一种从一开始就防止这些重复的方式创建数据框?

标签: rduplicatestidyverse

解决方案


为了解决您使用创建重复项的第一个问题expand.grid,我们可以combn改用它,这将为我们提供没有重复项的组合

combn(x, 3, simplify = FALSE)

#[[1]]
#[1] "1_1_1" "2_1_1" "3_1_1"

#[[2]]
#[1] "1_1_1" "2_1_1" "1_2_1"

#[[3]]
#[1] "1_1_1" "3_1_1" "1_2_1"

#[[4]]
#[1] "2_1_1" "3_1_1" "1_2_1"

现在我们需要的是创建具有这种组合的各种排列的行。我们可以手动编写一个函数来创建这种排列或从其中一个包中使用。我在这里使用combinat::permn.

do.call(rbind.data.frame, combn(x, 3, simplify = FALSE, FUN = function(y) 
        do.call(rbind, combinat::permn(y))))

#      V1    V2    V3
#1  1_1_1 2_1_1 3_1_1
#2  1_1_1 3_1_1 2_1_1
#3  3_1_1 1_1_1 2_1_1
#4  3_1_1 2_1_1 1_1_1
#5  2_1_1 3_1_1 1_1_1
#6  2_1_1 1_1_1 3_1_1
#....

要删除duplicated行,我们可以做

df[!apply(df, 1, function(x) any(duplicated(x))), ]

推荐阅读