Ik heb een aantal kolommen die ik uit een dataframe wil verwijderen. Ik weet dat we ze afzonderlijk kunnen verwijderen met iets als:
df$x <- NULL
Maar ik hoopte dit met minder opdrachten te doen.
Ik weet ook dat ik kolommen kan laten vallen met behulp van integer indexeren als volgt:
df <- df[ -c(1, 3:6, 12) ]
Maar ik ben bang dat de relatieve positie van mijn variabelen kan veranderen.
Gezien hoe krachtig R is, dacht ik dat er misschien een betere manier was dan elke kolom één voor één te laten vallen.
Antwoord 1, autoriteit 100%
U kunt een eenvoudige lijst met namen gebruiken:
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)]
Of u kunt ook een lijst maken van degenen die u wilt bewaren en er bij naam naar verwijzen:
keeps <- c("y", "a")
DF[keeps]
BEWERKEN:
Voor degenen die nog steeds niet bekend zijn met het argument drop
van de indexeringsfunctie, als u één kolom als gegevensframe wilt behouden, doet u het volgende:
keeps <- "y"
DF[ , keeps, drop = FALSE]
drop=TRUE
(of niet vermelden) zal onnodige dimensies laten vallen en dus een vector retourneren met de waarden van kolom y
.
Antwoord 2, autoriteit 50%
Er is ook de opdracht subset
, handig als je weet welke kolommen je wilt:
df <- data.frame(a = 1:10, b = 2:11, c = 3:12)
df <- subset(df, select = c(a, c))
GE-UPDATE na opmerking van @hadley: kolommen a,c laten vallenzou je kunnen doen:
df <- subset(df, select = -c(a, c))
Antwoord 3, autoriteit 24%
within(df, rm(x))
is waarschijnlijk het gemakkelijkst, of voor meerdere variabelen:
within(df, rm(x, y))
Of als je te maken hebt met data.table
s (per Hoe verwijder je een kolom op naam in data.table?):
dt[, x := NULL] # Deletes column x by reference instantly.
dt[, !"x"] # Selects all but x into a new data.table.
of voor meerdere variabelen
dt[, c("x","y") := NULL]
dt[, !c("x", "y")]
Antwoord 4, autoriteit 13%
Je zou %in%
als volgt kunnen gebruiken:
df[, !(colnames(df) %in% c("x","bar","foo"))]
Antwoord 5, autoriteit 6%
list(NULL) werkt ook:
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"
Antwoord 6, autoriteit 5%
Als u de kolommen per referentie wilt verwijderen en het interne kopiëren van data.frames
wilt vermijden, dan kunt u het pakket data.table
en de functie :=
Je kunt tekenvectornamen doorgeven aan de linkerkant van de operator :=
en NULL
als de 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]
Als u de namen vooraf wilt definiëren als tekenvector buiten de aanroep van [
, zet u de naam van het object in ()
of {}
om te forceren dat de LHS wordt geëvalueerd in het aanroepende bereik, niet als een naam binnen het bereik van 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.
U kunt ook set
gebruiken, wat de overhead van [.data.table
, vermijdt en ook werkt voor 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)
Antwoord 7, autoriteit 4%
Er is een potentieel krachtigere strategie gebaseerd op het feit dat grep() een numerieke vector retourneert. Als je een lange lijst met variabelen hebt zoals ik in een van mijn datasets, sommige variabelen die eindigen op “.A” en andere die eindigen op “.B” en je wilt alleen de variabelen die eindigen op “.A” (samen met doe dit met alle variabelen die niet overeenkomen met een van beide patronen:
dfrm2 <- dfrm[ , -grep("\\.B$", names(dfrm)) ]
Voor het onderhavige geval, met het voorbeeld van Joris Meys, is het misschien niet zo compact, maar het zou zijn:
DF <- DF[, -grep( paste("^",drops,"$", sep="", collapse="|"), names(DF) )]
Antwoord 8, autoriteit 3%
Nog een dplyr
antwoord. Als uw variabelen een gemeenschappelijke naamgevingsstructuur hebben, kunt u starts_with()
proberen. Bijvoorbeeld
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
Als u een reeks variabelen in het dataframe wilt neerzetten, kunt u :
gebruiken. Als u bijvoorbeeld var2
, var3
en allevariabelen ertussen wilt laten vallen, houdt u gewoon var1
:
df2 <- df1 %>% select(-c(var2:var3) )
df2
# var1
#1 0.75879754
#2 0.31168919
#3 0.03983268
Antwoord 9, autoriteit 3%
Dplyr-oplossing
Ik betwijfel of dit hier veel aandacht zal krijgen, maar als je een lijst met kolommen hebt die je wilt verwijderen, en je wilt het in een dplyr
-keten doen, gebruik ik one_of()
in de select
-clausule:
Hier is een eenvoudig, reproduceerbaar voorbeeld:
undesired <- c('mpg', 'cyl', 'hp')
mtcars <- mtcars %>%
select(-one_of(undesired))
Documentatie kan worden gevonden door ?one_of
uit te voeren of hier:
http://genomicsclass.github.io/book/pages/dplyr_tutorial.html
Antwoord 10, autoriteit 3%
Een andere mogelijkheid:
df <- df[, setdiff(names(df), c("a", "c"))]
of
df <- df[, grep('^(a|c)$', names(df), invert=TRUE)]
Antwoord 11, autoriteit 2%
DF <- data.frame(
x=1:10,
y=10:1,
z=rep(5,10),
a=11:20
)
DF
Uitvoer:
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)
Uitvoer:
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
Antwoord 12, autoriteit 2%
Uit interesse signaleert dit een van de vreemde meervoudige syntaxisinconsistenties van R. Bijvoorbeeld gegeven een gegevensframe met twee kolommen:
df <- data.frame(x=1, y=2)
Dit geeft een dataframe
subset(df, select=-y)
maar dit geeft een vector
df[,-2]
Dit wordt allemaal uitgelegd in ?[
maar het is niet echt verwacht gedrag. In ieder geval niet voor mij…
Antwoord 13, autoriteit 2%
Hier is een dplyr
manier om dit aan te pakken:
#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()
Ik vind dit leuk omdat het intuïtief is om & begrijpen zonder annotatie en robuust voor kolommen die van positie veranderen binnen het dataframe. Het volgt ook het gevectoriseerde idioom dat -
gebruikt om elementen te verwijderen.
Antwoord 14
Ik blijf denken dat er een beter idioom moet zijn, maar voor het aftrekken van kolommen op naam, heb ik de neiging om het volgende te doen:
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
Antwoord 15
Er is een functie genaamd dropNamed()
in het BBmisc
-pakket van Bernd Bischl die precies dit doet.
BBmisc::dropNamed(df, "x")
Het voordeel is dat het herhaling van het dataframe-argument voorkomt en dus geschikt is voor piping in magrittr
(net als de dplyr
-benaderingen):
df %>% BBmisc::dropNamed("x")
Antwoord 16
Een andere oplossing als u de bovenstaande gegevens van @hadley niet wilt gebruiken: Als “COLUMN_NAME” de naam is van de kolom die u wilt verwijderen:
df[,-which(names(df) == "COLUMN_NAME")]
Antwoord 17
Naast select(-one_of(drop_col_names))
gedemonstreerd in eerdere antwoorden, zijn er een paar andere dplyr
opties voor het neerzetten van kolommen met behulp van select()
waarbij niet alle specifieke kolomnamen moeten worden gedefinieerd (met behulp van de dplyr starwars-voorbeeldgegevens voor enige variatie in kolomnamen):
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
Als u een kolom moet verwijderen die al dan niet in het dataframe bestaat, is hier een kleine draai aan het gebruik van select_if()
die, in tegenstelling tot het gebruik van one_of()
gooi geen Unknown columns:
waarschuwing als de kolomnaam niet bestaat. In dit voorbeeld is ‘bad_column’ geen kolom in het dataframe:
starwars %>%
select_if(!names(.) %in% c('height', 'mass', 'bad_column'))
Antwoord 18
Geef het gegevensframeen een reeks door komma’s gescheiden namenop om te verwijderen:
remove_features <- function(df, features) {
rem_vec <- unlist(strsplit(features, ', '))
res <- df[,!(names(df) %in% rem_vec)]
return(res)
}
Gebruik:
remove_features(iris, "Sepal.Length, Petal.Width")
Antwoord 19
Zoek de index van de kolommen die u wilt verwijderen met which
. Geef deze indexen een minteken (*-1
). Subset vervolgens op die waarden, waardoor ze uit het dataframe worden verwijderd. Dit is een voorbeeld.
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
Antwoord 20
Als je een groot data.frame
hebt en weinig geheugen hebt, gebruik dan [
....of rm
en within
om kolommen van een data.frame
te verwijderen, als subset
gebruikt momenteel (R 3.6.2) meer geheugen – naast de hint van de handleiding om subset
interactief te gebruiken.
getData <- function() {
n <- 1e7
set.seed(7)
data.frame(a = runif(n), b = runif(n), c = runif(n), d = runif(n))
}
DF <- getData()
tt <- sum(.Internal(gc(FALSE, TRUE, TRUE))[13:14])
DF <- DF[setdiff(names(DF), c("a", "c"))] ##
#DF <- DF[!(names(DF) %in% c("a", "c"))] #Alternative
#DF <- DF[-match(c("a","c"),names(DF))] #Alternative
sum(.Internal(gc(FALSE, FALSE, TRUE))[13:14]) - tt
#0.1 MB are used
DF <- getData()
tt <- sum(.Internal(gc(FALSE, TRUE, TRUE))[13:14])
DF <- subset(DF, select = -c(a, c)) ##
sum(.Internal(gc(FALSE, FALSE, TRUE))[13:14]) - tt
#357 MB are used
DF <- getData()
tt <- sum(.Internal(gc(FALSE, TRUE, TRUE))[13:14])
DF <- within(DF, rm(a, c)) ##
sum(.Internal(gc(FALSE, FALSE, TRUE))[13:14]) - tt
#0.1 MB are used
DF <- getData()
tt <- sum(.Internal(gc(FALSE, TRUE, TRUE))[13:14])
DF[c("a", "c")] <- NULL ##
sum(.Internal(gc(FALSE, FALSE, TRUE))[13:14]) - tt
#0.1 MB are used