ডেটা ফ্রেমে নাম দিয়ে কলাম কীভাবে ড্রপ করবেন


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(...))আমার মামলাগুলি বাদ দেওয়ার ক্ষেত্রে সহায়তা করে। paste("data$",var.out[i],sep="")লুপের অভ্যন্তরে আগ্রহের কলামগুলি অ্যাক্সেস করার অংশটি ছিল মূলত । আমি কীভাবে কোনও কলামের নামটি আটকানো বা রচনা করতে পারি? আপনার মনোযোগ এবং আপনার সহায়তার জন্য প্রত্যেককে ধন্যবাদ
লেওরক্স

উত্তর:


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ফাংশন পুরোপুরি কাজ করেছেন! ধন্যবাদ যুবা!
লেওরেক্স

2
whichপ্রয়োজনীয় নয়, ইস্তার উত্তর দেখুন। তবে সাবসেটটি দুর্দান্ত -! জানতাম না!
টিএমএস

5
subsetদেখতে দেখতে দুর্দান্ত লাগছে, কিন্তু নিভৃতে হারিয়ে যাওয়া মানগুলি যেভাবে ফেলেছে তা আমার পক্ষে বেশ বিপজ্জনক বলে মনে হচ্ছে।
স্থির_আরত্তি

2
subsetপ্রকৃতপক্ষে খুব সুবিধাজনক, তবে আপনি যদি ইন্টারঅ্যাক্টিভভাবে আর ব্যবহার না করেন তবে এটিকে ব্যবহার করা এড়াতে ভুলবেন না। দেখুন ফাংশনের ডকুমেন্টেশনে সতর্কতা এবং এই তাই প্রশ্ন আরো অনেক কিছুর জন্য।
ওয়াল্ডির লিওনসিও

4
"আপনি নামগুলির চারপাশে উদ্ধৃতিগুলিও বাদ দিতে পারেন!", আপনাকে আসলে উদ্ধৃতিগুলি বাদ দিতে হবে, অন্যথায় আপনি অ্যানারি অপারেটরের কাছে অবৈধ যুক্তি পাবেন। আপনার নামগুলিতে যদি নির্দিষ্ট অক্ষর (উদাহরণস্বরূপ "-") থাকে তবে আপনি এই পদ্ধতিটি মোটেই ব্যবহার করতে পারবেন না যেহেতু উদ্ধৃতি বাদ দেওয়ার ফলে আর আপনার কোডটি সঠিকভাবে পার্স করতে অক্ষম হবে।
oh54

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@ হডলির দ্বারা প্রস্তাবিত নাম দীর্ঘ তালিকা জন্য খুব ভাল।
জেএসসি

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.

শেষ অবধি, আপনি সাবসেট () ব্যবহার করতে পারেন, তবে এটি কোডে সত্যই ব্যবহার করা যাবে না (এমনকি সহায়তা ফাইল এটি সম্পর্কে সতর্ক করে দেয়)। বিশেষত, আমার কাছে একটি সমস্যা হ'ল আপনি যদি সাসবসেটের ড্রপ বৈশিষ্ট্যটি সরাসরি ব্যবহার করতে চান () আপনার কলামের নামগুলির সাথে মিল রেখে প্রকাশের উদ্ধৃতি ছাড়াই লিখতে হবে:

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')))নামকরণকৃত কিছু কলামের অস্তিত্ব না থাকলেও ব্যবহার এখনও (একটি সতর্কতার সাথে) কাজ করবে
বিভাজন

13

এই জন্য একটি দ্রুত সমাধান এখানে। বলুন, আপনার কাছে তিনটি কলাম এ, বি এবং সি সহ একটি ডেটা ফ্রেম এক্স রয়েছে:

> 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

আমি যদি একটি কলামটি মুছে ফেলতে চাই, বি বলুন, কলাম সূচী পেতে কলনেমে গ্রেপ ব্যবহার করুন, যা আপনি কলামটি বাদ দিতে ব্যবহার করতে পারেন।

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

আপনার নতুন এক্স ডেটা ফ্রেমটি নীচের মতো দেখাবে (এবার বি কলাম ছাড়াই):

> X
  A C
1 1 5
2 2 6

গ্রেপের সৌন্দর্য হ'ল আপনি নিয়মিত অভিব্যক্তির সাথে মেলে এমন একাধিক কলাম নির্দিষ্ট করতে পারেন। যদি আমার পাঁচটি কলাম (এ, বি, সি, ডি, ই) সহ এক্স থাকে:

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

সম্পাদনা: নীচের মন্তব্যে ম্যাথু লন্ডবার্গের গ্রেপল পরামর্শ বিবেচনা:

> 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একটি উদাহরণ সঙ্গে বিবেচনা করুন । গণিত মান সহ negativeণাত্মক সূচকগুলি ব্যবহার করার ক্ষেত্রে এটি সমস্যা। 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 দেখুন Q তোমাকে সতর্ক করা হল!


1
অথবা আপনি DT[,var.out := NULL]যে কলামগুলি এটি করতে চান তা মুছতে ব্যবহার করতে পারেন।
মণেল

উপসেট (x, নির্বাচন করুন = ...) পদ্ধতি উভয় data.frameএবং data.tableশ্রেণীর জন্য কাজ করে
মোমারা

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 টি ভার্স রয়েছে এবং আমি ঠিক সেগুলি কোথায় তা না জেনে কেবলমাত্র 4 টি ব্যবহার করতে আগ্রহী।
লেওরেক্স

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

কম খ্যাতিমান স্কোরের কারণে আমি মন্তব্যে আপনার প্রশ্নের উত্তর দিতে পারি না।

পরবর্তী কোড আপনাকে একটি ত্রুটি দেবে কারণ পেস্ট ফাংশনটি একটি অক্ষরের স্ট্রিং দেয় return

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 
বনাম এবং am সরান কারণ তারা শ্রেণিবদ্ধ। ডেটাসেট বনাম 8 কলামে, সকাল 9 নং কলামে

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

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.