У меня есть несколько столбцов, которые я хотел бы удалить из фрейма данных. Я знаю, что мы можем удалить их индивидуально, используя что-то вроде:
df$x <- NULL
Но я надеялся сделать это с меньшим количеством команд.
Кроме того, я знаю, что я могу удалить столбцы с использованием целочисленного индексации следующим образом:
df <- df[ -c(1, 3:6, 12) ]
Но я обеспокоен тем, что относительное положение моих переменных может измениться.
Учитывая, насколько силен R, я понял, что может быть лучший способ, чем сбросить каждый столбец один за другим.
Вы можете использовать простой список имен:
DF <- data.frame(
x=1:10,
y=10:1,
z=rep(5,10),
a=11:20
)
drops <- c("x","z")
DF[ , !(names(DF) %in% drops)]
Или, альтернативно, вы можете составить список тех, которые нужно сохранить и ссылаться на них по имени:
keeps <- c("y", "a")
DF[keeps]
ИЗМЕНИТЬ:
Для тех, кто еще не знаком с аргументом drop
функции индексирования, если вы хотите сохранить один столбец в качестве фрейма данных, выполните следующие действия:
keeps <- "y"
DF[ , keeps, drop = FALSE]
drop=TRUE
(или не упоминает об этом) отбросит ненужные размеры и, следовательно, вернет вектор со значениями столбца y
.
Там также команда subset
, полезная, если вы знаете, какие столбцы вы хотите:
df <- data.frame(a = 1:10, b = 2:11, c = 3:12)
df <- subset(df, select = c(a, c))
ОБНОВЛЕНО после комментария @hadley: Чтобы удалить столбцы a, c, вы можете сделать:
df <- subset(df, select = -c(a, c))
subset
R имела опцию, подобную «allbut = FALSE», которая «инвертирует» выборку, когда установлена в «TRUE», то есть сохраняет все столбцы, кроме тех, которые находятся в списке select
.
df[c("a", "c")]
within(df, rm(x))
вероятно, проще всего, или для нескольких переменных:
within(df, rm(x, y))
Или, если вы имеете дело с data.table
(согласно Как удалить столбец по имени в data.table?):
dt[, x := NULL] # Deletes column x by reference instantly.
dt[, !"x"] # Selects all but x into a new data.table.
или для нескольких переменных
dt[, c("x","y") := NULL]
dt[, !c("x", "y")]
within(df, rm(x))
является безусловно самым чистым решением. Учитывая, что это возможно, любой другой ответ кажется излишне сложным на порядок.
within(df, rm(x))
не будет работать, если в df
есть повторяющиеся столбцы с именем x
.
Вы можете использовать %in%
следующим образом:
df[, !(colnames(df) %in% c("x","bar","foo"))]
DF[ , !(names(DF) %in% drops)]
(NULL) также работает:
dat <- mtcars
colnames(dat)
# [1] "mpg" "cyl" "disp" "hp" "drat" "wt" "qsec" "vs" "am" "gear"
# [11] "carb"
dat[,c("mpg","cyl","wt")] <- list(NULL)
colnames(dat)
# [1] "disp" "hp" "drat" "qsec" "vs" "am" "gear" "carb"
Существует потенциально более мощная стратегия, основанная на том, что grep() вернет числовой вектор. Если у вас есть длинный список переменных, как в одном из моих наборов данных, некоторые переменные, которые заканчиваются на ".A" и другие, которые заканчиваются на ".B", и вам нужны только те, которые заканчиваются на ".A" (вдоль со всеми переменными, которые не соответствуют ни одному шаблону, выполните следующее:
dfrm2 <- dfrm[ , -grep("\\.B$", names(dfrm)) ]
В данном случае, используя пример Joris Meys, он может быть не таким компактным, но это будет:
DF <- DF[, -grep( paste("^",drops,"$", sep="", collapse="|"), names(DF) )]
drops
в первую очередь , как paste0("^", drop_cols, "$")
, это становится гораздо лучше (читай: более компактный) с sapply
: DF[ , -sapply(drops, grep, names(DF))]
Если вы хотите удалить столбцы по ссылке и избежать внутреннего копирования, связанного с data.frames
, то вы можете использовать пакет data.table
и функцию :=
Вы можете передать имена векторных символов в левой части оператора :=
и NULL
в качестве RHS.
library(data.table)
df <- data.frame(a=1:10, b=1:10, c=1:10, d=1:10)
DT <- data.table(df)
# or more simply DT <- data.table(a=1:10, b=1:10, c=1:10, d=1:10) #
DT[, c('a','b') := NULL]
Если вы хотите предопределить имена как символы символов вне вызова [
, оберните имя объекта в ()
или {}
, чтобы заставить LHS оцениваться в области вызова не как имя в пределах DT
.
del <- c('a','b')
DT <- data.table(a=1:10, b=1:10, c=1:10, d=1:10)
DT[, (del) := NULL]
DT <- <- data.table(a=1:10, b=1:10, c=1:10, d=1:10)
DT[, {del} := NULL]
# force or `c` would also work.
Вы также можете использовать set
, который позволяет избежать накладных расходов [.data.table
, , а также работает для data.frames
!
df <- data.frame(a=1:10, b=1:10, c=1:10, d=1:10)
DT <- data.table(df)
# drop `a` from df (no copying involved)
set(df, j = 'a', value = NULL)
# drop `b` from DT (no copying involved)
set(DT, j = 'b', value = NULL)
Другой ответ dplyr
. Если ваши переменные имеют некоторую общую структуру именования, вы можете попробовать starts_with()
. Например
library(dplyr)
df <- data.frame(var1 = rnorm(5), var2 = rnorm(5), var3 = rnorm (5),
var4 = rnorm(5), char1 = rnorm(5), char2 = rnorm(5))
df
# var2 char1 var4 var3 char2 var1
#1 -0.4629512 -0.3595079 -0.04763169 0.6398194 0.70996579 0.75879754
#2 0.5489027 0.1572841 -1.65313658 -1.3228020 -1.42785427 0.31168919
#3 -0.1707694 -0.9036500 0.47583030 -0.6636173 0.02116066 0.03983268
df1 <- df %>% select(-starts_with("char"))
df1
# var2 var4 var3 var1
#1 -0.4629512 -0.04763169 0.6398194 0.75879754
#2 0.5489027 -1.65313658 -1.3228020 0.31168919
#3 -0.1707694 0.47583030 -0.6636173 0.03983268
Если вы хотите отбросить последовательность кадров в фрейме данных, вы можете использовать :
. Например, если вы хотите сбросить var2
, var3
и все переменные между ними, вы просто останетесь с var1
:
df2 <- df1 %>% select(-c(var2:var3) )
df2
# var1
#1 0.75879754
#2 0.31168919
#3 0.03983268
select()
, таких как contains()
или matches()
, которые также принимают регулярные выражения.
Из интереса, это указывает на один из R странных множественных несоответствий синтаксиса. Например, для двухстолбцового кадра данных:
df <- data.frame(x=1, y=2)
Это дает фрейм данных
subset(df, select=-y)
но это дает вектор
df[,-2]
Все это объясняется в ?[
, но это не совсем ожидаемое поведение. Ну, по крайней мере, не мне...
DF <- data.frame(
x=1:10,
y=10:1,
z=rep(5,10),
a=11:20
)
DF
Выход:
x y z a
1 1 10 5 11
2 2 9 5 12
3 3 8 5 13
4 4 7 5 14
5 5 6 5 15
6 6 5 5 16
7 7 4 5 17
8 8 3 5 18
9 9 2 5 19
10 10 1 5 20
DF[c("a","x")] <- list(NULL)
Вывод:
y z
1 10 5
2 9 5
3 8 5
4 7 5
5 6 5
6 5 5
7 4 5
8 3 5
9 2 5
10 1 5
Другая возможность:
df <- df[, setdiff(names(df), c("a", "c"))]
или
df <- df[, grep('^(a|c)$', names(df), invert=TRUE)]
setdiff
является оптимальным, особенно в случае очень большого количества столбцов.
df <- df[ , -which(grepl('a|c', names(df)))]
: df <- df[ , -which(grepl('a|c', names(df)))]
Вот способ dplyr
:
#df[ -c(1,3:6, 12) ] # original
df.cut <- df %>% select(-col.to.drop.1, -col.to.drop.2, ..., -col.to.drop.6) # with dplyr::select()
Мне это нравится, потому что он интуитивно понятен для чтения и понимания без аннотаций и надежных для столбцов, изменяющих позицию в кадре данных. Он также следует за векторизованной идиомой, используя -
для удаления элементов.
%<>%
для замены входного объекта, его можно упростить до df %<>% select(-col.to.drop.1, -col.to.drop.2, ..., -col.to.drop.6)
dplyr
может быть проще сгруппировать их и поставить только один минус: df.cut <- df %>% select(-c(col.to.drop.1, col.to.drop.2, ..., col.to.drop.n))
Я продолжаю думать, что должна быть лучшая идиома, но для вычитания столбцов по имени я стараюсь сделать следующее:
df <- data.frame(a=1:10, b=1:10, c=1:10, d=1:10)
# return everything except a and c
df <- df[,-match(c("a","c"),names(df))]
df
df[,-match(c("e","f"),names(df))]
-
?
Решение Dplyr
Я сомневаюсь, что здесь будет уделено много внимания, но если у вас есть список столбцов, которые вы хотите удалить, и вы хотите сделать это в цепочке dplyr
я использую one_of()
в предложении select
:
Вот простой, воспроизводимый пример:
undesired <- c('mpg', 'cyl', 'hp')
mtcars %>%
select(-one_of(undesired))
Документацию можно найти, запустив ?one_of
или здесь:
http://genomicsclass.github.io/book/pages/dplyr_tutorial.html
В пакете Bernd Bischl BBmisc
есть функция, называемая dropNamed()
, которая делает именно это.
BBmisc::dropNamed(df, "x")
Преимущество состоит в том, что он избегает повторения аргумента кадра данных и, следовательно, подходит для трубопроводов в magrittr
(как и подходы dplyr
):
df %>% BBmisc::dropNamed("x")
Другое решение, если вы не хотите использовать @hadley выше: Если "COLUMN_NAME" - это имя столбца, который вы хотите удалить:
df[,-which(names(df) == "COLUMN_NAME")]
COLUMN_NAME
не находится в df
(проверьте себя: df<-data.frame(a=1,b=2)
). (3) df[,names(df) != "COLUMN_NAME"]
проще и не страдает от (2)
Помимо select(-one_of(drop_col_names))
продемонстрированного в предыдущих ответах, есть несколько других опций dplyr
для отбрасывания столбцов с использованием select()
которые не включают в себя определение всех конкретных имен столбцов (с использованием данных примера звездных звезд dplyr для некоторого разнообразия в имена столбцов):
library(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
Укажите фрейм данных и строку имен, разделенных запятыми, для удаления:
remove_features <- function(df, features) {
rem_vec <- unlist(strsplit(features, ', '))
res <- df[,!(names(df) %in% rem_vec)]
return(res)
}
Использование:
remove_features(iris, "Sepal.Length, Petal.Width")
мы также можем использовать следующее:
library(dplyr)
a <- rnorm(10)
b <- rnorm(10)
c <- rnorm(10)
d <- rnorm(10)
e <- data.frame(a,b,c,d)
e
a b c d
1 1.43302370 -0.7432732 -1.253633400 0.5939462
2 1.98039990 0.1887923 0.291446236 0.3329504
3 -0.36722148 -1.8049586 -0.443291873 1.0630998
4 -1.04413463 1.4655549 0.001105352 -0.3041839
5 0.56971963 0.1532533 0.074341324 0.3700188
6 -0.13505460 2.1726117 -0.589520946 0.2670988
7 2.40161776 0.4755095 -0.568668733 -0.5425200
8 -0.03924000 -0.7099464 -0.135178615 1.2078678
9 0.68973936 0.6107264 1.178086997 1.1604026
10 0.02800216 -0.9340976 -1.523566800 0.7002136
e <- select(e, -c(a,b))
e
c d
1 -1.253633400 0.5939462
2 0.291446236 0.3329504
3 -0.443291873 1.0630998
4 0.001105352 -0.3041839
5 0.074341324 0.3700188
6 -0.589520946 0.2670988
7 -0.568668733 -0.5425200
8 -0.135178615 1.2078678
9 1.178086997 1.1604026
10 -1.523566800 0.7002136
Найдите индекс столбцов, которые вы хотите удалить, используя which
. Дайте этим индексам отрицательный знак (*-1
). Затем подмножество этих значений, которые будут удалять их из кадра данных. Это пример.
DF <- data.frame(one=c('a','b'), two=c('c', 'd'), three=c('e', 'f'), four=c('g', 'h'))
DF
# one two three four
#1 a d f i
#2 b e g j
DF[which(names(DF) %in% c('two','three')) *-1]
# one four
#1 a g
#2 b h
Я думаю, что у всех отсутствует один метод удаления столбца с использованием значения индекса. Ниже приведен код для него:
>g = 1:10
>r = 11:20
>h = data.frame(g,r)
>h
g r
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5
6 6 6
7 7 7
8 8 8
9 9 9
10 10 10
>h = h[,-2]
>h
[1] 1 2 3 4 5 6 7 8 9 10
Надеюсь, что это поможет:)
df#drop(var_name)
, и вместо этого нам нужно выполнить эти сложные обходные пути?