首页 > 解决方案 > 在数据框中选择第一次出现的带有前缀的变量

问题描述

dplyr::select第一次出现具有特定前缀的变量(以及没有该前缀的所有其他变量)的最佳方法是什么。或者换一种说法,删除所有带有该前缀的变量,除了第一次出现。

library(tidyverse)
hiris <- head(iris)
#given this data.frame:
lst(hiris, hiris, hiris) %>% 
  map(rownames_to_column) %>% 
  reduce(full_join, by = "rowname")

#   rowname Sepal.Length.x Sepal.Width.x Petal.Length.x Petal.Width.x Species.x Sepal.Length.y Sepal.Width.y Petal.Length.y Petal.Width.y Species.y Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1       1            5.1           3.5            1.4           0.2    setosa            5.1           3.5            1.4           0.2    setosa          5.1         3.5          1.4         0.2  setosa
# 2       2            4.9           3.0            1.4           0.2    setosa            4.9           3.0            1.4           0.2    setosa          4.9         3.0          1.4         0.2  setosa
# 3       3            4.7           3.2            1.3           0.2    setosa            4.7           3.2            1.3           0.2    setosa          4.7         3.2          1.3         0.2  setosa
# 4       4            4.6           3.1            1.5           0.2    setosa            4.6           3.1            1.5           0.2    setosa          4.6         3.1          1.5         0.2  setosa
# 5       5            5.0           3.6            1.4           0.2    setosa            5.0           3.6            1.4           0.2    setosa          5.0         3.6          1.4         0.2  setosa
# 6       6            5.4           3.9            1.7           0.4    setosa            5.4           3.9            1.7           0.4    setosa          5.4         3.9          1.7         0.4  setosa

现在假设我想删除Sepal.Length除第一个 ( Sepal.Length.x) 之外的所有带前缀的变量,我可以这样做:

lst(hiris, hiris, hiris) %>% 
  map(rownames_to_column) %>% 
  reduce(full_join, by = "rowname") %>%
  dplyr::select(-Sepal.Length.y, -Sepal.Length)

效果很好,但我想要一些灵活的东西,所以它可以处理任意数量的带有前缀的变量,Sepal.Length例如:

lst(hiris, hiris, hiris, hiris, hiris, hiris, hiris) %>% 
  map(rownames_to_column) %>% 
  reduce(full_join, by = "rowname") 

我可以做这样的事情:

df <- lst(hiris, hiris, hiris, hiris, hiris, hiris, hiris) %>% 
  map(rownames_to_column) %>% 
  reduce(full_join, by = "rowname")
name_drop <- (df %>% select(matches("Sepal.Length")) %>% names())[-1]
df %>% 
  select(-name_drop)

但我希望在管道中更有效地做到这一点。有什么建议么?

谢谢

标签: rdplyr

解决方案


我喜欢这个问题的解释:

除第一次出现外,删除所有具有该前缀的变量。

select(iris, !starts_with("Sepal")[-1])
#     Sepal.Length Petal.Length Petal.Width    Species
# 1            5.1          1.4         0.2     setosa
# 2            4.9          1.4         0.2     setosa
# ...

starts_with("Sepal")当然会返回所有以 开头的列"Sepal",我们可以使用它[-1]来删除第一个匹配项,并!删除任何剩余的匹配项。

它看起来有点像黑魔法——如果我们在基数 R 中这样做,[-1]如果我们曾经which()获取列索引,那!将是合适的,如果我们不使用which()并且有一个逻辑向量,那将是合适的,但不知何故tidyselect功能使它工作!


推荐阅读