【问题标题】:Julia: read many files in the working directoryJulia:读取工作目录中的许多文件
【发布时间】:2017-03-01 03:16:35
【问题描述】:

我刚开始学习 Julia,我想在我的目录中读取许多 csv 文件。我该怎么做?

我的目录有以下文件,我想读入从trip_data_1到trip_data_12的所有文件。

“trip_data_1.csv” “trip_data_10.csv” “trip_data_11.csv” “trip_data_12.csv” “trip_data_2.csv” “trip_data_3.csv” “trip_data_4.csv” “trip_data_5.csv” “trip_data_6.csv” “trip_data_7.csv” “trip_data_8.csv” “trip_data_9.csv” “trip_fare_1.csv” “trip_fare_10.csv” “trip_fare_11.csv” “trip_fare_12.csv” “trip_fare_2.csv” “trip_fare_3.csv” “trip_fare_4.csv” “trip_fare_5.csv” “trip_fare_6.csv” “trip_fare_7.csv” “trip_fare_8.csv” “trip_fare_9.csv”

这是我尝试过的:

using DataFrames
df = readtable(filter!(r"^trip_data", readdir()))

但我得到 MethodError: no method matching readtable(::Array{String,1})

【问题讨论】:

  • filter!(在这种情况下)返回Array{String, 1},即所有文件名的向量。但是readtable 一次只能读取一个文件,因此需要String 输入。解决方案?只需通过调用readtable 来迭代filter! 操作的输出。
  • 谢谢!这有帮助!

标签: julia


【解决方案1】:

我非常喜欢这种情况下的.broadcasting 语法。

df = readtable.(filter(r"^trip_data", readdir())) 会给你一个数据帧数组(@avysk 是正确的,你可能想要filter 而不是filter!

如果你想要一个单一的数据框,那么mapreduceoption 很好。

或者你可以:vcat(readtable.(filter(r"^trip_data", readdir()))

注意:所有这些都是该问题的一般解决方案,我有一个将 f 应用于 x 的函数(方法),现在我想将它应用于许多实例,或者数组,x

因此,如果您遇到另一个错误,表明您不能将函数直接应用于任何数组或集合,但可以应用于单个元素,那么 mapbroadcast/. 和列表推导是您的朋友!

【讨论】:

  • 广播的好方法!但是,在“我需要一个数据帧”的情况下,我认为mapreduce(不是reduce(... map(...)))是最好的,因为它不会复制内存中的数据——所有其他方法首先创建一个数据帧序列,它保存在内存中,直到完成最终结果的创建。另一方面,mapreduce 不构建中间序列。还是我错了?
  • 不,没错。我能想到首先创建中间集合的唯一原因是您是否需要跟踪每行/帧源自哪个文件。
【解决方案2】:

你可以这样做:

reduce(vcat,  map(readtable, filter(r"^trip_data", readdir())))

此处mapreadtable 应用于与filter 匹配的每个文件名(此处不需要filter!)并将所有生成的数据帧连接在一起(vcat)。

mapreduce也可以这样写:

mapreduce(readtable, vcat, filter(r"^trip_data", readdir()))

【讨论】:

    【解决方案3】:

    另一种方法(将连接移动到输入字符串级别而不是 DataFrame 级别)并使用Iterators 包:

    readtable(IOBuffer(join(chain([drop((l for l in readlines(fn)),i>1?1:0) for (i,fn) in enumerate(filter!(r"^trip_data", readdir()))]...))))

    这实际上可以节省一些时间和分配(在我的宠物示例中确实如此),但这取决于输入文件的参数。

    【讨论】:

      【解决方案4】:

      这是一个使用 Glob 的解决方案,我认为它更具可读性:

      using CSV, Glob, DataFrames
      
      files = glob("trip_data_*.csv")
      dfs = CSV.read.(files)
      

      正如另一个答案中提到的,CSV.read.(带有最后一个点)在files 数组上广播,并创建一个 DataFrame 数组。因此,最后一行相当于:

      dfs = [CSV.read(file) for file in files]
      

      最后,如果你想连接所有文件,你可以这样做:

      df = vcat(dfs...)
      

      ... 用于将可变数量的参数传递给函数。

      【讨论】:

        【解决方案5】:

        你也可以做一个简单的

        files = filter(r".csv$", readdir(path))
        df = vcat([readtable(f) for f in files])
        

        作为后续,我对 julia 的 CSV.read(file) 做了同样的事情,但速度要慢得多。其实不是阅读部分,而是采购部分:

        source = CSV.Source(file)
        CSV.Read(source)
        

        【讨论】:

          【解决方案6】:

          补充以上答案。似乎 CSV.read 将被弃用。此外,一些用户在直接使用 CSV.read 时似乎遇到了问题deleting rows from DataFrames。此代码使用 CSV.File 发布 here 也可能有所帮助。

          using CSV, Glob, DataFrame  
          folder = "d:/Data/Test/" 
          files = glob("*.csv", folder) 
          df3=DataFrame.(CSV.File.(files))
          

          【讨论】:

            猜你喜欢
            • 2018-08-20
            • 2014-11-07
            • 2022-08-04
            • 2016-01-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多