Kolommen op naam in een gegevensframe neerzetten

Ik heb een grote dataset en ik wil graag specifieke kolommen lezen of alle andere schrappen.

data <- read.dta("file.dta")

Ik selecteer de kolommen waarin ik niet geïnteresseerd ben:

var.out <- names(data)[!names(data) %in% c("iden", "name", "x_serv", "m_serv")]

en dan zou ik iets willen doen als:

for(i in 1:length(var.out)) {
   paste("data$", var.out[i], sep="") <- NULL
}

om alle ongewenste kolommen te verwijderen. Is dit de optimale oplossing?


Antwoord 1, autoriteit 100%

U moet ofwel indexeren of de functie subsetgebruiken. Bijvoorbeeld:

R> df <- data.frame(x=1:5, y=2:6, z=3:7, u=4:8)
R> df
  x y z u
1 1 2 3 4
2 2 3 4 5
3 3 4 5 6
4 4 5 6 7
5 5 6 7 8

Vervolgens kunt u de functie whichen de operator -gebruiken in kolomindexering :

R> df[ , -which(names(df) %in% c("z","u"))]
  x y
1 1 2
2 2 3
3 3 4
4 4 5
5 5 6

Of, veel eenvoudiger, gebruik het argument selectvan de functie subset: u kunt dan de operator -rechtstreeks op een vector van kolomnamen, en u kunt zelfs de aanhalingstekens rond de namen weglaten!

R> subset(df, select=-c(z,u))
  x y
1 1 2
2 2 3
3 3 4
4 4 5
5 5 6

Houd er rekening mee dat u ook de gewenste kolommen kunt selecteren in plaats van de andere te laten vallen:

R> df[ , c("x","y")]
  x y
1 1 2
2 2 3
3 3 4
4 4 5
5 5 6
R> subset(df, select=c(x,y))
  x y
1 1 2
2 2 3
3 3 4
4 4 5
5 5 6

Antwoord 2, autoriteit 32%

Gebruik -which()hiervoor niet, het is extreem gevaarlijk. Overweeg:

dat <- data.frame(x=1:5, y=2:6, z=3:7, u=4:8)
dat[ , -which(names(dat) %in% c("z","u"))] ## works as expected
dat[ , -which(names(dat) %in% c("foo","bar"))] ## deletes all columns! Probably not what you wanted...

Gebruik in plaats daarvan subset of de functie !:

dat[ , !names(dat) %in% c("z","u")] ## works as expected
dat[ , !names(dat) %in% c("foo","bar")] ## returns the un-altered data.frame. Probably what you want

Ik heb dit uit pijnlijke ervaring geleerd. Gebruik which()niet te veel!


Antwoord 3, autoriteit 12%

Ten eerstekunt u directe indexering (met booleans vectoren) gebruiken in plaats van opnieuw toegang te krijgen tot kolomnamen als u met hetzelfde dataframe werkt; het zal veiliger zijn, zoals aangegeven door Ista, en sneller te schrijven en uit te voeren. Dus wat je alleen nodig hebt is:

var.out.bool <- !names(data) %in% c("iden", "name", "x_serv", "m_serv")

en dan, eenvoudig gegevens opnieuw toewijzen:

data <- data[,var.out.bool] # or...
data <- data[,var.out.bool, drop = FALSE] # You will need this option to avoid the conversion to an atomic vector if there is only one column left

Ten tweede, sneller te schrijven, kunt u direct NULL toewijzen aan de kolommen die u wilt verwijderen:

data[c("iden", "name", "x_serv", "m_serv")] <- list(NULL) # You need list() to respect the target structure.

Eindelijkkun je subset() gebruiken, maar het kan niet echt in de code worden gebruikt (zelfs het helpbestand waarschuwt ervoor). Een specifiek probleem voor mij is dat als je de drop-functie van susbset() direct wilt gebruiken, je de uitdrukking die overeenkomt met de kolomnamen moet schrijven zonder aanhalingstekens:

subset( data, select = -c("iden", "name", "x_serv", "m_serv") ) # WILL NOT WORK
subset( data, select = -c(iden, name, x_serv, m_serv) ) # WILL

Als bonusis hier een kleine benchmark van de verschillende opties, waaruit duidelijk blijkt dat de subset langzamer is en dat de eerste, opnieuw toewijzende methode de snellere is:

                                       re_assign(dtest, drop_vec)  46.719  52.5655  54.6460  59.0400  1347.331
                                      null_assign(dtest, drop_vec)  74.593  83.0585  86.2025  94.0035  1476.150
               subset(dtest, select = !names(dtest) %in% drop_vec) 106.280 115.4810 120.3435 131.4665 65133.780
 subset(dtest, select = names(dtest)[!names(dtest) %in% drop_vec]) 108.611 119.4830 124.0865 135.4270  1599.577
                                  subset(dtest, select = -c(x, y)) 102.026 111.2680 115.7035 126.2320  1484.174

Microbench-grafiek

Codestaat hieronder:

dtest <- data.frame(x=1:5, y=2:6, z = 3:7)
drop_vec <- c("x", "y")
null_assign <- function(df, names) {
  df[names] <- list(NULL)
  df
}
re_assign <- function(df, drop) {
  df <- df [, ! names(df) %in% drop, drop = FALSE]
  df
}
res <- microbenchmark(
  re_assign(dtest,drop_vec),
  null_assign(dtest,drop_vec),
  subset(dtest, select = ! names(dtest) %in% drop_vec),
  subset(dtest, select = names(dtest)[! names(dtest) %in% drop_vec]),
  subset(dtest, select = -c(x, y) ),
times=5000)
plt <- ggplot2::qplot(y=time, data=res[res$time < 1000000,], colour=expr)
plt <- plt + ggplot2::scale_y_log10() + 
  ggplot2::labs(colour = "expression") + 
  ggplot2::scale_color_discrete(labels = c("re_assign", "null_assign", "subset_bool", "subset_names", "subset_drop")) +
  ggplot2::theme_bw(base_size=16)
print(plt)

Antwoord 4, autoriteit 7%

Je kunt ook het pakket dplyrproberen:

R> df <- data.frame(x=1:5, y=2:6, z=3:7, u=4:8)
R> df
  x y z u
1 1 2 3 4
2 2 3 4 5
3 3 4 5 6
4 4 5 6 7
5 5 6 7 8
R> library(dplyr)
R> dplyr::select(df2, -c(x, y))  # remove columns x and y
  z u
1 3 4
2 4 5
3 5 6
4 6 7
5 7 8

Antwoord 5, autoriteit 4%

Hier is een snelle oplossing hiervoor. Stel, je hebt een dataframe X met drie kolommen A, B en C:

> X<-data.frame(A=c(1,2),B=c(3,4),C=c(5,6))
> X
  A B C
1 1 3 5
2 2 4 6

Als ik een kolom wil verwijderen, zeg B, gebruik dan grep op colnames om de kolomindex te krijgen, die u vervolgens kunt gebruiken om de kolom weg te laten.

> X<-X[,-grep("B",colnames(X))]

Uw nieuwe X-dataframe ziet er als volgt uit (dit keer zonder de B-kolom):

> X
  A C
1 1 5
2 2 6

Het mooie van grep is dat je meerdere kolommen kunt specificeren die overeenkomen met de reguliere expressie. Als ik X had met vijf kolommen (A,B,C,D,E):

> X<-data.frame(A=c(1,2),B=c(3,4),C=c(5,6),D=c(7,8),E=c(9,10))
> X
  A B C D  E
1 1 3 5 7  9
2 2 4 6 8 10

Kolom B en D eruit halen:

> X<-X[,-grep("B|D",colnames(X))]
> X
  A C  E
1 1 5  9
2 2 6 10

EDIT: Gezien de grepl-suggestie van Matthew Lundberg in de opmerkingen hieronder:

> X<-data.frame(A=c(1,2),B=c(3,4),C=c(5,6),D=c(7,8),E=c(9,10))
> X
  A B C D  E
1 1 3 5 7  9
2 2 4 6 8 10
> X<-X[,!grepl("B|D",colnames(X))]
> X
  A C  E
1 1 5  9
2 2 6 10

Als ik een kolom probeer te verwijderen die niet bestaat, zou er niets moeten gebeuren:

> X<-X[,!grepl("G",colnames(X))]
> X
  A C  E
1 1 5  9
2 2 6 10

Antwoord 6, autoriteit 2%

Ik heb geprobeerd een kolom te verwijderen terwijl ik het pakket data.tablegebruikte en kreeg een onverwacht resultaat. Ik denk dat het volgende misschien de moeite waard is om te posten. Gewoon een kleine waarschuwing.

[ Bewerkt door Matthew … ]

DF = read.table(text = "
     fruit state grade y1980 y1990 y2000
     apples Ohio   aa    500   100   55
     apples Ohio   bb      0     0   44
     apples Ohio   cc    700     0   33
     apples Ohio   dd    300    50   66
", sep = "", header = TRUE, stringsAsFactors = FALSE)
DF[ , !names(DF) %in% c("grade")]   # all columns other than 'grade'
   fruit state y1980 y1990 y2000
1 apples  Ohio   500   100    55
2 apples  Ohio     0     0    44
3 apples  Ohio   700     0    33
4 apples  Ohio   300    50    66
library('data.table')
DT = as.data.table(DF)
DT[ , !names(dat4) %in% c("grade")]    # not expected !! not the same as DF !!
[1]  TRUE  TRUE FALSE  TRUE  TRUE  TRUE
DT[ , !names(DT) %in% c("grade"), with=FALSE]    # that's better
    fruit state y1980 y1990 y2000
1: apples  Ohio   500   100    55
2: apples  Ohio     0     0    44
3: apples  Ohio   700     0    33
4: apples  Ohio   300    50    66

In principe is de syntaxis voor data.tableNIET exact hetzelfde als data.frame. Er zijn namelijk veel verschillen, zie FAQ 1.1 en FAQ 2.17. Je bent gewaarschuwd!


Antwoord 7

df2 <- df[!names(df) %in% c("c1", "c2")]

Antwoord 8

Ik heb de code gewijzigd in:

# read data
dat<-read.dta("file.dta")
# vars to delete
var.in<-c("iden", "name", "x_serv", "m_serv")
# what I'm keeping
var.out<-setdiff(names(dat),var.in)
# keep only the ones I want       
dat <- dat[var.out]

Hoe dan ook, het antwoord van juba is de beste oplossing voor mijn probleem!


Antwoord 9

Hier is nog een oplossing die voor anderen nuttig kan zijn. De onderstaande code selecteert een klein aantal rijen en kolommen uit een grote dataset. De kolommen zijn geselecteerd zoals in een van de antwoorden van juba, behalve dat ik een plakfunctie gebruik om een ​​reeks kolommen te selecteren met namen die opeenvolgend zijn genummerd:

df = read.table(text = "
state county city  region  mmatrix  X1 X2 X3    A1     A2     A3      B1     B2     B3      C1      C2      C3
  1      1     1      1     111010   1  0  0     2     20    200       4      8     12      NA      NA      NA
  1      2     1      1     111010   1  0  0     4     NA    400       5      9     NA      NA      NA      NA
  1      1     2      1     111010   1  0  0     6     60     NA      NA     10     14      NA      NA      NA
  1      2     2      1     111010   1  0  0    NA     80    800       7     11     15      NA      NA      NA
  1      1     3      2     111010   0  1  0     1      2      1       2      2      2      10      20      30
  1      2     3      2     111010   0  1  0     2     NA      1       2      2     NA      40      50      NA
  1      1     4      2     111010   0  1  0     1      1     NA      NA      2      2      70      80      90
  1      2     4      2     111010   0  1  0    NA      2      1       2      2     10     100     110     120
  1      1     1      3     010010   0  0  1    10     20     10     200    200    200       1       2       3
  1      2     1      3     001000   0  0  1    20     NA     10     200    200    200       4       5       9
  1      1     2      3     101000   0  0  1    10     10     NA     200    200    200       7       8      NA
  1      2     2      3     011010   0  0  1    NA     20     10     200    200    200      10      11      12
", sep = "", header = TRUE, stringsAsFactors = FALSE)
df
df2 <- df[df$region == 2, names(df) %in% c(paste("C", seq_along(1:3), sep=''))]
df2
#    C1  C2  C3
# 5  10  20  30
# 6  40  50  NA
# 7  70  80  90
# 8 100 110 120

Antwoord 10

Ik kan je vraag niet beantwoorden in de reacties vanwege de lage reputatiescore.

De volgende code geeft een foutmelding omdat de plakfunctie een tekenreeks retourneert

for(i in 1:length(var.out)) {
   paste("data$", var.out[i], sep="") <- NULL
}

Hier is een mogelijke oplossing:

for(i in 1:length(var.out)) {
  text_to_source <- paste0 ("data$", var.out[i], "<- NULL") # Write a line of your
                                                  # code like a character string
  eval (parse (text=text_to_source)) # Source a text that contains a code
}

of doe gewoon:

for(i in 1:length(var.out)) {
  data[var.out[i]] <- NULL
}

Antwoord 11

df = mtcars 

verwijder vs en ben omdat ze categorisch zijn. In de dataset
vs staat in kolom 8, am staat in kolom 9

dfnum = df[,-c(8,9)]

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Other episodes