如何从data.frame中删除列?

时间:2011-08-16 00:00:04

标签: r dataframe

不是那么'你怎么......?'但更多'你怎么......?'

如果您有一个文件,有人会为您提供200列,并且您希望将其减少到您需要进行分析的少数几个,那么您如何去做呢?一种解决方案是否比其他解决方案更具优势?

假设我们有一个包含col1,col2到col200列的数据框。如果您只想要1-100,然后是125-135和150-200,您可以:

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

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

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

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

我还缺少什么?我知道这是主观的,但这是你可能会潜入并开始以一种方式进行的那些细节之一,并且当有更有效的方法时会陷入习惯。很像关于which的这个问题。

修改

或者,是否有一种简单的方法来创建可行的列名矢量? name(dat)不打印它们之间的逗号,你需要在上面的代码示例中,所以如果以这种方式打印出名称,你到处都有空格,必须手动输入逗号...是否有命令会给你“col1”,“col2”,“col3”,......作为你的输出,这样你就可以轻松抓住你想要的东西了吗?

12 个答案:

答案 0 :(得分:54)

我使用data.table:=运算符立即删除列,无论表的大小如何。

DT[, coltodelete := NULL]

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

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

DT[, (variableHoldingNamesOrNumbers) := NULL]

使用<-subset的任何解决方案都会复制整个表。 data.table:=运算符只是修改了指向列的指针的内部向量。因此,该操作(几乎)是即时的。

答案 1 :(得分:31)

要删除单个列,我只使用dat$x <- NULL

要删除多列,但少于3-4,我会使用dat$x <- dat$y <- dat$z <- NULL

除此之外,我将使用subset,使用否定名称(!):

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

答案 2 :(得分:9)

为清楚起见,我经常使用subset中的select参数。对于更新的人,我已经了解到保持他们需要的命令数量至少可以帮助采用。随着技能的提高,他们的编码能力也会提高。而子集是我在需要在给定标准内选择数据时向人们展示的第一个命令之一。

类似的东西:

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

我确信这会比大多数其他解决方案测试得慢,但我很少会在微秒发挥作用的时候出现。

答案 3 :(得分:7)

将read.table与colClasses实例“NULL”一起使用,以避免在第一时间创建它们:

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

x a
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)

答案 4 :(得分:5)

对于我倾向于获得的大型文件类型,我通常甚至不会在R中执行此操作。我会在Linux中使用cut命令在数据到达R之前处理数据。这不是对R的批评,只是偏爱使用一些非常基本的Linux工具,如grep,tr,cut,sort,uniq,偶尔sed&amp; awk(或Perl),当有关于正则表达式的事情要做时。

使用标准GNU命令的另一个原因是我可以将它们传递回数据源并要求它们预先过滤数据,这样我就不会得到无关的数据。我的大多数同事都熟悉Linux,很少有人知道R.

(更新)我不久就想要使用的方法是将mmap与文本文件配对并检查数据 in situ ,而不是将其全部读入RAM 。我用C做了这个,它可以非常快。

答案 5 :(得分:3)

有时候我喜欢使用列ID来做这件​​事。

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(名(DF))

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

删除列“c”和“g”

df[,-c(3,7)]

如果您有大型的data.frames或者您不想键入的长列名,这将非常有用。或者跟随模式的列名,因为那样你可以使用seq()来删除。

RE:您的编辑

您不一定要在字符串周围放置“”,也不必“,”来创建字符向量。我发现这个小技巧很方便:

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

答案 6 :(得分:2)

来自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

认为这是一个非常聪明的列表&#34;不包括&#34;

答案 7 :(得分:1)

只是解决编辑问题。

@nzcoops,你不需要需要逗号分隔的字符向量中的列名。你正在以错误的方式思考这个问题。当你这样做

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

您正在创建字符向量。 ,只是在定义该向量时分隔c()函数所采用的参数。 names()和类似函数返回名称的字符向量。

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

names(dat)的元素中选择比将其输出处理为可以剪切和粘贴的逗号分隔字符串要容易得多且不容易出错。

假设我们想要列col1col2,子集names(dat),只保留我们想要的列:

> 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

你可以做你想做的事,但R总会在引号"中打印出屏幕的矢量:

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

所以后者可能更有用。但是,现在你必须从那个字符串中剪切和过去。更好地处理返回所需内容的对象,并使用标准子集例程来保留您所需的内容。

答案 8 :(得分:1)

可以使用setdiff功能:

如果要保留的列数多于要删除的列数: 假设您要删除 2列,例如来自data.frame DT的col1,col2;你可以做到以下几点:

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

如果要删除的列多于要保留的列: 假设你想保持只有col1和col2:

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

答案 9 :(得分:1)

如果您已经有了一些名称向量,有多种创建方法,您可以轻松使用子集函数来保留或删除对象。

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

在这种情况下,KEEP是预先创建的列名称的向量。例如:

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

结果是:

> head(df)
            a          b           c          d
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
            e           f           g
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)
        a          b           c           e
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

答案 10 :(得分:1)

来自dplyr的select()函数对于子列化列表非常有用。有关方法列表,请参阅?select_helpers

在这种情况下,如果您有列名的公共前缀和序号,则可以使用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

更一般地说,您可以使用select()中的减号来删除列,例如:

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

最后,对于您的问题“是否有一种简单的方法来创建可行的列名称向量?” - 是的,如果您需要手动编辑名称列表,请使用dput获取逗号分隔的引用列表,您可以轻松操作:

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

答案 11 :(得分:0)

rm中的

within可能非常有用。

within(mtcars, rm(mpg, cyl, disp, hp))
#                     drat    wt  qsec vs am gear carb
# Mazda RX4           3.90 2.620 16.46  0  1    4    4
# Mazda RX4 Wag       3.90 2.875 17.02  0  1    4    4
# Datsun 710          3.85 2.320 18.61  1  1    4    1
# Hornet 4 Drive      3.08 3.215 19.44  1  0    3    1
# Hornet Sportabout   3.15 3.440 17.02  0  0    3    2
# Valiant             2.76 3.460 20.22  1  0    3    1
# ...

可以与其他操作组合。

within(mtcars, {
  mpg2=mpg^2
  cyl2=cyl^2
  rm(mpg, cyl, disp, hp)
  })
#                     drat    wt  qsec vs am gear carb cyl2    mpg2
# Mazda RX4           3.90 2.620 16.46  0  1    4    4   36  441.00
# Mazda RX4 Wag       3.90 2.875 17.02  0  1    4    4   36  441.00
# Datsun 710          3.85 2.320 18.61  1  1    4    1   16  519.84
# Hornet 4 Drive      3.08 3.215 19.44  1  0    3    1   36  457.96
# Hornet Sportabout   3.15 3.440 17.02  0  0    3    2   64  349.69
# Valiant             2.76 3.460 20.22  1  0    3    1   36  327.61
# ...