删除 R 中多个文件中的列

Removing columns in multiple files in R

我有多个包含 18 或 20 列的文本文件。我想将所有文件绑定在一起,但为了这样做,我必须删除由 20 列组成的文件中的前两列(这两列是日期和时间)。

我找不到解决问题的方法(我只是 R 的新手)"numbers of columns of arguments do not match"。因此,我想确定文件的前两行是否称为日期和时间,然后删除这些列。这是我正在处理的代码:

file_list <- list.files()

for (file in file_list){
    if (!exists("dataset")){
        dataset <- read.table(file, header=TRUE, sep="\t", stringsAsFactors=FALSE)
    if (colnames(dataset)[1] == "date" & colnames(dataset)[2] == "time"){
        dataset$date <- NULL
        dataset$time <- NULL
    }
}

if (exists("dataset")){
    temp_dataset <-read.table(file, header=TRUE, sep="\t", stringsAsFactors=FALSE)
    dataset<-rbind(dataset, temp_dataset)
    rm(temp_dataset)
    }

}

谢谢!

正如@user5249203 评论的那样,如果您在加载 之前根据文件名(或其他名称)知道文件有太多列,那么您可以通过编程跳过列。如果没有,继续。

我假设您正在使用类似这样的方式读取文件:

fnames <- list.files(pattern = "*.csv", path = "some/dir")
# replace `read.csv` with whichever function you're using to read in the data
alldata <- sapply(fnames, read.csv, stringsAsFactors = FALSE, simplify = FALSE)

没有任何文件可以这样读取,我将生成一个伪造的 alldata 列表:

set.seed(42)
fnames <- paste0("mtcars", 1:5)
alldata <- sapply(fnames, function(fn) {
  if (runif(1) < 0.7) mtcars[,-1] else mtcars
})
# should have 3 with 11 columns, 2 with 10 columns
sapply(alldata, ncol)
# mtcars1 mtcars2 mtcars3 mtcars4 mtcars5 
#      11      11      10      11      10 

毫不奇怪,我们不能使用 base R:

rbind 它们
do.call("rbind", alldata)
# Error in rbind(deparse.level, ...) : 
#   numbers of columns of arguments do not match

dplyr

但是我们可以使用 dplyr::bind_rows,尽管它会 保留 不需要的列,导致该列在较窄的表格中的值为 NA :

library(dplyr)
str( bind_rows(alldata) )
# 'data.frame': 160 obs. of  11 variables:
#  $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
#  $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
#  $ disp: num  160 160 108 258 360 ...
#  $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
#  $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
#  $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
#  $ qsec: num  16.5 17 18.6 19.4 17 ...
#  $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...
#  $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
#  $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
#  $ carb: num  4 4 1 1 2 1 4 2 2 4 ...

您在此 str 摘要中看不到的是,某些 mpg 变量是 NA:

table(is.na(bind_rows(alldata)$mpg))
# FALSE  TRUE 
#    96    64 

(如果需要,请将其删除。)

基础 R

(假设您选择不使用 dplyr)。从这里开始你的 alldata:

的实际列表
numColumnsWanted <- 10    # you want this to be 18, I think
alldata2 <- lapply(alldata, function(dat) {
  # this grabs the *last* 'numColumnsWanted' columns
  if (ncol(dat) > numColumnsWanted) dat[, 1 + ncol(dat) - numColumnsWanted:1] else dat
})

验证 data.frames 的大小是否相同。 (您可能还应该验证列名:

sapply(alldata2, ncol)
# mtcars1 mtcars2 mtcars3 mtcars4 mtcars5 
#      10      10      10      10      10 

现在您应该可以安全地绑定它们了:

str( do.call("rbind", alldata2) )
# 'data.frame': 160 obs. of  10 variables:
#  $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
#  $ disp: num  160 160 108 258 360 ...
#  $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
#  $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
#  $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
#  $ qsec: num  16.5 17 18.6 19.4 17 ...
#  $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...
#  $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
#  $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
#  $ carb: num  4 4 1 1 2 1 4 2 2 4 ...

$mpg 不存在于此解决方案中。)

考虑在列名称上使用 lapply() 和倒置的 grep() 以删除 datetime。无论这两列位于何处,或者它们是否存在于较小的集合中,下面都有效。

dfList <- lapply(file_list, function(f) {
                    df <- read.table(f, header=TRUE, sep="\t", stringsAsFactors=FALSE)
                    df <- df[grep("(date|time)", names(df), invert = TRUE)]
                 })

finaldf <- do.call(rbind, dfList)

或者,不使用不匹配的正则表达式模式 invert = TRUE:

dfList <- lapply(file_list, function(f) {
                    df <- read.table(f, header=TRUE, sep="\t", stringsAsFactors=FALSE)
                    df <- df[grep("[^(date|time)]", names(df))]
                 }) 

finaldf <- do.call(rbind, dfList)

感谢您的建议!

一个对我有用的解决方案是替换

dataset<-rbind(dataset, temp_dataset)

来自

dataset<-rbind.fill(dataset, temp_dataset)

缺失的数据被 NA 替换,我可以轻松删除不完整的列。