คุณจะลบคอลัมน์ตามชื่อใน data.table ได้อย่างไร?


196

หากต้องการกำจัดคอลัมน์ชื่อ "foo" ใน a data.frameฉันสามารถทำได้:

df <- df[-grep('foo', colnames(df))]

อย่างไรก็ตามเมื่อdfถูกแปลงเป็นdata.tableวัตถุจะไม่มีวิธีเพียงแค่ลบคอลัมน์

ตัวอย่าง:

df <- data.frame(id = 1:100, foo = rnorm(100))
df2 <- df[-grep('foo', colnames(df))] # works
df3 <- data.table(df)
df3[-grep('foo', colnames(df3))] 

แต่เมื่อมันถูกแปลงเป็นdata.tableวัตถุสิ่งนี้จะไม่ทำงานอีกต่อไป


2
มันจะได้รับการตั้งชื่อที่ชัดเจน data.table dtแทนdf3...
PatrickT

คำตอบ:


284

ข้อใดข้อหนึ่งต่อไปนี้จะลบคอลัมน์ออกfooจาก data.table df3:

# Method 1 (and preferred as it takes 0.00s even on a 20GB data.table)
df3[,foo:=NULL]

df3[, c("foo","bar"):=NULL]  # remove two columns

myVar = "foo"
df3[, (myVar):=NULL]   # lookup myVar contents

# Method 2a -- A safe idiom for excluding (possibly multiple)
# columns matching a regex
df3[, grep("^foo$", colnames(df3)):=NULL]

# Method 2b -- An alternative to 2a, also "safe" in the sense described below
df3[, which(grepl("^foo$", colnames(df3))):=NULL]

data.tableยังสนับสนุนไวยากรณ์ต่อไปนี้:

## Method 3 (could then assign to df3, 
df3[, !"foo"]  

แม้ว่าถ้าคุณต้องการลบคอลัมน์"foo"จากdf3(แทนที่จะเป็นเพียงการพิมพ์มุมมองของdf3คอลัมน์ลบ"foo") คุณต้องการใช้วิธีที่ 1 แทน

(โปรดทราบว่าหากคุณใช้วิธีการที่ขึ้นอยู่กับgrep()หรือgrepl()คุณจำเป็นต้องตั้งค่าpattern="^foo$"มากกว่า"foo"หากคุณไม่ต้องการให้คอลัมน์ที่มีชื่อเช่น"fool"และ"buffoon"(เช่นที่มีfooชื่อเป็นสตริงย่อย) จะถูกจับคู่และลบออกด้วย)

ตัวเลือกที่ปลอดภัยน้อยลงปรับได้สำหรับการใช้งานแบบโต้ตอบ:

สำนวนที่สองถัดไปจะใช้งานได้ - หากdf3มีการจับคู่คอลัมน์"foo" - แต่จะล้มเหลวในลักษณะที่ไม่คาดคิดหากไม่มี ตัวอย่างเช่นหากคุณใช้คอลัมน์ใดคอลัมน์หนึ่งในการค้นหาคอลัมน์ที่ไม่มีอยู่"bar"คุณจะพบกับ data. แถวศูนย์

เป็นผลให้พวกเขาเป็นจริงเหมาะที่สุดสำหรับการใช้งานแบบโต้ตอบที่หนึ่งอาจเช่นต้องการแสดง data.table ลบคอลัมน์ใด ๆ "foo"ที่มีชื่อที่มีอักขระย่อย สำหรับจุดประสงค์ในการเขียนโปรแกรม (หรือถ้าคุณต้องการลบคอลัมน์ออกจากตัวจริงdf3มากกว่าเดิม) วิธีที่ 1, 2a และ 2b เป็นตัวเลือกที่ดีที่สุด

# Method 4:
df3[, .SD, .SDcols = !patterns("^foo$")]

ในที่สุดก็มีวิธีการใช้with=FALSEงานแม้ว่าdata.tableจะค่อยๆเคลื่อนออกห่างจากการใช้อาร์กิวเมนต์นี้ดังนั้นจึงเป็นเรื่องท้อใจที่คุณสามารถหลีกเลี่ยงได้ แสดงที่นี่เพื่อให้คุณรู้ว่ามีตัวเลือกอยู่ในกรณีที่คุณต้องการ:

# Method 5a (like Method 3)
df3[, !"foo", with=FALSE] 
# Method 5b (like Method 4)
df3[, !grep("^foo$", names(df3)), with=FALSE]
# Method 5b (another like Method 4)
df3[, !grepl("^foo$", names(df3)), with=FALSE]

2
ดูความคิดเห็นของฉันที่จะ OP เกี่ยวกับ-grep !grepl
Joshua Ulrich

1
@JoshuaUlrich - จุดดี ฉันพยายามเริ่มต้นgrepl()แต่ก็ไม่ทำงานเนื่องจากคอลัมน์ data.table ไม่สามารถจัดทำดัชนีโดยเวกเตอร์เชิงตรรกะได้ แต่ตอนนี้ฉันรู้แล้วว่าgrepl()สามารถทำงานได้โดยการหุ้มด้วยมันwhich()เพื่อให้มันคืนค่าเวคเตอร์จำนวนเต็ม
Josh O'Brien

1
ฉันไม่รู้ว่าเกี่ยวกับการจัดทำดัชนีด้วยdata.tableแต่การตัดในwhichนั้นเป็นเรื่องที่ฉลาด!
Joshua Ulrich

6
ฉันก็ไม่รู้data.tableเหมือนกัน เพิ่มFR # 1797 แต่วิธีที่ 1 คือ (เกือบ) เร็วกว่าอนันต์อื่น ๆ วิธีที่ 1 เอาคอลัมน์ออกโดยอ้างอิงโดยไม่มีการคัดลอกเลย ฉันสงสัยว่าคุณได้รับมันมากกว่า 0.005 วินาทีสำหรับ data.table ใด ๆ ขนาด ในทางตรงกันข้ามคนอื่นอาจไม่ทำงานเลยถ้าตารางอยู่ใกล้ RAM 50% เพราะคัดลอกทั้งหมดยกเว้นตารางที่จะลบ
Matt Dowle

1
@ user3969377 หากคุณต้องการลบคอลัมน์ตามเนื้อหาของตัวแปรตัวละครที่คุณจะใส่ไว้ในวงเล็บ กล่าวคือ df [, (afoo): = NULL]
Dean MacGregor

31

นอกจากนี้คุณยังสามารถใช้setสำหรับสิ่งนี้ซึ่งหลีกเลี่ยงค่าใช้จ่าย[.data.tableในลูป:

dt <- data.table( a=letters, b=LETTERS, c=seq(26), d=letters, e=letters )
set( dt, j=c(1L,3L,5L), value=NULL )
> dt[1:5]
   b d
1: A a
2: B b
3: C c
4: D d
5: E e

หากคุณต้องการที่จะทำโดยใช้ชื่อคอลัมน์ควรจะทำงานให้which(colnames(dt) %in% c("a","c","e"))j


2
ในdata.table1.11.8 ถ้าคุณต้องการทำโดยใช้ชื่อคอลัมน์คุณสามารถทำได้โดยตรงrm.col = c("a","b")และdt[, (rm.col):=NULL]
Duccio A

20

ฉันทำได้ในกรอบข้อมูลชนิด:

DT$col = NULL

ทำงานได้เร็วและเท่าที่ฉันเห็นจะไม่ทำให้เกิดปัญหาใด ๆ

UPDATE: ไม่ใช่วิธีที่ดีที่สุดถ้า DT ของคุณมีขนาดใหญ่มากเนื่องจากการใช้$<-โอเปอเรเตอร์จะนำไปสู่การคัดลอกวัตถุ ใช้ดีกว่า:

DT[, col:=NULL]

8

ตัวเลือกที่ง่ายมากในกรณีที่คุณมีหลายคอลัมน์ที่จะลบในตารางข้อมูลและคุณต้องการหลีกเลี่ยงการพิมพ์ชื่อคอลัมน์ทั้งหมด #careadviced

dt <- dt[, -c(1,4,6,17,83,104)]

สิ่งนี้จะลบคอลัมน์ตามหมายเลขคอลัมน์แทน

เห็นได้ชัดว่ามันไม่ได้มีประสิทธิภาพเพราะมันเลี่ยง data.table ข้อดี แต่ถ้าคุณทำงานกับน้อยกว่า 500,000 แถวมันทำงานได้ดี


4

สมมติว่าคุณมี dt คอลัมน์col1, col2, col3, col4, ,col5coln

หากต้องการลบชุดย่อยของพวกเขา:

vx <- as.character(bquote(c(col1, col2, col3, coln)))[-1]
DT[, paste0(vx):=NULL]

นี่ควรเป็นความคิดเห็น
Sachila Ranawaka

-2

นี่คือวิธีเมื่อคุณต้องการตั้งค่าจำนวนคอลัมน์เป็น NULL เนื่องจากชื่อคอลัมน์มีฟังก์ชันสำหรับการใช้งานของคุณ :)

deleteColsFromDataTable <- function (train, toDeleteColNames) {

       for (myNm in toDeleteColNames)

       train <- train [,(myNm):=NULL]

       return (train)
}


-7

สำหรับ data.table การกำหนดคอลัมน์ให้กับ NULL จะเป็นการลบคอลัมน์

DT[,c("col1", "col1", "col2", "col2")] <- NULL
^
|---- Notice the extra comma if DT is a data.table

... ซึ่งเทียบเท่ากับ:

DT$col1 <- NULL
DT$col2 <- NULL
DT$col3 <- NULL
DT$col4 <- NULL

ค่าที่เทียบเท่าสำหรับ data.frame คือ:

DF[c("col1", "col1", "col2", "col2")] <- NULL
      ^
      |---- Notice the missing comma if DF is a data.frame

ถาม: ทำไมจึงมีเครื่องหมายจุลภาคในรุ่น data.table และไม่มีเครื่องหมายจุลภาคในรุ่น data.frame?

A. เนื่องจาก data.frames ถูกจัดเก็บเป็นรายการของคอลัมน์คุณสามารถข้ามเครื่องหมายจุลภาค นอกจากนี้คุณยังสามารถเพิ่มใน แต่แล้วคุณจะต้องกำหนดไว้ในรายการของs,NULLDF[, c("col1", "col2", "col3")] <- list(NULL)


@ รันฉันไม่สามารถนึกถึงสถานการณ์ใด ๆdata.framesที่จะเปลี่ยนแถวและคอลัมน์ นั่นจะไร้เหตุผล
duHaas

@ Run ฉันติดแท็กคุณเนื่องจากความคิดเห็นแรกของคุณทำให้ดูเหมือนว่ามีบางครั้งที่คุณอาจโทรหาDF[column,row]ดังนั้นฉันแค่อยากจะดูว่ามีกรณีใดบ้างที่เกิดขึ้นจริง
duHaas

อัปเดตคำตอบเพื่อลบการพิมพ์ผิด
Contango
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.