Почему [- подмножество (например, удаление) столбцов невозможно с именами?
Я очень опасаюсь, что это было задано и будет отменено, но я не нашел ответа в документах (? "[" ) и обнаружил, что его трудно найти.
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!
Ответы
Ответ 1
Когда вы делаете
wines[, -1]
-1
оценивается до того, как используется [
. Как вы знаете, унарный оператор -
не будет работать с объектом класса character
, поэтому сделать то же самое с "алкоголем" приведет вас к:
Error in -"alcohol" : invalid argument to unary operator
Вы можете добавить следующие альтернативы:
wines[, -match("alcohol", colnames(wines))]
wines[, setdiff(colnames(wines), "alcohol")]
но вы должны знать о рисках отрицательного индексирования, например, посмотреть, что произойдет, если вы ошиблись "alcool" (sic.). Поэтому ваше первое предложение и последнее здесь (@Ананда) должны быть предпочтительнее. Вы также можете написать функцию, которая будет выходить из системы, если вы укажете имя, которое не является частью ваших данных.
Ответ 2
Другая возможность:
subset(wines,select=-alcohol)
Вы даже можете сделать
subset(wines,select=-c(alcohol,other_drop))
Фактически, если у вас есть смежный набор столбцов, которые вы хотите отбросить, вы можете даже
subset(wines,select=-(first_drop:last_drop))
что может быть удобно (хотя IMO это зависит от порядка столбцов, что может быть хрупким: я мог бы предпочесть решение на основе grep
, если бы был способ идентифицировать столбцы или более явный отдельное определение групп столбцов).
В этом случае subset
использует нестандартную оценку, которая, как обсуждалось в других местах, может быть опасна в некоторых контекстах. Но мне все еще нравится простое управление данными на верхнем уровне из-за его удобочитаемости.
Ответ 3
Другой метод, который использует числовую индексацию и обобщает на ситуации, когда вы хотите удалить кучу столбцов с одинаковым именем:
dfrm[ , -grep("^val", names(dfrm) )] #remove columns starting with "val"
(Я дал свой голос флоле, так как его ответ описал "почему" знак "минус" не работал. По сути, поскольку авторы R не перегружали оператора "-" для этой цели, t перегрузить "+", чтобы сделать конкатенацию так, как это делали некоторые языки.
Ответ 4
Как писать простую небольшую функцию и вставлять ее в .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
Ответ 5
Я не могу найти это в документации, но следующий синтаксис работает с data.table
:
dt = data.table(wines)
dt[, !"alcohol", with = F]
И вы также можете иметь список столбцов, если хотите:
dt[, !c("Country", "alcohol"), with = F]
Это было просто задокументировано в NEWS для v1.8.4, похоже:
Когда с = 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]
чтобы удалить столбец по имени по ссылке.
Ответ 6
Вы можете получить желаемое поведение следующим образом:
data(iris)
str(iris)
delete <- which(colnames(iris) == "Species")
iris2 <- iris[, -delete]
str(iris2)