Come rimuovi le colonne da un data.frame?

Non tanto ‘Come fai …?’ ma più ‘Come si …?’

Se hai un file che ti dà 200 colonne e vuoi ridurlo a pochi quelli che ti servono per l’analisi, come lo fai? Una soluzione offre vantaggi rispetto ad un’altra?

Supponendo che abbiamo un frame di dati con colonne col1, col2 attraverso col200. Se volevi solo 1-100 e poi 125-135 e 150-200, potresti:

dat$col101 <- NULL dat$col102 <- NULL # etc 

o

 dat <- dat[,c("col1","col2",...)] 

o

 dat <- dat[,c(1:100,125:135,...)] # shortest probably but I don't like this 

o

 dat <- dat[,!names(dat) %in% c("dat101","dat102",...)] 

Qualcos’altro che mi manca? So che questo è visivamente soggettivo, ma è una di quelle cose nitide e grintose in cui potresti tuffarti e iniziare a farlo in un modo e cadere in un’abitudine quando ci sono modi molto più efficienti là fuori. Molto simile a questa domanda su quale .

MODIFICARE:

Oppure esiste un modo semplice per creare un vettore realizzabile dei nomi delle colonne? nome (dat) non li stampa con le virgole in mezzo, di cui hai bisogno negli esempi di codice sopra, quindi se stampi i nomi in questo modo hai spazi ovunque e devi inserire manualmente le virgole … Esiste un comando che ti darà “col1”, “col2”, “col3”, … come output in modo da poter afferrare facilmente ciò che vuoi?

Uso data.table ‘s := operator per eliminare le colonne istantaneamente indipendentemente dalla dimensione della tabella.

 DT[, coltodelete := NULL] 

o

 DT[, c("col1","col20") := NULL] 

o

 DT[, (125:135) := NULL] 

o

 DT[, (variableHoldingNamesOrNumbers) := NULL] 

Qualsiasi soluzione che utilizzi <- o subset copierà l' intera tabella. data.table 's := operatore modifica semplicemente il vettore interno dei puntatori alle colonne, in posizione. Quell'operazione è quindi (quasi) istantanea.

Per eliminare singole colonne, userò solo dat$x <- NULL .

Per cancellare più colonne, ma meno di circa 3-4, userò dat$x <- dat$y <- dat$z <- NULL .

Per di più, userò subset , con nomi negativi (!):

 subset(mtcars, , -c(mpg, cyl, disp, hp)) 

A fini di chiarezza, utilizzo spesso l’argomento select in subset . Con le persone più nuove, ho imparato che mantenere il numero di comandi di cui hanno bisogno per arrivare al minimo aiuta l’adozione. Con l’aumentare delle loro capacità, aumenterà anche la loro capacità di codifica. E il sottoinsieme è uno dei primi comandi che mostro alle persone quando è necessario selezionare i dati all’interno di un determinato criterio.

Qualcosa di simile a:

 > subset(mtcars, select = c("mpg", "cyl", "vs", "am")) mpg cyl vs am Mazda RX4 21.0 6 0 1 Mazda RX4 Wag 21.0 6 0 1 Datsun 710 22.8 4 1 1 .... 

Sono sicuro che questo testerà più lentamente della maggior parte delle altre soluzioni, ma raramente sono al punto in cui i microsecondi fanno la differenza.

Utilizza read.table con istanze di colClasses di “NULL” per evitare di crearli in primo luogo:

 ## example data and temp file x <- data.frame(x = 1:10, y = rnorm(10), z = runif(10), a = letters[1:10], stringsAsFactors = FALSE) tmp <- tempfile() write.table(x, tmp, row.names = FALSE) (y <- read.table(tmp, colClasses = c("numeric", rep("NULL", 2), "character"), header = TRUE)) xa 1 1 a 2 2 b 3 3 c 4 4 d 5 5 e 6 6 f 7 7 g 8 8 h 9 9 i 10 10 j unlink(tmp) 

Per i tipi di file di grandi dimensioni che tendo a ottenere, in genere non lo farei nemmeno in R. Userò il comando di cut in Linux per elaborare i dati prima che arrivi a R. Questa non è una critica di R, solo una preferenza per l’uso di alcuni strumenti Linux molto basilari come grep, tr, cut, sort, uniq e occasionalmente sed & awk (o Perl) quando c’è qualcosa da fare sulle espressioni regolari.

Un altro motivo per usare i comandi GNU standard è che posso passarli alla fonte dei dati e chiedere loro di prefiltrare i dati in modo da non ottenere dati estranei. La maggior parte dei miei colleghi sono competenti con Linux, meno sanno R.

(Aggiornato) Un metodo che vorrei usare in breve tempo è quello di accoppiare mmap con un file di testo ed esaminare i dati in situ , piuttosto che leggerli affatto nella RAM. L’ho fatto con C, e può essere velocissimo.

A volte mi piace farlo usando gli id ​​delle colonne.

 df <- data.frame(a=rnorm(100), b=rnorm(100), c=rnorm(100), d=rnorm(100), e=rnorm(100), f=rnorm(100), g=rnorm(100)) 

as.data.frame (nomi (df))

  names(df) 1 a 2 b 3 c 4 d 5 e 6 f 7 g 

Rimozione delle colonne "c" e "g"

 df[,-c(3,7)] 

Ciò è particolarmente utile se si dispone di data.frames di grandi dimensioni o di nomi di colonna lunghi che non si desidera digitare. O nomi di colonne che seguono uno schema, perché in questo caso puoi usare seq () per rimuoverlo.

RE: la tua modifica

Non devi necessariamente mettere "" attorno a una stringa, né "," per creare un vettore di caratteri. Trovo questo piccolo trucco a portata di mano:

 x <- unlist(strsplit( 'A B C D E',"\n")) 

Basta indirizzare la modifica.

@ nzcoops, non hai bisogno dei nomi delle colonne in un vettore di caratteri delimitati da virgole. Stai pensando a questo nel modo sbagliato. Quando lo fai

 vec <- c("col1", "col2", "col3") 

stai creando un vettore di caratteri. Il , separa solo gli argomenti presi dalla funzione c() quando si definisce quel vettore. names() e funzioni simili restituiscono un carattere vettoriale di nomi.

 > dat <- data.frame(col1 = 1:3, col2 = 1:3, col3 = 1:3) > dat col1 col2 col3 1 1 1 1 2 2 2 2 3 3 3 3 > names(dat) [1] "col1" "col2" "col3" 

È molto più facile e meno incline agli errori selezionare gli elementi dei names(dat) piuttosto che elaborare l'output in una stringa separata da virgole da cui è ansible tagliare e incollare.

Diciamo che vogliamo le colonne col1 e col2 , i names(dat) sottoinsiemi names(dat) , mantenendo solo quelli che vogliamo:

 > names(dat)[c(1,3)] [1] "col1" "col3" > dat[, names(dat)[c(1,3)]] col1 col3 1 1 1 2 2 2 3 3 3 

Puoi fare quello che vuoi, ma R stamperà sempre il vettore sullo schermo tra virgolette " :

 > paste('"', names(dat), '"', sep = "", collapse = ", ") [1] "\"col1\", \"col2\", \"col3\"" > paste("'", names(dat), "'", sep = "", collapse = ", ") [1] "'col1', 'col2', 'col3'" 

quindi quest'ultimo può essere più utile. Tuttavia, ora devi tagliare e passare da quella stringa. Molto meglio lavorare con oggetti che restituiscono ciò che si desidera e utilizzare routine di subsetting standard per mantenere ciò di cui si ha bisogno.

Se si dispone già di un vettore di nomi, che esistono diversi modi per creare, è ansible utilizzare facilmente la funzione sottoinsieme per mantenere o rilasciare un object.

 dat2 <- subset(dat, select = names(dat) %in% c(KEEP)) 

In questo caso, KEEP è un vettore di nomi di colonne che è stato creato in precedenza. Per esempio:

 #sample data via Brandon Bertelsen df <- data.frame(a=rnorm(100), b=rnorm(100), c=rnorm(100), d=rnorm(100), e=rnorm(100), f=rnorm(100), g=rnorm(100)) #creating the initial vector of names df1 <- as.matrix(as.character(names(df))) #retaining only the name values you want to keep KEEP <- as.vector(df1[c(1:3,5,6),]) #subsetting the intial dataset with the object KEEP df3 <- subset(df, select = names(df) %in% c(KEEP)) 

Quale risulta in:

 > head(df) abcd 1 1.05526388 0.6316023 -0.04230455 -0.1486299 2 -0.52584236 0.5596705 2.26831758 0.3871873 3 1.88565261 0.9727644 0.99708383 1.8495017 4 -0.58942525 -0.3874654 0.48173439 1.4137227 5 -0.03898588 -1.5297600 0.85594964 0.7353428 6 1.58860643 -1.6878690 0.79997390 1.1935813 efg 1 -1.42751190 0.09842343 -0.01543444 2 -0.62431091 -0.33265572 -0.15539472 3 1.15130591 0.37556903 -1.46640276 4 -1.28886526 -0.50547059 -2.20156926 5 -0.03915009 -1.38281923 0.60811360 6 -1.68024349 -1.18317733 0.42014397 > head(df3) abce 1 1.05526388 0.6316023 -0.04230455 -1.42751190 2 -0.52584236 0.5596705 2.26831758 -0.62431091 3 1.88565261 0.9727644 0.99708383 1.15130591 4 -0.58942525 -0.3874654 0.48173439 -1.28886526 5 -0.03898588 -1.5297600 0.85594964 -0.03915009 6 1.58860643 -1.6878690 0.79997390 -1.68024349 f 1 0.09842343 2 -0.33265572 3 0.37556903 4 -0.50547059 5 -1.38281923 6 -1.18317733 

Da http://www.statmethods.net/management/subset.html

 # exclude variables v1, v2, v3 myvars <- names(mydata) %in% c("v1", "v2", "v3") newdata <- mydata[!myvars] # exclude 3rd and 5th variable newdata <- mydata[c(-3,-5)] # delete variables v3 and v5 mydata$v3 <- mydata$v5 <- NULL 

Ho pensato che fosse davvero intelligente fare una lista di "non includere"

Può usare la funzione setdiff :

Se ci sono più colonne da conservare che da cancellare: Supponiamo di voler cancellare 2 colonne, diciamo col1, col2 da un DT di data.frame; puoi fare quanto segue:

 DT<-DT[,setdiff(names(DT),c("col1","col2"))] 

Se ci sono più colonne da eliminare che tenere: Supponiamo di voler mantenere solo col1 e col2:

 DT<-DT[,c("col1","col2")] 

La funzione select() di dplyr è potente per il subsetting delle colonne. Vedi ?select_helpers per una lista di approcci.

In questo caso, dove hai un prefisso comune e numeri sequenziali per i nomi delle colonne, potresti usare num_range :

 library(dplyr) df1 <- data.frame(first = 0, col1 = 1, col2 = 2, col3 = 3, col4 = 4) df1 %>% select(num_range("col", c(1, 4))) #> col1 col4 #> 1 1 4 

Più in generale puoi usare il segno meno in select() per rilasciare colonne, come:

 mtcars %>% select(-mpg, -wt) 

Infine, alla tua domanda “c’è un modo semplice per creare un vettore realizzabile dei nomi delle colonne?” – sì, se hai bisogno di modificare manualmente un elenco di nomi, usa dput per ottenere un elenco quotato e separato da virgole che puoi facilmente manipolare:

 dput(names(mtcars)) #> c("mpg", "cyl", "disp", "hp", "drat", "wt", "qsec", "vs", "am", #> "gear", "carb")