R dplyr:删除多列

132

我有一个数据框和该数据框中的一些列,我想要删除这些列。让我们以iris数据集为例。我想删除Sepal.LengthSepal.Width并仅使用其余的列。如何使用dplyr包中的selectselect_实现这一点?

到目前为止,这是我尝试过的:

drop.cols <- c('Sepal.Length', 'Sepal.Width')
iris %>% select(-drop.cols)

-drop.cols中的错误:一元运算符的参数无效

iris %>% select_(.dots = -drop.cols)

-drop.cols发生错误:一元运算符的参数无效

iris %>% select(!drop.cols)

在!drop.cols中出现错误:无效的参数类型

iris %>% select_(.dots = !drop.cols)

!drop.cols 中的错误:无效的参数类型

我觉得我可能错过了什么显而易见的东西,因为这似乎是一个非常有用的操作,应该已经存在。在 Github 上,有人发布了类似的问题,Hadley说要使用“负索引”。这就是我尝试过的(我想),但没有成功。有什么建议吗?

10个回答

147

查看 select_vars 的帮助页面,那里会提供一些关于如何使用它的额外想法。

在你的情况下:

iris %>% select(-one_of(drop.cols))

谢谢。由于某种原因,这在“鸢尾花”数据集上可以工作,但在我的实际数据框中不行(“鸢尾花”是一个玩具示例)。我的数据框包含4558行和147列。我收到的错误消息是“在数据集中变量名限制为10000个字节”。有任何想法可能是发生了什么? - Navaneethan Santhanam
1
啊,看起来我犯了个错误。我不小心使用了select_vars而不是select。现在它完美地运行了! - Navaneethan Santhanam
7
我们应该在哪里查找内置函数,比如 one_of?除非我漏掉了什么,否则它似乎不在包文档(help(package='dplyr'))中出现。 - geotheory
4
@geotheory,实际上one_of已经有文档了。请参考 help(one_of, package="dplyr")。至少在 0.5.0 版本中已经有文档了。但是阅读 Hadley 在更新他的包时发布的博客会有所帮助。有些函数的文档可能在其他函数的内部。不幸的是,这需要阅读所有文档,我大多数情况下只在想要某些不太明显或不可能的功能时才这样做。 - phiver
13
谢谢。在文档方面,您是如何首次了解这些功能的呢? - geotheory

99

还可以尝试

## Notice the lack of quotes
iris %>% select (-c(Sepal.Length, Sepal.Width))

7
太好了!当我们需要通过从控制台复制粘贴列名来删除列时,这个功能非常有用。 - Pablo Casas

57

除了select(-one_of(drop.cols))之外,使用select()删除列的另外几个选项没有涉及定义所有特定列名(使用dplyr星球大战示例数据来提供更多列名的变化):

starwars %>% 
  select(-(name:mass)) %>%        # the range of columns from 'name' to 'mass'
  select(-contains('color')) %>%  # any column name that contains 'color'
  select(-starts_with('bi')) %>%  # any column name that starts with 'bi'
  select(-ends_with('er')) %>%    # any column name that ends with 'er'
  select(-matches('^f.+s$')) %>%  # any column name matching the regex pattern
  select_if(~!is.list(.)) %>%     # not by column name but by data type
  head(2)

# A tibble: 2 x 2
homeworld species
  <chr>     <chr>  
1 Tatooine  Human  
2 Tatooine  Droid 

select_if(~!is.list(.)) 是否等同于 select_if(is.list(.)) - Jasha
4
在这种情况下,~是purrr中定义匿名函数的简写方式,它不是表示“not”的另一个符号。例如,这两个意思相同:function(x) {!is.list(x)}~!is.list(.)。可以将~视为function(.)的缩写。 - SlyFox

13

使用 select() 函数时要小心,因为它被同时用于 dplyr 和 MASS 包中。如果加载了 MASS 包,则 select() 可能无法正常工作。要查找已加载的包,请键入 sessionInfo() 并在“other attached packages:”部分查找它。如果已加载,请键入 detach( "package:MASS", unload = TRUE ),然后你的 select() 函数应该可以正常工作。


13
你可以选择直接访问包命名空间中的函数,如 dplyr::select() - Triamus
2
我也经常遇到这个问题。现在我通常会在我的脚本顶部定义一个新的函数 dselect <- dplyr::select() - filups21
1
后加载的包具有优先权。我总是在所有包都加载后p_load(tidyverse),以确保函数不会被另一个包无意中屏蔽。 - taiyodayo

6
我们可以尝试。
iris %>% 
      select_(.dots= setdiff(names(.),drop.cols))

感谢@akrun,这个方法完美解决了问题。然而,考虑到dplyr在使基本分析任务易于阅读和编写方面的炒作,我对实际解决方案看起来像一个变通方法感到失望。 - Navaneethan Santhanam
@NavaneethanSanthanam 实际上,另一个解决方案中的 one_of 是正确的方法。我忘记了它。 - akrun

6

如果有人想要删除一系列列,请按如下方式进行:

最小可重现示例

像这样删除一系列列:

iris %>% 
  select(-(Sepal.Width:Petal.Width)) %>% 
  head

#   Sepal.Length Species
# 1          5.1  setosa
# 2          4.9  setosa
# 3          4.7  setosa
# 4          4.6  setosa
# 5          5.0  setosa
# 6          5.4  setosa

注意:
  • 列名周围的括号 ()是重要的,必须使用

4
另一种方法是将不需要的列突变为 NULL,这样可以避免嵌套括号的问题:
head(iris,2) %>% mutate_at(drop.cols, ~NULL)
#   Petal.Length Petal.Width Species
# 1          1.4         0.2  setosa
# 2          1.4         0.2  setosa

如果一列不存在,这也不会发出警告。 - skoz

3
如果列名中有特殊字符,则selectselect_可能无法按预期工作。 dplyr使用"."来解决这个问题。要引用问题中的数据集,可以使用以下行来解决此问题:
drop.cols <- c('Sepal.Length', 'Sepal.Width')
  iris %>% .[,setdiff(names(.),drop.cols)]

不鼓励仅提供代码的答案。请解释答案的工作原理以及与已有答案的区别。 - Ralf Stubner
谢谢!以上的其他解决方案都没有起作用,原因正是如此。 - Marty999

2
你可以尝试

iris %>% select(-!!drop.cols)

1
我也遇到了同样的问题,但主要错误在于包含另一个具有与“select()”相同名称的函数定义的库。对我来说,它与MASS包选择功能冲突。
分离MASS库后,错误停止了。

请注意,您也可以通过执行 dplyr::select 来仅从 dplyr 库中指定 select - Parseltongue

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接