डेटा फ़्रेम में नाम से कॉलम कैसे छोड़ें


304

मेरे पास एक बड़ा डेटा सेट है और मैं विशिष्ट कॉलम पढ़ना चाहूंगा या अन्य सभी को छोड़ दूंगा।

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

मैं उन कॉलमों का चयन करता हूं, जिनमें मेरी रुचि नहीं है:

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

और जैसे मैं कुछ करना चाहता हूं:

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

सभी अवांछित स्तंभों को छोड़ने के लिए। क्या यह इष्टतम समाधान है?


1
समस्या पर नींद, मैं सोच रहा था कि subset(data, select=c(...))var छोड़ने के लिए मेरे मामले में मदद करता है। सवाल हालांकि मुख्य रूप paste("data$",var.out[i],sep="")से लूप के अंदर ब्याज के कॉलम तक पहुंचने वाले हिस्से के बारे में था । मैं किसी कॉलम नाम को कैसे पेस्ट या किसी तरह से कर सकता हूं? आपके ध्यान और आपकी सहायता के लिए सभी का धन्यवाद
leroux

जवाबों:


380

आपको इंडेक्सिंग या subsetफ़ंक्शन का उपयोग करना चाहिए । उदाहरण के लिए :

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

तब आप whichफ़ंक्शन और -ऑपरेटर को स्तंभ अनुक्रमण में उपयोग कर सकते हैं :

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

या, बहुत सरल, फ़ंक्शन के selectतर्क का उपयोग करें subset: आप -ऑपरेटर को सीधे कॉलम नामों के वेक्टर पर उपयोग कर सकते हैं, और आप नामों के आसपास के उद्धरण भी छोड़ सकते हैं!

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

ध्यान दें कि आप उन कॉलमों का भी चयन कर सकते हैं जिन्हें आप दूसरों को छोड़ने के बजाय चाहते हैं:

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

2
फ़ंक्शन के selectतर्क subsetने पूरी तरह से काम किया! शुक्रिया जुबा!
leroux

2
whichनिस्सार नहीं है, इस्सा का जवाब देखें। लेकिन के साथ सबसेट -अच्छा है! नहीं पता था कि!
टीएमएस

5
subsetअच्छा लग रहा है, लेकिन जिस तरह से यह चुपचाप गायब मूल्यों को छोड़ देता है वह मुझे बहुत खतरनाक लगता है।
स्थिर_परिवर्तन

2
subsetवास्तव में बहुत सुविधाजनक है, लेकिन याद रखें कि जब तक आप आर का उपयोग नहीं कर रहे हैं, तब तक इसका उपयोग करने से बचें। देखें समारोह के दस्तावेज में चेतावनी और इस तो सवाल यह अधिक के लिए।
वाल्डिर लियोनिको

4
"आप नामों के आस-पास के उद्धरणों को भी छोड़ सकते हैं!", आपको वास्तव में उद्धरणों को छोड़ना होगा, अन्यथा आपको अपर संचालक से अमान्य तर्क मिल जाएगा। यदि आपके नाम में कुछ अक्षर हैं (उदाहरण के लिए "-") तो आप इस पद्धति का उपयोग नहीं कर सकते क्योंकि उद्धरण छोड़ने के बाद आर आपके कोड को ठीक से पार्स करने में असमर्थ होने का कारण बन जाएगा।
ओम ५५

122

इसके -which()लिए उपयोग न करें , यह बेहद खतरनाक है। विचार करें:

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...

इसके बजाय सबसेट या !फ़ंक्शन का उपयोग करें :

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

मैंने इसे दर्दनाक अनुभव से सीखा है। अति प्रयोग न करें which()!


31
setdiffयह भी उपयोगी है:setdiff(names(dat), c("foo", "bar"))
हैडली

setdiff@Hadley द्वारा प्रस्ताव नामों की लंबी सूची के लिए बहुत अच्छा है।
JASC

48

सबसे पहले , आप के बजाय (बूलियन्स वैक्टर के साथ) प्रत्यक्ष अनुक्रमण का उपयोग कर सकते फिर से पहुँचने के स्तंभ नाम यदि आप एक ही डेटा फ्रेम के साथ काम कर रहे हैं; यह इस्टा द्वारा इंगित के रूप में सुरक्षित होगा, और लिखने और निष्पादित करने के लिए तेज होगा। तो क्या आप केवल आवश्यकता होगी:

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

और फिर, बस डेटा पुन: असाइन करें:

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

दूसरा , लिखने के लिए तेज, आप सीधे उन कॉलमों को NULL असाइन कर सकते हैं जिन्हें आप हटाना चाहते हैं:

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

अंत में , आप सबसेट () का उपयोग कर सकते हैं, लेकिन यह वास्तव में कोड में उपयोग नहीं किया जा सकता है (यहां तक ​​कि सहायता फ़ाइल इसके बारे में चेतावनी देती है)। विशेष रूप से, मेरे लिए एक समस्या यह है कि यदि आप सीधे susbset () की ड्रॉप सुविधा का उपयोग करना चाहते हैं, तो आपको कॉलम नामों के अनुरूप अभिव्यक्ति के बिना उद्धरण लिखने की आवश्यकता है:

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

एक बोनस के रूप में , यहाँ विभिन्न विकल्पों में से एक छोटा बेंचमार्क है, जो स्पष्ट रूप से दर्शाता है कि सबसेट सबसे धीमा है, और यह कि पहला, पुन: असाइन करने का तरीका सबसे तेज़ है:

                                        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

माइक्रोबेंक ग्राफ

कोड नीचे है:

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)

2
मुझे आपके दूसरे विकल्प का उपयोग करना पसंद है NULL, लेकिन जब आप दो से अधिक नाम रखते हैं, तो इसे list(NULL)कैसे असाइन करना आवश्यक है ? मैं केवल यह जानने के लिए उत्सुक हूं कि यह कैसे काम करता है, क्योंकि मैंने केवल एक नाम के साथ प्रयास किया और मुझे इसकी आवश्यकता नहीं हैlist()
डार्विन पीसी

3
@ डार्विनपीसी हाँ। यदि आप सीधे एक वेक्टर तत्व ( $या के साथ [[) का उपयोग करते हैं, <- list(NULL)तो वास्तव में गलत परिणामों का कारण होगा। यदि आप एक या एक से अधिक स्तंभों के साथ डेटाफ़्रेम के सबसेट तक पहुँचते <- list(NULL)हैं, तो जाने का रास्ता है, भले ही इसके लिए एक कॉलम डेटाफ़्रेम की आवश्यकता न हो (क्योंकि df['myColumns']आवश्यकता पड़ने पर वेक्टर को कास्ट किया जाएगा)।
एंटोनी लिजी

27

आप dplyrपैकेज भी आज़मा सकते हैं :

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

4
का उपयोग dplyr::select(df2, -one_of(c('x','y')))करना अभी भी काम करेगा (एक चेतावनी के साथ) भले ही कुछ नामित कॉलम मौजूद न हों
divibisan

13

यहाँ इसके लिए एक त्वरित समाधान है। कहें, आपके पास एक डेटा फ़्रेम X है जिसमें तीन कॉलम A, B और 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

यदि मैं एक कॉलम को हटाना चाहता हूं, तो B का कहना है, कॉलम इंडेक्स प्राप्त करने के लिए बस कॉल्रेम्स पर grep का उपयोग करें, जिसे आप कॉलम को छोड़ने के लिए उपयोग कर सकते हैं।

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

आपका नया X डेटा फ़्रेम निम्न की तरह दिखेगा (इस बार B कॉलम के बिना):

> X
  A C
1 1 5
2 2 6

ग्रीप की सुंदरता यह है कि आप कई कॉलम निर्दिष्ट कर सकते हैं जो नियमित अभिव्यक्ति से मेल खाते हैं। अगर मेरे पास पाँच कॉलम (A, B, C, D, E) के साथ X है:

> 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

कॉलम B और D को बाहर निकालें:

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

EDIT: नीचे टिप्पणी में मैथ्यू लुंडबर्ग के संक्षिप्त सुझाव पर विचार:

> 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

अगर मैं किसी ऐसे स्तंभ को छोड़ने की कोशिश करता हूं जो गैर-मौजूद है, तो कुछ भी नहीं होना चाहिए:

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

3
X[,-grep("B",colnames(X))]उस मामले में कोई कॉलम नहीं लौटाएगा, जिसमें कोई कॉलम नाम नहीं है B, बल्कि सभी कॉलमों को वापस करना होगा। X <- irisएक उदाहरण के साथ विचार करें । यह गणना के मूल्यों के साथ नकारात्मक सूचकांकों का उपयोग करने में समस्या है। greplइसके बजाय विचार करें ।
मैथ्यू लुंडबर्ग

6

मैंने पैकेज का उपयोग करते समय एक कॉलम को हटाने की कोशिश की data.tableऔर अप्रत्याशित परिणाम मिला। मुझे लगता है कि निम्नलिखित पोस्ट करने के लायक हो सकता है। बस थोड़ी सी सावधानी बरतें।

[मैथ्यू द्वारा संपादित ...]

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

असल में, के लिए वाक्यविन्यास data.tableबिल्कुल वैसा ही नहीं है data.frame। वास्तव में बहुत सारे अंतर हैं, FAQ 1.1 और FAQ 2.17 देखें। आपको चेतावनी दी गई है!


1
या आप DT[,var.out := NULL]उन स्तंभों को हटाने के लिए उपयोग कर सकते हैं जो आप ऐसा करना चाहते हैं।
मेल

सबसेट (x, select = ...) विधि दोनों data.frameऔर data.tableवर्गों के लिए काम करती है
Momeara

3

मैंने कोड बदल दिया है:

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

वैसे भी, जुबा का जवाब मेरी समस्या का सबसे अच्छा समाधान है!


आप इसे लूप में क्यों करना चाहते हैं? जुबा का जवाब आपको दिखाता है कि इसे एक चरण में कैसे किया जाए। इसे और अधिक जटिल क्यों बनाते हैं?
इस्सा

बेशक मैं अपने कोड में फ़ंक्शन के selectतर्क का उपयोग करता subsetहूं। मैं सिर्फ यह देखना चाहता था कि कैसे मैं एक लूप में मनमाने ढंग से कॉलम एक्सेस कर सकता हूं अगर मैं कॉलम को छोड़ने के अलावा कुछ और करना चाहता था। मूल डेटा सेट में लगभग 1200 vars हैं और मैं केवल उन 4 का उपयोग करने में दिलचस्पी रखता हूं, जो बिना यह जाने कि वे वास्तव में कहां हैं।
leroux

2

यहां एक और उपाय है जो दूसरों के लिए मददगार हो सकता है। नीचे दिया गया कोड एक बड़े डेटा सेट से छोटी संख्या में पंक्तियों और स्तंभों का चयन करता है। कॉलम को जुबा के उत्तरों में से एक के रूप में चुना गया है, सिवाय इसके कि मैं एक पेस्ट फ़ंक्शन का उपयोग करता हूं, क्रमिक रूप से गिने जाने वाले नामों के साथ कॉलम का एक सेट का चयन करने के लिए:

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


-1

मैं कम प्रतिष्ठा स्कोर के कारण टिप्पणियों में आपके सवाल का जवाब नहीं दे सकता।

अगला कोड आपको एक त्रुटि देगा क्योंकि पेस्ट फ़ंक्शन एक वर्ण स्ट्रिंग लौटाता है

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

यहाँ एक संभावित समाधान है:

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
}

या बस करो:

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

-1
df = mtcars 
vs vs am क्योंकि वे श्रेणीबद्ध हैं। डेटासेट बनाम कॉलम नंबर 8 में है, कॉलम नंबर 9 में है

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.