【问题标题】:Adding part of filename into column of dataframe - with multiple input-files将文件名的一部分添加到数据框的列中 - 带有多个输入文件
【发布时间】:2021-11-16 11:37:26
【问题描述】:

我正在尝试从给定的“.dta”文件中提取一些数据,并向每个创建的数据框添加一个新列,其中包含文件名的一部分(一年)。必须这样做,因为我想做一些队列分析,因此跟踪年份列中每个观察的起源,然后操纵它来查看每个人的队列。 对于“.csv”文件,我有一些工作代码,但我想在处理实际数据时会遇到一些问题。我的代码如下:

library(data.table) #-> for fread
library(readr) #-> for map_df
library(dplyr) #-> for pipe_operator
library(stringr) #-> for str_sub

### Get desired filenames structure (e.g. 4 digits for year)
filenames <- list.files("~/R/Data", full.names = TRUE, pattern = "*.csv")
sites <- str_sub(filenames, start = -5, end = -5) #just for experimental purpose -5 to -5
### Get length of each file
file_lengths <- unlist(lapply(lapply(filenames, read_csv2), nrow))
### Repeat sites using lengths
file_names <- rep(sites,file_lengths)
###actual file-reading
map_df_fread <- function(path,
                         pattern = "*.csv",
                         sep = ";",
                         dec = ",",
                         colClasses = NULL,
                         select = NULL) {
    list.files(path, pattern, full.names = TRUE) %>% 
    map_dfr(~fread(., sep = sep, dec = dec, stringsAsFactors = F,
                   header = T, colClasses = colClasses,
                   select = select)) %>%
    tibble() %>% mutate(year = file_names)
}

它做了它应该做的事情,至少在小数据集上是这样。实际数据中每个变量的观测值超过 10m。由于我想处理“*.dta”文件,我想我可以用 read_dta 替换 read_csv2() 但我担心的是在这一步中 R 会读取完整的数据,我想这将花费非常多的时间。无论如何要在我的文件读取功能中包含第一步(必须执行 20 次)? 我真的很想限制所有这些计算所需的内存量。

任何帮助将不胜感激!

提前致谢

【问题讨论】:

    标签: r


    【解决方案1】:

    df &lt;- data.frame(a = 1:5, b = c(T,F,T,F, F)), df$nms &lt;- "filename" 之所以有效,是因为它被回收了。结合在迭代器上工作的imap 函数,我们可以直接创建一列(操作的)文件名,而不是两次读取文件。要使这对 .dta 文件可行,只需替换相关的 I/O 函数和 list.files 中的模式或函数参数。

    # NOTRUN
    write.csv(data.frame(a = 1:5, b = c(T, F, T, F, F)), file = "t1.csv")
    write.csv(data.frame(a = 1:3, b = c(F, F, F)), file = "t2.csv")
    
    f <- function(path = NULL){
      if(is.null(path)) path <- getwd()
      fls <- as.list(list.files(path = path, pattern = ".csv"))
      string <- lapply(fls, substring, 2, 2)
      lapply(fls, data.table::fread) |>
        purrr::imap(~.x |> transform(year = string[.y]))
    }
    
    f()
    
    [[1]]
       V1 a     b year
    1:  1 1  TRUE    1
    2:  2 2 FALSE    1
    3:  3 3  TRUE    1
    4:  4 4 FALSE    1
    5:  5 5 FALSE    1
    
    [[2]]
       V1 a     b year
    1:  1 1 FALSE    2
    2:  2 2 FALSE    2
    3:  3 3 FALSE    2
    

    或者如果你想要一个单独的data.frame

    do.call(rbind, f())
    

    【讨论】:

    • 非常感谢您的回答。只是出于好奇:|> 是什么意思或它来自哪里?我找不到这个(我猜的)运算符的帮助文件,R 只是告诉我,这条线会导致错误。如果你能帮我解决这个问题。谢谢。
    • @BossVomSchloss |&gt; 是 R 3.5 版本的原生管道“操作符”。有关其文档,请参阅?pipeOp。它的用法与magrittr%&gt;% 非常相似,但不同之处在于它在后台由解析器解释,因此它知道如何评估表达式。很像英语中的标点符号。要查看实际情况,请尝试 deparse(substitute(x |&gt; sum() |&gt; exp())) 并将其与 deparse(substitute(x %&gt;% sum() %&gt;% exp())) 进行比较。它是一个相对较新的添加,因此当 RStudio 开发人员发布更新时,错误指示将消失。
    • 所以,我将我的工作目录传递给了您的函数,不幸的是我收到了以下错误: fread() 中的 Fehler :输入为空或仅包含 BOM 或终端控制字符调用自:fread()它与 read.csv 一起工作(并且仍然有效),.csv 文件绝对不是空的。测试文件只包含 15 个变量,每个变量都有一些随机数和 10k 到 150k 之间的观察值。我在这里错过了什么?
    • 您是否将相同的参数传递给fread 函数,就像您在原始方法中所做的那样?也就是说,lapply(fls, data.table::fread) 目前不使用任何附加参数。您可以添加它们lapply(fls, data.table::fread, sep = ";", dec = ",") 等等。我没有任何遵循这种结构的 .csv 文件,所以我不能说要传递的具体参数
    • 不,我只是将所有内容都留空,因为 fread 应该会自动看到“;”作为分隔符和“,”作为小数点,因为我已经理解了帮助文件。我也没有指定要导入哪些列,只是看看 fread 是否会加载整个数据。
    猜你喜欢
    • 1970-01-01
    • 2020-10-06
    • 2022-11-11
    • 2017-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-26
    • 1970-01-01
    相关资源
    最近更新 更多