将文本文件合并到 R 中相同 header 下的 csv
Merging text files to csv under the same header in R
我有一个文件夹,其中包含 1000 多个文本文件,显示特定空气质量站的污染物水平。
我希望将所有这些文本文件合并到 R 中的一个 csv 中,这样我就可以在一个 space.
中临时分析数据
每个文本文件的组织方式如下,包括单位名称、特定观察集的开始时间以及数据的列。
我的文本文件 1 的 header 示例:
Unit 12345678
Start time: Wed Jan 29 10:57:58 2020
**dd/mm/yyyy hh:mm:ss, PM1, PM2.5, PM10, TSP, RHpre, Tpre, DPpre, RHpost, Tpost, DPpost**
29/01/2020 10:59:00, 1.39, 4.70, 17.11, 172.64, 36.10, 23.11, 7.17, 12.49, 41.26, 7.09
29/01/2020 11:00:00, 1.21, 3.64, 15.68, 26.39, 36.59, 23.12, 7.32, 12.41, 41.52, 7.17
29/01/2020 11:01:00, 1.20, 3.65, 15.12, 93.69, 36.51, 23.18, 7.43, 12.39, 41.68, 7.31
29/01/2020 11:02:00, 1.29, 4.09, 11.93, 15.31, 36.19, 23.22, 7.42, 12.30, 41.79, 7.37
29/01/2020 11:03:00, 1.30, 3.74, 9.06, 11.90, 36.04, 23.26, 7.33, 12.27, 41.88, 7.27
29/01/2020 11:04:00, 1.33, 4.31, 18.62, 44.38, 35.98, 23.28, 7.33, 12.21, 41.97, 7.34
文本文件示例 2
Unit 12345678
Start time: Wed Jan 29 11:14:46 2020
**dd/mm/yyyy hh:mm:ss, PM1, PM2.5, PM10, TSP, RHpre, Tpre, DPpre, RHpost, Tpost, DPpost**
29/01/2020 11:16:00, 1.29, 4.80, 12.68, 14.96, 36.77, 23.15, 7.69, 14.41, 38.14, 6.58
29/01/2020 11:17:00, 1.24, 3.97, 13.30, 18.04, 37.51, 23.13, 7.58, 14.23, 38.57, 6.76
29/01/2020 11:18:00, 1.13, 3.50, 16.80, 60.72, 37.09, 23.16, 7.80, 14.11, 38.89, 6.84
29/01/2020 11:19:00, 1.33, 4.56, 14.23, 71.32, 38.96, 23.22, 8.25, 14.24, 39.15, 7.04
29/01/2020 11:20:00, 1.23, 3.72, 16.87, 22.36, 38.13, 23.29, 8.47, 14.00, 39.39, 7.27
29/01/2020 11:21:00, 1.17, 4.47, 12.30, 15.60, 37.00, 23.34, 8.36, 13.86, 39.62, 7.24
29/01/2020 11:22:00, 1.28, 4.18, 12.80, 229.03, 36.27, 23.36, 7.54, 13.70, 39.85, 7.37
29/01/2020 11:23:00, 1.34, 4.28, 17.27, 96.94, 36.19, 23.37, 7.50, 13.54, 40.05, 7.30
因此对于每个文本文件,第一行(站点 ID)和第三行(列名)对于特定站点将保持不变,但第二行将随着监视器生成的每个输出而变化。
如上所述,我希望将所有这些文本文件组合在一起,但是在统一的 header 列名下 (dd/mm/yyyy hh:mm:ss, PM1, PM2.5, PM10、TSP、RHpre、Tpre、DPpre、RHpost、Tpost、DPpost),因为这在我也可以访问的每个监视器中都是一致的,因此可以轻松复制代码。
我尝试过:
mypath = "C:/Desktop/mytxtfolder/"
txt_files_ls = list.files(path=mypath, pattern="*.txt")
txt_files_df <- lapply(txt_files_ls, function(x) {read.table(file = x,skip =3, header = T, sep =",")})
combined_df <- do.call("rbind", lapply(txt_files_df, as.data.frame))
并得到
的一致错误
Error in rbind(deparse.level, ...) :
numbers of columns of arguments do not match
我认为这是因为第二行的值(上传时间)不匹配,我错误地使用该函数跳过前两行,只在第三行合并。
首先,我认为 do.call(dplyr::bind_rows, txt_files_df)
已经可以解决您在 base::rbind
中看到的错误,因为 bind_rows
在其输入列不存在时不会崩溃'对齐。在这种情况下,它只是将新列添加到结果中。
其次,您还可以使用 purrr
的 map_dfr
使您的代码更简洁一些,它对列表的元素应用一个函数,并 row-binds 使用 [=20= 稳健地得到结果].像这样:
library(dplyr)
library(purrr)
library(readr)
combined_df <- purrr::map_dfr(txt_files_ls, function(x) {
readr::read_csv(x, skip = 3, trim_ws = T)
})
但是,根据您遇到的错误,我猜想 header 是 not 总是相同的,或者它不是 3 行的常量你需要跳过。
您可以通过遍历列表并测试所有加载的数据帧来测试 colnames 是否与第一个相同。例如:
test <- txt_files_df %>%
purrr::discard(~identical(colnames(.), colnames(txt_files_df[[1]])))
我正在使用 purrr::discard
排除任何列名符合预期的条目,因此您的最终结果应该为空 - 但如果不是,您知道您需要检查您的数据或如果不可能,请调整您的代码以使其更健壮。
我建议将文件名添加到您阅读的数据框中,以便您可以识别哪个文件为您提供了奇怪的输入。此外,如果引导线是罪魁祸首,让我们明确检查 header 在哪里并相应地跳过行:
combined_df <- purrr::map_dfr(txt_files_ls, function(x) {
first_10_lines <- readLines(x, 10L)
header_line <- min(which(grepl('**dd/mm/yyyy hh:mm:ss', first_10_lines, fixed = T)))
df <- readr::read_csv(x, skip = header_line - 1, trim_ws = T)
df$file_name <- x # allowing you to know what file this data came from
df
})
// 更新,响应 OP 的列类型不匹配的问题:
I am receiving errors Error: Can't combine PM1 <double> and PM1 <character>
有两种攻击方式:
- 如果您 100% 确定数据始终是数字,那么您可以在 csv 解析器本身中声明它。但是,如果角色数据设法潜入,它将被视为
<NA>
并因此被“丢失”(你 将 收到警告):
combined_df <- purrr::map_dfr(txt_files_ls, function(x) {
first_10_lines <- readLines(x, 10L)
header_line <- min(which(grepl('**dd/mm/yyyy hh:mm:ss', first_10_lines, fixed = T)))
df <- readr::read_csv(
x,
skip = header_line - 1,
trim_ws = T,
col_types = cols(
`**dd/mm/yyyy hh:mm:ss` = col_datetime(format = "%d/%m/%Y %H:%M:%S"),
.default = col_double()
)
)
df$file_name <- x # allowing you to know what file this data came from
df
})
- 如果您不想在加载文件时丢失任何内容,您可以只读取所有列作为 character-vectors 并让
readr::type_convert
稍后在行绑定之后猜测类型。
combined_df <- purrr::map_dfr(txt_files_ls, function(x) {
first_10_lines <- readLines(x, 10L)
header_line <- min(which(grepl('**dd/mm/yyyy hh:mm:ss', first_10_lines, fixed = T)))
df <- readr::read_csv(
x,
skip = header_line - 1,
trim_ws = T,
col_types = cols(
`**dd/mm/yyyy hh:mm:ss` = col_datetime(format = "%d/%m/%Y %H:%M:%S"),
.default = col_character()
)
)
df$file_name <- x # allowing you to know what file this data came from
df
}) %>%
readr::type_convert()
我有一个文件夹,其中包含 1000 多个文本文件,显示特定空气质量站的污染物水平。
我希望将所有这些文本文件合并到 R 中的一个 csv 中,这样我就可以在一个 space.
中临时分析数据每个文本文件的组织方式如下,包括单位名称、特定观察集的开始时间以及数据的列。
我的文本文件 1 的 header 示例:
Unit 12345678
Start time: Wed Jan 29 10:57:58 2020
**dd/mm/yyyy hh:mm:ss, PM1, PM2.5, PM10, TSP, RHpre, Tpre, DPpre, RHpost, Tpost, DPpost**
29/01/2020 10:59:00, 1.39, 4.70, 17.11, 172.64, 36.10, 23.11, 7.17, 12.49, 41.26, 7.09
29/01/2020 11:00:00, 1.21, 3.64, 15.68, 26.39, 36.59, 23.12, 7.32, 12.41, 41.52, 7.17
29/01/2020 11:01:00, 1.20, 3.65, 15.12, 93.69, 36.51, 23.18, 7.43, 12.39, 41.68, 7.31
29/01/2020 11:02:00, 1.29, 4.09, 11.93, 15.31, 36.19, 23.22, 7.42, 12.30, 41.79, 7.37
29/01/2020 11:03:00, 1.30, 3.74, 9.06, 11.90, 36.04, 23.26, 7.33, 12.27, 41.88, 7.27
29/01/2020 11:04:00, 1.33, 4.31, 18.62, 44.38, 35.98, 23.28, 7.33, 12.21, 41.97, 7.34
文本文件示例 2
Unit 12345678
Start time: Wed Jan 29 11:14:46 2020
**dd/mm/yyyy hh:mm:ss, PM1, PM2.5, PM10, TSP, RHpre, Tpre, DPpre, RHpost, Tpost, DPpost**
29/01/2020 11:16:00, 1.29, 4.80, 12.68, 14.96, 36.77, 23.15, 7.69, 14.41, 38.14, 6.58
29/01/2020 11:17:00, 1.24, 3.97, 13.30, 18.04, 37.51, 23.13, 7.58, 14.23, 38.57, 6.76
29/01/2020 11:18:00, 1.13, 3.50, 16.80, 60.72, 37.09, 23.16, 7.80, 14.11, 38.89, 6.84
29/01/2020 11:19:00, 1.33, 4.56, 14.23, 71.32, 38.96, 23.22, 8.25, 14.24, 39.15, 7.04
29/01/2020 11:20:00, 1.23, 3.72, 16.87, 22.36, 38.13, 23.29, 8.47, 14.00, 39.39, 7.27
29/01/2020 11:21:00, 1.17, 4.47, 12.30, 15.60, 37.00, 23.34, 8.36, 13.86, 39.62, 7.24
29/01/2020 11:22:00, 1.28, 4.18, 12.80, 229.03, 36.27, 23.36, 7.54, 13.70, 39.85, 7.37
29/01/2020 11:23:00, 1.34, 4.28, 17.27, 96.94, 36.19, 23.37, 7.50, 13.54, 40.05, 7.30
因此对于每个文本文件,第一行(站点 ID)和第三行(列名)对于特定站点将保持不变,但第二行将随着监视器生成的每个输出而变化。
如上所述,我希望将所有这些文本文件组合在一起,但是在统一的 header 列名下 (dd/mm/yyyy hh:mm:ss, PM1, PM2.5, PM10、TSP、RHpre、Tpre、DPpre、RHpost、Tpost、DPpost),因为这在我也可以访问的每个监视器中都是一致的,因此可以轻松复制代码。
我尝试过:
mypath = "C:/Desktop/mytxtfolder/"
txt_files_ls = list.files(path=mypath, pattern="*.txt")
txt_files_df <- lapply(txt_files_ls, function(x) {read.table(file = x,skip =3, header = T, sep =",")})
combined_df <- do.call("rbind", lapply(txt_files_df, as.data.frame))
并得到
的一致错误Error in rbind(deparse.level, ...) :
numbers of columns of arguments do not match
我认为这是因为第二行的值(上传时间)不匹配,我错误地使用该函数跳过前两行,只在第三行合并。
首先,我认为 do.call(dplyr::bind_rows, txt_files_df)
已经可以解决您在 base::rbind
中看到的错误,因为 bind_rows
在其输入列不存在时不会崩溃'对齐。在这种情况下,它只是将新列添加到结果中。
其次,您还可以使用 purrr
的 map_dfr
使您的代码更简洁一些,它对列表的元素应用一个函数,并 row-binds 使用 [=20= 稳健地得到结果].像这样:
library(dplyr)
library(purrr)
library(readr)
combined_df <- purrr::map_dfr(txt_files_ls, function(x) {
readr::read_csv(x, skip = 3, trim_ws = T)
})
但是,根据您遇到的错误,我猜想 header 是 not 总是相同的,或者它不是 3 行的常量你需要跳过。
您可以通过遍历列表并测试所有加载的数据帧来测试 colnames 是否与第一个相同。例如:
test <- txt_files_df %>%
purrr::discard(~identical(colnames(.), colnames(txt_files_df[[1]])))
我正在使用 purrr::discard
排除任何列名符合预期的条目,因此您的最终结果应该为空 - 但如果不是,您知道您需要检查您的数据或如果不可能,请调整您的代码以使其更健壮。
我建议将文件名添加到您阅读的数据框中,以便您可以识别哪个文件为您提供了奇怪的输入。此外,如果引导线是罪魁祸首,让我们明确检查 header 在哪里并相应地跳过行:
combined_df <- purrr::map_dfr(txt_files_ls, function(x) {
first_10_lines <- readLines(x, 10L)
header_line <- min(which(grepl('**dd/mm/yyyy hh:mm:ss', first_10_lines, fixed = T)))
df <- readr::read_csv(x, skip = header_line - 1, trim_ws = T)
df$file_name <- x # allowing you to know what file this data came from
df
})
// 更新,响应 OP 的列类型不匹配的问题:
I am receiving errors
Error: Can't combine PM1 <double> and PM1 <character>
有两种攻击方式:
- 如果您 100% 确定数据始终是数字,那么您可以在 csv 解析器本身中声明它。但是,如果角色数据设法潜入,它将被视为
<NA>
并因此被“丢失”(你 将 收到警告):
combined_df <- purrr::map_dfr(txt_files_ls, function(x) {
first_10_lines <- readLines(x, 10L)
header_line <- min(which(grepl('**dd/mm/yyyy hh:mm:ss', first_10_lines, fixed = T)))
df <- readr::read_csv(
x,
skip = header_line - 1,
trim_ws = T,
col_types = cols(
`**dd/mm/yyyy hh:mm:ss` = col_datetime(format = "%d/%m/%Y %H:%M:%S"),
.default = col_double()
)
)
df$file_name <- x # allowing you to know what file this data came from
df
})
- 如果您不想在加载文件时丢失任何内容,您可以只读取所有列作为 character-vectors 并让
readr::type_convert
稍后在行绑定之后猜测类型。
combined_df <- purrr::map_dfr(txt_files_ls, function(x) {
first_10_lines <- readLines(x, 10L)
header_line <- min(which(grepl('**dd/mm/yyyy hh:mm:ss', first_10_lines, fixed = T)))
df <- readr::read_csv(
x,
skip = header_line - 1,
trim_ws = T,
col_types = cols(
`**dd/mm/yyyy hh:mm:ss` = col_datetime(format = "%d/%m/%Y %H:%M:%S"),
.default = col_character()
)
)
df$file_name <- x # allowing you to know what file this data came from
df
}) %>%
readr::type_convert()