删除 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()
以删除 date
和 time
。无论这两列位于何处,或者它们是否存在于较小的集合中,下面都有效。
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 替换,我可以轻松删除不完整的列。
我有多个包含 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()
以删除 date
和 time
。无论这两列位于何处,或者它们是否存在于较小的集合中,下面都有效。
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 替换,我可以轻松删除不完整的列。