r - 在导入时在 csvs 中格式化一列
问题描述
我正在导入几个.csv,它们都是两列宽(它们是从程序中输出的)——第一列是波长,第二列是吸光度,但我用文件名命名它,以便稍后组合,如这个旧的堆栈溢出答案(将 R 中的 csv 文件组合到不同的列)。传入的 .csvs 没有标题,我知道我命名它们的方式会裁剪第一个数据点。我希望第一列没有任何小数,并将所有数字标准化为四位数字 - 我添加的代码独立工作,但不在此块中 - 我更愿意一次完成所有格式化. 我遇到了 $ 不是正确的运算符的错误,但是当我使用 [] 时,我也得到了错误。我需要这样做的列是第一列,它被命名为“波长”——这也会给我带来错误,因为波长不存在或者它是非数字的。有任何想法吗?
这是我的脚本目前的样子:
for (file in file_list) {
f <- sub("(.*)\\.CSV", "\\1", file)
assign(f, read.csv(file = file))
assign(f, setNames(get(f), c(names(get(f))[0:0], "Wavelength")))
assign(f, setNames(get(f), c(names(get(f))[1:1], file)))
floor(f[Wavelength]) #the issues are here
sprintf("%04d", f$Wavelength) #and here
}
数据在处理之前在 csv 中如下所示:
1 401.7664 0.1379457
2 403.8058 0.1390427
3 405.8452 0.1421666
4 407.8847 0.1463629
5 409.9241 0.1477264
我希望输出为:
Wavelength (file name)
1 0401 0.1379457
2 0403 0.1390427
3 0405 0.1421666
4 0407 0.1463629
5 0409 0.1477264
这是 r2evans 要求的 dput:
structure(list(X3.997270e.002 = c(401.7664, 403.8058, 405.8452,
407.8847, 409.9241, 411.9635), X1.393858e.001 = c(0.1379457,
0.1390427, 0.1421666, 0.1463629, 0.1477264, 0.1476971)), row.names =
c(NA,
6L), class = "data.frame")
提前致谢!
6/24 更新: 当我分配列名“波长”时,它只会作为字符添加,而不是作为真正的列名?当我 dput/head 文件通过后(省略 sprintf/floor 函数),它只列出文件名(第二列)。当我在 R studio 中打开 csvs 时,第一列被正确标记 - 甚至更进一步,我能够组合所有按“波长”排序的 csvs:
list_csvs <- mget(sub("(.*)\\.CSV", "\\1", file_list))
all_csvs <- Reduce(function(x, y) merge(x, y, all=T,
by=c("Wavelength")), list_csvs, accumulate=F)
自然地,我考虑过在此之后对列进行格式化,但是有些小数在数千位是关闭的,所以我需要在合并 csv 之前进行格式化。
我已经更新了代码以使用 read.csv 之外的 colnames:
for (file in file_list) {
f <- sub("(.*)\\.CSV", "\\1", file)
assign(f, read.csv(file = file,
header = FALSE,
row.names = NULL))
colnames(f) <- c("Wavelength", file)
print(summary(f))
print(names(f))
#floor("Wavelength") #I'm omitting this to see the console errors
#sprintf("%04.0f", f["Wavelength"]) #omitting this too
}
但我收到以下错误:
attempt to set 'colnames' on an object with less than two dimensions
没有命名位,也没有 sprintf/floor 我从每个文件的摘要和名称提示中得到这个:
Length Class Mode
1 character character
NULL
当我尝试通过 f[1]、f[[1]]、f[,1] 或 f[[,1]] 调用第一列时,我收到有关“维数不正确”的错误消息。我可以在 R 环境中清楚地看到每个数据帧的长度为 2。我还仔细检查.row_names_info(f)
了第一列没有被读取为行名。我究竟做错了什么?
解决方案
我将为此建议一个 dplyr/tidyr 管道。
首先,数据设置:
writeLines(
"401.7664,0.1379457
403.8058,0.1390427
405.8452,0.1421666
407.8847,0.1463629
409.9241,0.1477264", "sample1.csv")
file.copy("sample1.csv", "sample2.csv")
file_list <- normalizePath(list.files(pattern = ".*\\.csv$", full.names = TRUE), winslash = "/")
file_list
# [1] "C:/Users/r2/StackOverflow/13765634/sample1.csv"
# [2] "C:/Users/r2/StackOverflow/13765634/sample2.csv"
首先,我将建议一种稍微不同的格式:不为文件名命名列。我喜欢这个,因为我仍将保留文件名和数据(可以说是一个类别),但它允许您将所有数据合并到一个帧中以进行更有效的处理:
library(dplyr)
library(purrr) # map*
library(tidyr) # pivot_wider
file_list %>%
set_names(.) %>%
# set_names(tools::file_path_sans_ext(basename(.))) %>%
map_dfr(~ read.csv(.x, header = FALSE, col.names = c("freq", "val")),
.id = "filename") %>%
mutate(freq = sprintf("%04.0f", freq))
# filename freq val
# 1 C:/Users/r2/StackOverflow/13765634/sample1.csv 0402 0.1379457
# 2 C:/Users/r2/StackOverflow/13765634/sample1.csv 0404 0.1390427
# 3 C:/Users/r2/StackOverflow/13765634/sample1.csv 0406 0.1421666
# 4 C:/Users/r2/StackOverflow/13765634/sample1.csv 0408 0.1463629
# 5 C:/Users/r2/StackOverflow/13765634/sample1.csv 0410 0.1477264
# 6 C:/Users/r2/StackOverflow/13765634/sample2.csv 0402 0.1379457
# 7 C:/Users/r2/StackOverflow/13765634/sample2.csv 0404 0.1390427
# 8 C:/Users/r2/StackOverflow/13765634/sample2.csv 0406 0.1421666
# 9 C:/Users/r2/StackOverflow/13765634/sample2.csv 0408 0.1463629
# 10 C:/Users/r2/StackOverflow/13765634/sample2.csv 0410 0.1477264
选项:如果您只喜欢文件名(无路径)并且确定没有文件名冲突,请set_names(basename(.))
改用。(无论如何,当使用文件名作为列名时,这一步确实是必要的。)我还将删除文件扩展名,因为它们可能全部.csv
或相似。
file_list %>%
# set_names(.) %>%
set_names(tools::file_path_sans_ext(basename(.))) %>%
map_dfr(~ read.csv(.x, header = FALSE, col.names = c("freq", "val")),
.id = "filename") %>%
mutate(freq = sprintf("%04.0f", freq))
# filename freq val
# 1 sample1 0402 0.1379457
# 2 sample1 0404 0.1390427
# 3 sample1 0406 0.1421666
# 4 sample1 0408 0.1463629
# 5 sample1 0410 0.1477264
# 6 sample2 0402 0.1379457
# 7 sample2 0404 0.1390427
# 8 sample2 0406 0.1421666
# 9 sample2 0408 0.1463629
# 10 sample2 0410 0.1477264
(如果您需要一次对每个数据集做某事,那么您应该使用%>% group_by(filename)
,不确定这是否相关。)
如果您确实需要将文件名作为值的列名,请稍微修改一下,以便将其保留为列表:
file_list %>%
set_names(tools::file_path_sans_ext(basename(.))) %>%
map(~ read.csv(.x, header = FALSE, col.names = c("freq", "val"))) %>%
map2(., names(.), ~ transmute(.x, freq = sprintf("%04.0f", freq), !!.y := val))
# $sample1
# freq sample1
# 1 0402 0.1379457
# 2 0404 0.1390427
# 3 0406 0.1421666
# 4 0408 0.1463629
# 5 0410 0.1477264
# $sample2
# freq sample2
# 1 0402 0.1379457
# 2 0404 0.1390427
# 3 0406 0.1421666
# 4 0408 0.1463629
# 5 0410 0.1477264
但是我将推断最终您希望按列组合这些列,假设列中会有对齐freq
。(我想不出您希望列名成为文件名的另一个原因。)
为此,试试这个,恢复到第一次使用map_dfr
,引入pivot_wider
:
file_list %>%
set_names(tools::file_path_sans_ext(basename(.))) %>%
map_dfr(~ read.csv(.x, header = FALSE, col.names = c("freq", "val")),
.id = "filename") %>%
mutate(freq = sprintf("%04.0f", freq)) %>%
pivot_wider(freq, names_from = filename, values_from = val)
# # A tibble: 5 x 3
# freq sample1 sample2
# <chr> <dbl> <dbl>
# 1 0402 0.138 0.138
# 2 0404 0.139 0.139
# 3 0406 0.142 0.142
# 4 0408 0.146 0.146
# 5 0410 0.148 0.148
笔记(也许更像是一个肥皂盒):
关于您对 的使用
assign
,我强烈反对这种行为。由于数据的结构实际上都是相同的,我推断您将对这些文件中的每一个执行相同的操作。在这种情况下,最好使用s列表中*apply
的一个函数。也就是说,它不必遍历变量名列表,而是做某事,然后……它通常更容易(编程、阅读、维护)或.data.frame
get
reassign
dats <- lapply(dats, some_function)
dats2 <- lapply(dats, function(x) { ...; x; })
关于使用文件名作为列名。一些工具(例如
ggplot2
)确实受益于拥有“长”数据(即,一个或多个类别列,例如filename
,并且每种类型的数据都有一个列......类型与您对数据的理解有关)。您可能会从重新思考使用这些数据的想法中受益。
推荐阅读
- javascript - 我似乎无法返回我想要返回的正确对象
- html - 在 html 标签中正确使用“隐藏”属性
- python - Mac osx python 看不到文件
- python-3.x - Python2.x/3.x 兼容性:“错误:AttributeError:‘Instruction’对象没有属性‘identity_byte’
- java - 如何返回不是实体的对象列表并添加一个自定义变量,该变量将从休眠查询中的属性文件中获取?
- javascript - Angular从html中的控件获取值
- c++ - 在多个对象中初始化预定义成员变量的正确方法是什么?
- google-chrome-extension - 从 devtools(自定义选项卡)到内容脚本的消息?
- loops - 似乎没有理由获得 NaN
- python-3.6 - 在 Raspbian Buster 上为非默认 python 制作 venv 时,mkvirtualenv 说“没有名为 distutils.spawn 的模块”