it-swarm.it

Trascinare le colonne del frame di dati per nome

Ho un numero di colonne che vorrei rimuovere da un frame di dati. So che possiamo eliminarli individualmente usando qualcosa come:

df$x <- NULL

Ma speravo di farlo con meno comandi.

Inoltre, so che potrei rilasciare colonne usando l'indice intero come questo:

df <- df[ -c(1, 3:6, 12) ]

Ma sono preoccupato che la posizione relativa delle mie variabili possa cambiare.

Considerato quanto sia potente R, ho pensato che potrebbe esserci un modo migliore di lasciar cadere una colonna una per una.

768
Btibert3

Puoi usare un semplice elenco di nomi:

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)]

Oppure, in alternativa, puoi creare un elenco di quelli da conservare e fare riferimento ad essi per nome:

keeps <- c("y", "a")
DF[keeps]

EDIT: per coloro che non hanno ancora familiarizzato con l'argomento drop della funzione di indicizzazione, se si desidera mantenere una colonna come frame di dati, si esegue:

keeps <- "y"
DF[ , keeps, drop = FALSE]

drop=TRUE (o non menzionandolo) eliminerà le dimensioni non necessarie e quindi restituirà un vettore con i valori della colonna y.

817
Joris Meys

C'è anche il comando subset, utile se sai quali colonne vuoi:

df <- data.frame(a = 1:10, b = 2:11, c = 3:12)
df <- subset(df, select = c(a, c))

AGGIORNATO dopo il commento di @hadley: A drop colonne a, c puoi fare:

df <- subset(df, select = -c(a, c))
399
within(df, rm(x))

è probabilmente più semplice o per più variabili:

within(df, rm(x, y))

O se hai a che fare con data.tables (per Come si elimina una colonna per nome in data.table? ):

dt[, x := NULL]   # Deletes column x by reference instantly.

dt[, !"x"]   # Selects all but x into a new data.table.

o per più variabili

dt[, c("x","y") := NULL]

dt[, !c("x", "y")]
155
Max Ghenis

Potresti usare %in% in questo modo:

df[, !(colnames(df) %in% c("x","bar","foo"))]
101
Joshua Ulrich

lista (NULL) funziona anche:

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"
44
Vincent

Esiste una strategia potenzialmente più potente basata sul fatto che grep () restituirà un vettore numerico. Se hai una lunga lista di variabili come faccio in uno dei miei set di dati, alcune variabili che terminano in ".A" e altre che terminano in ".B" e vuoi solo quelle che terminano in ".A" (lungo con tutte le variabili che non corrispondono a nessuno dei due pattern, fai questo:

dfrm2 <- dfrm[ , -grep("\\.B$", names(dfrm)) ]

Per il caso in questione, usando l'esempio di Joris Meys, potrebbe non essere così compatto, ma sarebbe:

DF <- DF[, -grep( paste("^",drops,"$", sep="", collapse="|"), names(DF) )]
37
42-

Se si desidera rimuovere le colonne per riferimento ed evitare la copia interna associata a data.frames, è possibile utilizzare il pacchetto data.table e la funzione :=

Puoi passare i nomi di un vettore di caratteri sul lato sinistro dell'operatore := e NULL come 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]

Se si desidera predefinire i nomi come vettore di caratteri al di fuori della chiamata a [, racchiudere il nome dell'oggetto in () o {} per forzare la valutazione dell'LHS nell'ambito della chiamata non come un nome nell'ambito di 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.   

Puoi anche usare set, che evita il sovraccarico di [.data.table, e funziona anche per 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)
37
mnel

Un'altra risposta dplyr. Se le tue variabili hanno una struttura di denominazione comune, potresti provare starts_with(). Per esempio

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

Se si desidera eliminare una sequenza di variabili nel frame di dati, è possibile utilizzare :. Ad esempio, se si desidera rilasciare var2, var3 e tutte le variabili in mezzo, verrebbe lasciato con var1:

df2 <- df1 %>% select(-c(var2:var3) )  
df2
#        var1
#1 0.75879754
#2 0.31168919
#3 0.03983268
24
Pat W.
DF <- data.frame(
  x=1:10,
  y=10:1,
  z=rep(5,10),
  a=11:20
)
DF

in uscita:

    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)

in uscita:

        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
20
Kun Ren

Interessante, questo evidenzia una delle strane incoerenze multiple di sintassi di R. Ad esempio, dato un frame di dati a due colonne:

df <- data.frame(x=1, y=2)

Questo dà una cornice di dati

subset(df, select=-y)

ma questo dà un vettore

df[,-2]

Questo è tutto spiegato in ?[ ma non è esattamente il comportamento previsto. Beh, almeno non per me ...

20
jkeirstead

Un'altra possibilità:

df <- df[, setdiff(names(df), c("a", "c"))]

o

df <- df[, grep('^(a|c)$', names(df), invert=TRUE)]
19
scentoni

Ecco un modo dplyr per risolverlo:

#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()

Mi piace perché è intuitivo leggere e comprendere senza annotazioni e robusto per le colonne che cambiano posizione all'interno del frame dei dati. Segue anche l'idioma vettorializzato usando - per rimuovere elementi.

18
c.gutierrez

Soluzione Dplyr

Dubito che questo avrà molta attenzione qui, ma se hai un elenco di colonne che vuoi rimuovere e vuoi farlo in una catena dplyr io uso one_of() nella clausola select:

Ecco un esempio semplice e riproducibile:

undesired <- c('mpg', 'cyl', 'hp')

mtcars <- mtcars %>%
  select(-one_of(undesired))

La documentazione può essere trovata eseguendo ?one_of o qui:

http://genomicsclass.github.io/book/pages/dplyr_tutorial.html

17
User632716

Continuo a pensare che ci deve essere un idioma migliore, ma per la sottrazione di colonne per nome, tendo a fare quanto segue:

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
13
JD Long

C'è una funzione chiamata dropNamed() nel pacchetto BBmisc di Bernd Bischl che fa esattamente questo.

BBmisc::dropNamed(df, "x")

Il vantaggio è che evita di ripetere l'argomento del frame di dati e quindi è adatto per il piping in magrittr (proprio come gli approcci dplyr):

df %>% BBmisc::dropNamed("x")
11
krlmlr

Un'altra soluzione se non si desidera utilizzare @ hadley sopra: Se "COLUMN_NAME" è il nome della colonna che si desidera eliminare:

df[,-which(names(df) == "COLUMN_NAME")]
7
Nick Keramaris

Oltre a select(-one_of(drop_col_names)) dimostrato nelle risposte precedenti, ci sono un paio di altre opzioni dplyr per il dropping di colonne che usano select() che non comportano la definizione di tutti i nomi di colonna specifici (usando i dati di esempio di starwars di dplyr per alcune varietà nei nomi delle colonne):

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 
5
sbha

Fornisci il frame dati e una stringa di nomi separati da virgola per rimuovere:

remove_features <- function(df, features) {
  rem_vec <- unlist(strsplit(features, ', '))
  res <- df[,!(names(df) %in% rem_vec)]
  return(res)
}

Uso :

remove_features(iris, "Sepal.Length, Petal.Width")

enter image description here

3
Cybernetic

Trova l'indice delle colonne che vuoi eliminare usando which. Dare a questi indici un segno negativo (*-1). Quindi imposta sotto questi valori, che li rimuoveranno dal dataframe. Questo è un esempio.

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
1
milan