【问题标题】:Why is [- subsetting (i.e. deletion) of columns not possible with names?为什么使用名称无法对列进行 [- 子集化(即删除)?
【发布时间】:2013-09-09 03:55:45
【问题描述】:

我非常担心这已被问及会被否决,但我在文档中没有找到答案(?“[”),发现很难搜索。

data(wines)
# This is allowed:
alcoholic <- wines[, 1]
alcoholic <- wines[, "alcohol"]
nonalcoholic <- wines[, -1]
# But this is not:
fail <- wines[, -"alcohol"]

我知道两种解决方案,但因为需要它们而感到沮丧。

win <- wines[, !colnames(wines) %in% "alcohol"]  # snappy
win <- wines[, -which(colnames(wines) %in% "alcohol")]  # snappier!

【问题讨论】:

  • snappysnappier 是积极的还是消极的措施?在这些情况下,我更喜欢setdiff。你期望-"alcohol" 会返回什么?它本身不能作为命令工作,那么为什么在尝试子集时它会起作用?
  • 也许不能回答你的“为什么”,就“为什么有人选择以这种方式实现它”而言,但无论如何:来自?[:“仅限[-indexing:我, j, ... 可以是逻辑向量(您的! 替代方案)[...] 也可以是负整数(您的which 替代方案)。
  • 如果您只是在寻找更短的东西:wines[names(wines)!="alcohol"]
  • subset(airquality, select = -Temp)
  • 葡萄酒数据集从何而来?我得到“未找到”(R 2.15,所以可能是新版本)。

标签: r dataframe subset


【解决方案1】:

当你这样做时

wines[, -1]

-1 在被[ 使用之前被评估。如您所知,- 一元运算符不适用于 character 类的对象,因此对“酒精”执行相同操作将导致您:

Error in -"alcohol" : invalid argument to unary operator

您可以在备选方案中添加以下内容:

wines[, -match("alcohol", colnames(wines))]
wines[, setdiff(colnames(wines), "alcohol")]

但是您应该了解负面索引的风险,例如,看看如果您错误地输入“alcool”(原文如此)会发生什么。所以您的第一个建议和这里的最后一个建议(@Ananda's)应该是首选。如果您提供的名称不是数据的一部分,您可能还想编写一个会出错的函数。

【讨论】:

  • R&gt; -1 给出[1] -1,那么它是如何工作的呢?我对 R 的工作方式不太熟悉。是这个意思吗?
  • 我将不得不写一个删除列的成语纲要,感谢您的补充:)
  • 是的,-1 的评估结果很好,因此您可以将它作为参数传递给 [ 函数,它会知道如何处理它。另一方面,-"alcohol" 没有。它与[ 的实现方式关系不大,更多的是因为您无法计算-"alcohol",因此将其传递给[ 或任何函数。
  • 我通常用-which()是邪恶的回答这些类型的问题,然后指向setdiff。 +1
  • 为了真正有趣,比较 foo[-0] 和 foo[-c(0,1)] 。几个月前,IIRC 弗洛德尔在一个 SO 问题中讨论了零。
【解决方案2】:

你可以得到你想要的行为如下:

data(iris)
str(iris)
delete <- which(colnames(iris) == "Species")
iris2 <- iris[, -delete]
str(iris2)

【讨论】:

  • 这相当于匹配单个字符串,而不是使用%in% 匹配字符串列表。
  • 这可以简化为deleted &lt;- colnames(iris) == "Species"; iris[!deleted]。当你得到逻辑向量时,你不需要负索引。
【解决方案3】:

编写一个简单的小函数并将其粘贴到您的.Rprofile 中怎么样。比如……

dropcols <- function( df , cols ){
  out <- df[ , !names(df) %in% cols]
  return( out )
}

#  To use it....
data( mtcars )
head( dropcols( mtcars , "mpg" ) )
#                  cyl disp  hp drat    wt  qsec vs am gear carb
#Mazda RX4           6  160 110 3.90 2.620 16.46  0  1    4    4
#Mazda RX4 Wag       6  160 110 3.90 2.875 17.02  0  1    4    4
#Datsun 710          4  108  93 3.85 2.320 18.61  1  1    4    1
#Hornet 4 Drive      6  258 110 3.08 3.215 19.44  1  0    3    1
#Hornet Sportabout   8  360 175 3.15 3.440 17.02  0  0    3    2
#Valiant             6  225 105 2.76 3.460 20.22  1  0    3    1

【讨论】:

  • 是的,这是解决问题的有用方法。但是对于其他人来说不是很便携,所以我有点不愿意这样做。由于这个原因,我通常避免了这种事情,但我总是忘记将我的工作同步到家用机器到笔记本电脑等,并且忘记了我的 .Rprofile 中的内容!
【解决方案4】:

另一种使用数字索引并推广到您想要删除一堆类似命名的列的情况的方法:

dfrm[ , -grep("^val", names(dfrm) )] #remove columns starting with "val"

(我投票给了弗洛德尔,因为他的回答描述了“为什么”一个“减号”不起作用。主要是因为 R 作者没有为此目的重载“-”运算符。他们也没有t 重载 "+" 以像某些语言那样进行连接。

【讨论】:

  • 所以如果开发人员选择了,它们可能会超载?
  • @adifferentben 或者如果你敢的话,你可以自己超载操作 :-)。
  • lattice 和 ggplot2 绘图系统的作者重载了“+”运算符,因此重载“-”没有根本障碍。
【解决方案5】:

另一种可能性:

subset(wines,select=-alcohol)

你甚至可以做

subset(wines,select=-c(alcohol,other_drop))

事实上,如果你想要删除一组连续的列,你甚至可以

subset(wines,select=-(first_drop:last_drop))

这很方便(尽管 IMO 它危险地取决于列的顺序,这可能很脆弱:如果有某种方法来识别列,我可能更喜欢基于 grep 的解决方案,或者更明确列组的单独定义)。

在这种情况下,subset 正在使用非标准评估,正如其他地方所讨论的那样,在某些情况下可能会很危险。但由于它的可读性,我仍然喜欢它进行简单的顶级数据操作。

【讨论】:

  • subset 函数通过一个命名的数字向量将选择表达式转换为数字,这就是“:”方法起作用的原因。
  • @DWin, ?subsetThis is a convenience function intended for use interactively. For programming it is better to use the standard subsetting functions like [, and in particular the non-standard evaluation of argument subset can have unanticipated consequences. 为什么?它所指的非标准评价是什么。 Ben Bolker 列出了这些?
【解决方案6】:

我在文档中找不到这个,但以下语法适用于 data.table

dt = data.table(wines)

dt[, !"alcohol", with = F]

如果你愿意,你也可以有一个列列表:

dt[, !c("Country", "alcohol"), with = F]

它似乎刚刚记录在NEWS for v1.8.4 中:

当 with=FALSE 时,“!”也可以是 j 的前缀,#1384ii。这选择 除了命名列之外的所有列。

DF[,-match("somecol",names(DF))]
# works when somecol exists. If not, NA causes an error.

DF[,-match("somecol",names(DF),nomatch=0)]
# works when somecol exists. Empty data.frame when it doesn't, silently.

DT[,-match("somecol",names(DT)),with=FALSE]
# same issues.

DT[,setdiff(names(DT),"somecol"),with=FALSE]
# works but you have to know order of arguments, and no warning if missing

DT[,!"somecol",with=FALSE]
# works and easy to read. With (helpful) warning if somecol isn't there.

但以上所有内容都复制了除已删除列之外的每一列。更常见的是:

DT[,somecol:=NULL]

通过引用按名称删除列。

【讨论】:

    猜你喜欢
    • 2013-05-13
    • 1970-01-01
    • 2020-06-19
    • 2015-02-13
    • 1970-01-01
    • 2019-11-08
    • 2023-01-14
    • 1970-01-01
    • 2016-06-18
    相关资源
    最近更新 更多