根据文件名将 CSV 迭代到不同的数据帧
Iterating over CSVs to different dataframes based on file names
我有一个数据框,其中包含一堆 .CSV 文件的名称。它在下面的代码片段中看起来是如何工作的:
我想做的是将这些 .CSV 中的每一个转换成一个数据框,附加每个的结果。我要做的是根据文件名中的内容创建三个不同的数据框:
- 使用文件名中包含
-callers-
的 .CSV 文件的所有结果创建一个数据框
- 创建一个数据框,其中包含文件名中包含
-results
的 .CSV 文件的所有结果
- 使用 .CSV 文件的所有结果创建一个数据框,文件名中包含
-script_results-
如果我在下面的数据框中使用第一个 .CSV,则将 .CSV 文件实际转换为数据框的命令如下所示:
data <- aws.s3::s3read_using(read.csv, object = "s3://abc-testtalk/08182020-testpilot-arizona-results-08-18-2020--08-18-2020-168701001.csv")
但我想做的是:
使用s3read_using
函数
迭代Key
下的所有.csv文件
根据上面列出的文件名将它们放在三个单独的数据框中
Key
08182020-testpilot-arizona-results-08-18-2020--08-18-2020-168701001.csv
08182020-testpilot-arizona-results-08-18-2020--08-18-2020-606698088.csv
08182020-testpilot-arizona-script_results-08-18-2020--08-18-2020-114004469.csv
08182020-testpilot-arizona-script_results-08-18-2020--08-18-2020-450823767.csv
08182020-testpilot-iowa-callers-08-18-2020-374839084.csv
08182020-testpilot-maine-callers-08-18-2020-396935866.csv
08182020-testpilot-maine-results-08-18-2020--08-18-2020-990912614.csv
08182020-testpilot-maine-script_results-08-18-2020--08-18-2020-897037786.csv
08182020-testpilot-michigan-callers-08-18-2020-367670258.csv
08182020-testpilot-michigan-follow-ups-08-18-2020--08-18-2020-049435266.csv
08182020-testpilot-michigan-results-08-18-2020--08-18-2020-544974900.csv
08182020-testpilot-michigan-script_results-08-18-2020--08-18-2020-239089219.csv
08182020-testpilot-nevada-callers-08-18-2020-782329503.csv
08182020-testpilot-nevada-results-08-18-2020--08-18-2020-348644934.csv
08182020-testpilot-nevada-script_results-08-18-2020--08-18-2020-517037762.csv
08182020-testpilot-new-hampshire-callers-08-18-2020-134150800.csv
08182020-testpilot-north-carolina-callers-08-18-2020-739838755.csv
08182020-testpilot-pennsylvania-callers-08-18-2020-223839956.csv
08182020-testpilot-pennsylvania-results-08-18-2020--08-18-2020-747438886.csv
08182020-testpilot-pennsylvania-script_results-08-18-2020--08-18-2020-546894204.csv
08182020-testpilot-virginia-callers-08-18-2020-027531377.csv
08182020-testpilot-virginia-follow-ups-08-18-2020--08-18-2020-419338697.csv
08182020-testpilot-virginia-results-08-18-2020--08-18-2020-193170030.csv
创建 3 个空数据框。您可能还需要指明与要附加的每个文件中的列名相匹配的列名:
results <- data.frame()
script_results <- data.frame()
callers <- data.frame()
然后遍历 file_name
并将其读入 data
对象。有条件地在每个文件的名称中包含什么模式(“-results-”,“-script_results-”或“-caller-”,它将附加到正确的数据帧:
for (file in file_name) {
data <- aws.s3::s3read_using(read.csv, object = paste0("s3://abc-testtalk/", file))
if (grepl(file, "-results-")) { results <- rbind(results, data)}
if (grepl(file, "-script_results-")) { script_results <- rbind(script_results, data)}
if (grepl(file, "-callers-")) { callers <- rbind(callers, data)}
}
作为@JohnFranchak 对 map_dfr
的建议(可能工作得很好)的替代方法,我在评论中引用的方法看起来像这样:
alldat <- lapply(setNames(nm = dat$file_name),
function(obj) aws.s3::s3read_using(read.csv, object = obj))
callers <- do.call(rbind, alldat[grepl("-callers-", names(alldat))])
results <- do.call(rbind, alldat[grepl("-results-", names(alldat))])
script_results <- do.call(rbind, alldat[grepl("-script_results-", names(alldat))])
others <- do.call(rbind, alldat[!grepl("-(callers|results|script_results)-", names(alldat))])
do.call(rbind, ...)
部分类似于 dplyr::bind_rows
和 data.table::rbindlist
,因为它接受帧列表,结果是单个帧。一些差异:
do.call(rbind, ...)
确实要求所有列以相同顺序存在于所有帧中。从外部强制执行此操作并不难(例如,添加缺失的列、重新排列),但它不是自动的。
data.table::rbindlist
会抱怨相同的条件(缺少列或不同的顺序),但它有 fill=
和 use.names=
需要设置的参数 TRUE
。
dplyr::bind_rows
将默认按名称填充和行绑定,没有消息或警告。 (我不同意默认的静音总是好的,但这是最简单的。)
最后,我使用setNames(nm=..)
只是为每个对象分配文件名。这不是绝对必要的,因为我们仍然有 dat$file_name
,但我发现对于两个单独的对象,不小心更改(删除、追加或重新排序)其中一个而不是另一个是可行的,所以我更喜欢将名称和对象(框架)完美地联系在一起。这两个调用在生成的命名列表中相对相同:
lapply(setNames(nm = dat$file_name), ...)
sapply(dat$file_name, ..., simplify = FALSE)
我有一个数据框,其中包含一堆 .CSV 文件的名称。它在下面的代码片段中看起来是如何工作的:
我想做的是将这些 .CSV 中的每一个转换成一个数据框,附加每个的结果。我要做的是根据文件名中的内容创建三个不同的数据框:
- 使用文件名中包含
-callers-
的 .CSV 文件的所有结果创建一个数据框 - 创建一个数据框,其中包含文件名中包含
-results
的 .CSV 文件的所有结果 - 使用 .CSV 文件的所有结果创建一个数据框,文件名中包含
-script_results-
如果我在下面的数据框中使用第一个 .CSV,则将 .CSV 文件实际转换为数据框的命令如下所示:
data <- aws.s3::s3read_using(read.csv, object = "s3://abc-testtalk/08182020-testpilot-arizona-results-08-18-2020--08-18-2020-168701001.csv")
但我想做的是:
使用
迭代s3read_using
函数Key
下的所有.csv文件根据上面列出的文件名将它们放在三个单独的数据框中
Key 08182020-testpilot-arizona-results-08-18-2020--08-18-2020-168701001.csv 08182020-testpilot-arizona-results-08-18-2020--08-18-2020-606698088.csv 08182020-testpilot-arizona-script_results-08-18-2020--08-18-2020-114004469.csv 08182020-testpilot-arizona-script_results-08-18-2020--08-18-2020-450823767.csv 08182020-testpilot-iowa-callers-08-18-2020-374839084.csv 08182020-testpilot-maine-callers-08-18-2020-396935866.csv 08182020-testpilot-maine-results-08-18-2020--08-18-2020-990912614.csv 08182020-testpilot-maine-script_results-08-18-2020--08-18-2020-897037786.csv 08182020-testpilot-michigan-callers-08-18-2020-367670258.csv 08182020-testpilot-michigan-follow-ups-08-18-2020--08-18-2020-049435266.csv 08182020-testpilot-michigan-results-08-18-2020--08-18-2020-544974900.csv 08182020-testpilot-michigan-script_results-08-18-2020--08-18-2020-239089219.csv 08182020-testpilot-nevada-callers-08-18-2020-782329503.csv 08182020-testpilot-nevada-results-08-18-2020--08-18-2020-348644934.csv 08182020-testpilot-nevada-script_results-08-18-2020--08-18-2020-517037762.csv 08182020-testpilot-new-hampshire-callers-08-18-2020-134150800.csv 08182020-testpilot-north-carolina-callers-08-18-2020-739838755.csv 08182020-testpilot-pennsylvania-callers-08-18-2020-223839956.csv 08182020-testpilot-pennsylvania-results-08-18-2020--08-18-2020-747438886.csv 08182020-testpilot-pennsylvania-script_results-08-18-2020--08-18-2020-546894204.csv 08182020-testpilot-virginia-callers-08-18-2020-027531377.csv 08182020-testpilot-virginia-follow-ups-08-18-2020--08-18-2020-419338697.csv 08182020-testpilot-virginia-results-08-18-2020--08-18-2020-193170030.csv
创建 3 个空数据框。您可能还需要指明与要附加的每个文件中的列名相匹配的列名:
results <- data.frame()
script_results <- data.frame()
callers <- data.frame()
然后遍历 file_name
并将其读入 data
对象。有条件地在每个文件的名称中包含什么模式(“-results-”,“-script_results-”或“-caller-”,它将附加到正确的数据帧:
for (file in file_name) {
data <- aws.s3::s3read_using(read.csv, object = paste0("s3://abc-testtalk/", file))
if (grepl(file, "-results-")) { results <- rbind(results, data)}
if (grepl(file, "-script_results-")) { script_results <- rbind(script_results, data)}
if (grepl(file, "-callers-")) { callers <- rbind(callers, data)}
}
作为@JohnFranchak 对 map_dfr
的建议(可能工作得很好)的替代方法,我在评论中引用的方法看起来像这样:
alldat <- lapply(setNames(nm = dat$file_name),
function(obj) aws.s3::s3read_using(read.csv, object = obj))
callers <- do.call(rbind, alldat[grepl("-callers-", names(alldat))])
results <- do.call(rbind, alldat[grepl("-results-", names(alldat))])
script_results <- do.call(rbind, alldat[grepl("-script_results-", names(alldat))])
others <- do.call(rbind, alldat[!grepl("-(callers|results|script_results)-", names(alldat))])
do.call(rbind, ...)
部分类似于 dplyr::bind_rows
和 data.table::rbindlist
,因为它接受帧列表,结果是单个帧。一些差异:
do.call(rbind, ...)
确实要求所有列以相同顺序存在于所有帧中。从外部强制执行此操作并不难(例如,添加缺失的列、重新排列),但它不是自动的。data.table::rbindlist
会抱怨相同的条件(缺少列或不同的顺序),但它有fill=
和use.names=
需要设置的参数TRUE
。dplyr::bind_rows
将默认按名称填充和行绑定,没有消息或警告。 (我不同意默认的静音总是好的,但这是最简单的。)
最后,我使用setNames(nm=..)
只是为每个对象分配文件名。这不是绝对必要的,因为我们仍然有 dat$file_name
,但我发现对于两个单独的对象,不小心更改(删除、追加或重新排序)其中一个而不是另一个是可行的,所以我更喜欢将名称和对象(框架)完美地联系在一起。这两个调用在生成的命名列表中相对相同:
lapply(setNames(nm = dat$file_name), ...)
sapply(dat$file_name, ..., simplify = FALSE)