【问题标题】:Group by and keep columns with matching pattern分组并保留具有匹配模式的列
【发布时间】:2020-04-17 23:14:40
【问题描述】:

我试图弄清楚如何按一个变量分组并保留具有相同变化模式的所有其他变量。这是一个示例 df,其中 gp 是我的分组变量:

   V1 V2 V3 V4 V5 V6 gp
1  0  1  0  0  0  0  x
2  0  0  0  0  1  0  x
3  1  0  1  0  1  1  y
4  0  0  0  0  0  1  x

我想结束的是:

  V1 V3 gp
1  0  0  x
2  0  0  x
3  1  1  y
4  0  0  x

我尝试了很多东西,但没有任何东西能让我接近有用的东西。我的真实数据会更大,但我认为这是一个很好的起点。在这种情况下,我可以做一些数字,但我的“真实数据”是基因组数据,因此不像 0 和 1 那样容易添加。

数据:

structure(list(V1 = c(0L, 0L, 1L, 0L), V2 = c(1L, 0L, 0L, 0L), 
    V3 = c(0L, 0L, 1L, 0L), V4 = c(0L, 0L, 0L, 0L), V5 = c(0L, 
    1L, 1L, 0L), V6 = c(0L, 0L, 1L, 1L), gp = structure(c(1L, 
    1L, 2L, 1L), .Label = c("x", "y"), class = "factor")), class = "data.frame", row.names = c(NA, 
-4L))

【问题讨论】:

  • 对于'y'组,有不止一列有1
  • 我知道,但我希望模式相同(即 0010 匹配 xxyx)

标签: r dplyr tidyverse


【解决方案1】:

您可以通过查找从gp 到该列的值的双射列来做到这一点。也就是说,对于gpxy)中的每个值,变量列中只有一个匹配值,例如V101)。反之亦然,对于像V1 这样的变量列中的每个值,gp 中都有一个匹配项。

要同时对所有列进行操作,首先要转向更长的表单。这也将立即删除简单的重复项。

uniq <- df %>% pivot_longer(-gp) %>% distinct(name, gp, value)
#    name  gp    value
#    <chr> <fct> <int>
#  1 V1    x         0
#  2 V2    x         1
#  3 V3    x         0
#  4 V4    x         0
#  5 V5    x         0
#  6 V6    x         0
#  7 V2    x         0
#  8 V5    x         1
# ...
# 14 V6    y         1
# 15 V6    x         1

然后,您可以通过计算每个gp 值在每个name 中出现的频率来找到一个方向上的“恰好一次”匹配。如果它始终与变量列的常量值匹配,它将恰好是一次。

match_left <- uniq %>%
  count(name, gp) %>%
  group_by(name) %>%
  filter(max(n) == 1) %>%
  distinct(name)

match_left
# # A tibble: 3 x 1
# # Groups:   name [3]
#   name 
#   <chr>
# 1 V1   
# 2 V3   
# 3 V4   

做同样的事情,但值列相反。

match_right <- uniq %>%
  count(name, value) %>%
  group_by(name) %>%
  filter(max(n) == 1) %>%
  distinct(name)

match_right
# # A tibble: 2 x 1
# # Groups:   name [2]
#   name 
#   <chr>
# 1 V1   
# 2 V3   

现在我们知道要保留哪些变量,我们可以将所有内容重新合并在一起并重塑为宽格式。

matches <- df %>%
  mutate(i = row_number()) %>%
  pivot_longer(-c(i, gp)) %>%
  inner_join(match_left, on='name') %>%
  inner_join(match_right, on='name') %>%
  spread(name, value) %>%
  arrange(i) %>%
  select(-i)

matches
# # A tibble: 4 x 3
#   gp       V1    V3
#   <fct> <int> <int>
# 1 x         0     0
# 2 x         0     0
# 3 y         1     1
# 4 x         0     0

【讨论】:

  • 太棒了,这很好用。有点冗长,但完成了工作。我并没有完全考虑所有可能的步骤,并且在枢轴之后被卡住了。谢谢!
【解决方案2】:

我们可以使用duplicated 来获取重复的列。但是,duplicated 以逐行方式工作,因此我们转置了原始数据帧。

t1 <- t(df[-ncol(df)])
df[c(duplicated(t1) | duplicated(t1, fromLast = TRUE), TRUE)]

#  V1 V3 gp
#1  0  0  x
#2  0  0  x
#3  1  1  y
#4  0  0  x

最后的TRUE 是选择最后一列gp

【讨论】:

  • 所以这适用于我给出的确切示例,但不适用于我的真实数据,因为有一些不感兴趣的重复列。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-29
  • 2021-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多