我有一个很大的数据集,我想阅读特定的列或放弃所有其他列。

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
}

删除所有不需要的列。这是最优解吗?


当前回答

df = mtcars 
remove vs and am because they are categorical. In the dataset vs is in column number 8, am is in column number 9

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

其他回答

如果你确切地知道原始数据框架df中的列的名称:

cols_to_drop <- c("A", "B", "C")
df_clean = df[,!(names(df) %in% cols_to_drop)]

Src: https://www.listendata.com/2015/06/r-keep-drop-columns-from-data-frame.html

您应该使用索引或子集函数。例如:

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参数:然后可以直接对列名向量使用-运算符,甚至可以省略列名周围的引号!

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

不要使用-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()!

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

首先,如果您使用相同的数据帧,您可以使用直接索引(使用布尔向量)而不是重新访问列名;正如Ista所指出的那样,它会更安全,而且编写和执行速度更快。所以你只需要:

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()的drop特性,你需要写不带引号的表达式对应的列名:

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)