提问人:Alexia k Boston 提问时间:7/17/2023 最后编辑:Alexia k Boston 更新时间:7/18/2023 访问量:103
无法获取:一个输入文件中缺少但存在于其他文件中的列应在输出文件中返回 NA
Unable to obtain: Columns missing in one input file but present in other files should return NA in output file
问:
我有各种txt文件,其中每个文件都包含多个列,但并非所有列都存在于所有文件中。 例如
Txt 文件1 的列
D/T City_Name Temp Pres Wind_Hor Wind_Ver S_Moist Temp1 Pres1 Wind1 S_Moist1
20200101 Mi 27 1019 287 278 78 1 2 2 1
20200101 Mi 28 1019 289 277 78 2 2 1 3
txt 文件的列2
D/T City_Name Temp Wind_Hor Rainf S_Moist Temp1 Wind1 S_Moist1
20200501 Ch 29 88 74 78 2 2 2 3
20200501 Ch 26 83 74 76 2 3 3 3
Txt 文件的列3
D/T City_Name Pres Wind_Vert Rainf S_Moist Pres1 Wind1 Rainf1 S_Moist1
20180701 Ny 1017 247 78 78 4 2 2 2
20180702 Ny 1017 249 79 79 2 3 3 3
我在 R 中运行了一个代码来处理这些文件,并为每个 txt 文件获取 1 个输出 csv。
我想要的输出是在所有输出文件中都有所有 7 列,如果输入中没有特定列,那么它应该在输出中具有 NA 值。
Txt File1 的所需输出列
D_T City_Name Temp Pres Wind_Hor Wind_Ver Rainf S_Moist
202001 Mi 26 1018 288 277 NA 77
202002 Mi 27 1018 288 278 NA 77
Txt 文件2 的所需输出列
D_T City_Name Temp Pres Wind_Hor Wind_Ver Rainf S_Moist
202005 Ch 28 NA 287 NA 77 77
202006 Ch 27 NA 284 NA 79 78
Txt 文件的期望输出列3
D_T City_Name Temp Pres Wind_Hor Wind_Vert Rainf S_Moist
201807 Mi NA 1016 NA 276 77 79
201808 Mi NA 1016 NA 276 77 81
我的代码如下:
library(data.table)
library(tidyr)
library(dplyr)
library(lubridate)
setwd("D:/Test3")
dirlist <- list.files(full.names = FALSE, no.. = TRUE)
#Read the files
read_the_files <- function(filelist){
lapply(filelist, function(file) {
fread(file, skip = "D/T\tXY [XY]")
})
}
#Adjusting with Columns
adj_col_names <- function(dt_list){
lapply(dt_list, FUN = function(x){
#replace [] with () as use of [] may lead to issues
colnames(x) <- gsub("\\[", "(", colnames(x))
colnames(x) <- gsub("\\]", ")", colnames(x))
#Applying quality codes given in the data and range given in paper
if ("Temp1" %in% colnames(x)) {
x[Temp1 != 5, Temp := NA]
x[Temp < 0 | Temp > 40, Temp := NA]
}
if ("Pres1" %in% colnames(x)) {
x[Pres1 != 5, Pres := NA]
x[Pres < 1000 | Pres > 1300, Pres := NA]
}
for (idx in seq_along(dirlist)){
filelist <- list.files(path = dirlist[idx], full.names = TRUE, recursive = TRUE, pattern =
".txt$")
dt_ <- read_the_files(filelist)
dt.tidied <- adj_col_names(dt_)
#bind, filling missing columns to NA
merged <- rbindlist(dt.tidied, fill = TRUE, use.names = TRUE)
#Choosing the columns in the output
sel_col <- c('D/T', 'City_Name', 'Temp', 'Pres', 'Wind_Hor', 'Wind_Ver', 'Rainf', 'S_Moist')
#calculating monthly average
avg_mn <- merged %>%
select(any_of(sel_col)) %>%
as_tibble() %>%
group_by(D_T = lubridate::floor_date(`D/T`, "1 month")) %>%
summarise(across(where(is.numeric), ~ if(mean(is.na(.x)) > 0.1) NA else mean(.x, na.rm = TRUE))) #summarise only numeric columns
write.csv(paste0(dirlist[idx],"_mn.csv"))
由于各种依赖关系,我无法更改我的代码。我只能修改。谁能帮我修改它以获得所需的输出?
根据 jkatam 的回答测试了代码:
dfs1 <- list.files(path = 'D:/Test3', pattern = "*txt", recursive = TRUE)
var <- c('D/T', 'City_Name', 'Temp', 'Pres', 'Wind_Hor', 'Wind_Ver', 'Rainf', 'S_Moist')
lapply(dfs1, \(x) {
dfn <- get(x, envir = .GlobalEnv)
dfn[[var[which(is.na(match(var,names(dfn))))]]] <- NA
dfn <- dfn %>% select(all_of(var))
return(assign(x,dfn,envir = .GlobalEnv))
})
我收到错误:
Error in get(x, envir = .GlobalEnv) :
object 'Mi/Mi_2020-01_0100.txt' not found
答:
0赞
jkatam
7/17/2023
#1
请检查下面的代码,我假设您有不同的数据帧,例如等,您想检查预期的列是否存在,如果不存在,则使用 NA 派生该列并输出数据帧,稍后可以将其导出为 csvdf1
df2
dfs1 <- c('df1','df2')
var <- c('City_Name', 'Temp', 'Pres' , 'Wind_Hor' , 'Wind_Ver' , 'Rainf' , 'S_Moist')
lapply(dfs1, \(x) {
dfn <- get(x, envir = .GlobalEnv)
dfn[[var[which(is.na(match(var,names(dfn))))]]] <- NA
dfn <- dfn %>% select(all_of(var))
return(assign(x,dfn,envir = .GlobalEnv))
})
评论
0赞
Alexia k Boston
7/18/2023
谢谢,但我没有数据帧。相反,我有文件。您能否告诉我如何使用文件而不是数据帧执行您提到的过程。
0赞
Alexia k Boston
7/18/2023
我使用文件列表(在帖子中提到)尝试了您的代码,但它给了我一个错误。此外,我试图将它放在adj_col_names上方,但我不确定它是否是这些代码行的正确位置。请帮忙。
0赞
r2evans
7/17/2023
#2
使用您的输入文件,我做了几件事:
- 将它们命名为 、 和
file1.txt
file2.txt
file3.txt
- 将所有空格更改为单个制表符,并确保一行中没有尾随制表符 (file3)
- 添加到 file2,因为它有 9 个列名和 10 个数据列
S_Rain1
然后我运行了这段代码:
files <- list.files(pattern = "txt$", full.names = TRUE)
alldat <- lapply(setNames(nm = files), fread)
rbindlist(alldat, idcol = "path", fill = TRUE, use.names = TRUE) %>%
setnames("D/T", "D_T") %>%
.[, fwrite(.SD, sub("txt$", "tab", path[1]), sep = "\t", na = "NA"),
.SDcols = c("D_T", "City_Name", "Temp", "Pres", "Wind_Hor", "Wind_Ver", "Rainf", "S_Moist"),
by = .(path)]
生成的文件:
file1.csv
:"D_T" "City_Name" "Temp" "Pres" "Wind_Hor" "Wind_Ver" "Rainf" "S_Moist" 20200101 "Mi" 27 1019 287 278 NA 78 20200101 "Mi" 28 1019 289 277 NA 78
file2.csv
"D_T" "City_Name" "Temp" "Pres" "Wind_Hor" "Wind_Ver" "Rainf" "S_Moist" 20200501 "Ch" 29 NA 88 NA 74 78 20200501 "Ch" 26 NA 83 NA 74 76
file3.csv
"D_T" "City_Name" "Temp" "Pres" "Wind_Hor" "Wind_Ver" "Rainf" "S_Moist" 20180701 "Ny" NA 1017 NA NA 78 78 20180702 "Ny" NA 1017 NA NA 79 79
添加引号是因为我们提供了添加文字文本的引号。可以通过向表达式中添加引号来禁止引用。na=""
NA
quote=FALSE
fwrite(..)
注意:由于 StackOverflow 代码渲染,上面的内容渲染带有空格;它们确实是结果文件中的选项卡。
评论
0赞
Alexia k Boston
7/17/2023
我尝试了代码,按照我的代码修改了它。我修改正确了吗?因为它给了我这个错误: FUN(X[[i]], ...) 中的错误: input= 必须是包含文件名的单个字符串、包含至少一个空格的系统命令、以“http[s]://”、“ftp[s]://”或“file://”开头的 URL,或者,输入数据本身包含至少一个 \n 或 \r 另外,您能否在代码中添加注释
0赞
r2evans
7/17/2023
对你来说看起来合理吗?是否所有文件都存在,格式是否正确?是否有不应读入批处理的额外文件名?files
files
0赞
Alexia k Boston
7/18/2023
文件对我来说看起来很合理,唯一的区别是因为我正在迭代处理多个文件,所以我在此步骤中使用了一个循环(请在我的代码中引用“filelist”)。是的,所有文件都存在。虽然文件格式不正确,但它已经在我的代码中得到处理。由于文件名很大,我保留了文件夹的名称作为文件名。如果您能将您的代码与我的代码合并并为其提供注释以便于理解,那将会很有帮助
评论
rbindlist(lapply(your_file_list, read.table))
rbindlist
dplyr::bind_rows(your_list)
rbindlist
fill=TRUE
use.names=TRUE